ficl.h revision 43139
140843Smsmith/*******************************************************************
240843Smsmith** f i c l . h
340843Smsmith** Forth Inspired Command Language
440843Smsmith** Author: John Sadler (john_sadler@alum.mit.edu)
540843Smsmith** Created: 19 July 1997
640843Smsmith**
740843Smsmith*******************************************************************/
840843Smsmith/*
940843Smsmith** N O T I C E -- DISCLAIMER OF WARRANTY
1040843Smsmith**
1140843Smsmith** Ficl is freeware. Use it in any way that you like, with
1240843Smsmith** the understanding that the code is supported on a "best effort"
1340843Smsmith** basis only.
1440843Smsmith**
1540843Smsmith** Any third party may reproduce, distribute, or modify the ficl
1640843Smsmith** software code or any derivative  works thereof without any
1740843Smsmith** compensation or license, provided that the author information
1840843Smsmith** and this disclaimer text are retained in the source code files.
1940843Smsmith** The ficl software code is provided on an "as is"  basis without
2040843Smsmith** warranty of any kind, including, without limitation, the implied
2140843Smsmith** warranties of merchantability and fitness for a particular purpose
2240843Smsmith** and their equivalents under the laws of any jurisdiction.
2340843Smsmith**
2440843Smsmith** I am interested in hearing from anyone who uses ficl. If you have
2540843Smsmith** a problem, a success story, a defect, an enhancement request, or
2640843Smsmith** if you would like to contribute to the ficl release (yay!), please
2740843Smsmith** send me email at the address above.
2840843Smsmith*/
2940843Smsmith
3040843Smsmith#if !defined (__FICL_H__)
3140843Smsmith#define __FICL_H__
3240843Smsmith/*
3340843Smsmith** Ficl (Forth-inspired command language) is an ANS Forth
3440843Smsmith** interpreter written in C. Unlike traditional Forths, this
3540843Smsmith** interpreter is designed to be embedded into other systems
3640843Smsmith** as a command/macro/development prototype language.
3740843Smsmith**
3840843Smsmith** Where Forths usually view themselves as the center of the system
3940843Smsmith** and expect the rest of the system to be coded in Forth, Ficl
4040843Smsmith** acts as a component of the system. It is easy to export
4140843Smsmith** code written in C or ASM to Ficl in the style of TCL, or to invoke
4240843Smsmith** Ficl code from a compiled module. This allows you to do incremental
4340843Smsmith** development in a way that combines the best features of threaded
4440843Smsmith** languages (rapid development, quick code/test/debug cycle,
4540843Smsmith** reasonably fast) with the best features of C (everyone knows it,
4640843Smsmith** easier to support large blocks of code, efficient, type checking).
4740843Smsmith**
4840843Smsmith** Ficl provides facilities for interoperating
4940843Smsmith** with programs written in C: C functions can be exported to Ficl,
5040843Smsmith** and Ficl commands can be executed via a C calling interface. The
5140843Smsmith** interpreter is re-entrant, so it can be used in multiple instances
5240843Smsmith** in a multitasking system. Unlike Forth, Ficl's outer interpreter
5340843Smsmith** expects a text block as input, and returns to the caller after each
5440843Smsmith** text block, so the "data pump" is somewhere in external code. This
5540843Smsmith** is more like TCL than Forth, which usually expcets to be at the center
5640843Smsmith** of the system, requesting input at its convenience. Each Ficl virtual
5740843Smsmith** machine can be bound to a different I/O channel, and is independent
5840843Smsmith** of all others in in the same address space except that all virtual
5940843Smsmith** machines share a common dictionary (a sort or open symbol table that
6040843Smsmith** defines all of the elements of the language).
6140843Smsmith**
6240843Smsmith** Code is written in ANSI C for portability.
6340843Smsmith**
6440843Smsmith** Summary of Ficl features and constraints:
6540843Smsmith** - Standard: Implements the ANSI Forth CORE word set and part
6640843Smsmith**   of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and
6740843Smsmith**   TOOLS EXT, LOCAL and LOCAL ext and various extras.
6840843Smsmith** - Extensible: you can export code written in Forth, C,
6940843Smsmith**   or asm in a straightforward way. Ficl provides open
7040843Smsmith**   facilities for extending the language in an application
7140843Smsmith**   specific way. You can even add new control structures!
7240843Smsmith** - Ficl and C can interact in two ways: Ficl can encapsulate
7340843Smsmith**   C code, or C code can invoke Ficl code.
7440843Smsmith** - Thread-safe, re-entrant: The shared system dictionary
7540843Smsmith**   uses a locking mechanism that you can either supply
7640843Smsmith**   or stub out to provide exclusive access. Each Ficl
7740843Smsmith**   virtual machine has an otherwise complete state, and
7840843Smsmith**   each can be bound to a separate I/O channel (or none at all).
7940843Smsmith** - Simple encapsulation into existing systems: a basic implementation
8040843Smsmith**   requires three function calls (see the example program in testmain.c).
8140843Smsmith** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data
8240843Smsmith**   environments. It does require somewhat more memory than a pure
8340843Smsmith**   ROM implementation because it builds its system dictionary in
8440843Smsmith**   RAM at startup time.
8540843Smsmith** - Written an ANSI C to be as simple as I can make it to understand,
8640843Smsmith**   support, debug, and port. Compiles without complaint at /Az /W4
8740843Smsmith**   (require ANSI C, max warnings) under Microsoft VC++ 5.
8840843Smsmith** - Does full 32 bit math (but you need to implement
8940843Smsmith**   two mixed precision math primitives (see sysdep.c))
9040843Smsmith** - Indirect threaded interpreter is not the fastest kind of
9140843Smsmith**   Forth there is (see pForth 68K for a really fast subroutine
9240843Smsmith**   threaded interpreter), but it's the cleanest match to a
9340843Smsmith**   pure C implementation.
9440843Smsmith**
9540843Smsmith** P O R T I N G   F i c l
9640843Smsmith**
9740843Smsmith** To install Ficl on your target system, you need an ANSI C compiler
9840843Smsmith** and its runtime library. Inspect the system dependent macros and
9940843Smsmith** functions in sysdep.h and sysdep.c and edit them to suit your
10040843Smsmith** system. For example, INT16 is a short on some compilers and an
10140843Smsmith** int on others. Check the default CELL alignment controlled by
10240843Smsmith** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree,
10340843Smsmith** ficlLockDictionary, and ficlTextOut to work with your operating system.
10440843Smsmith** Finally, use testmain.c as a guide to installing the Ficl system and
10540843Smsmith** one or more virtual machines into your code. You do not need to include
10640843Smsmith** testmain.c in your build.
10740843Smsmith**
10840843Smsmith** T o   D o   L i s t
10940843Smsmith**
11040843Smsmith** 1. Unimplemented system dependent CORE word: key
11140843Smsmith** 2. Kludged CORE word: ACCEPT
11240843Smsmith** 3. Dictionary locking is full of holes - only one vm at a time
11340843Smsmith**    can alter the dict.
11440843Smsmith** 4. Ficl uses the pad in CORE words - this violates the standard,
11540843Smsmith**    but it's cleaner for a multithreaded system. I'll have to make a
11640843Smsmith**    second pad for reference by the word PAD to fix this.
11743078Smsmith** 5. The whole inner interpreter is screwed up. It ought to be detached
11843078Smsmith**    from ficlExec. Also, it should fall in line with exception
11943078Smsmith**    handling by saving state. (sobral)
12043078Smsmith** 6. EXCEPTION should be cleaned. Right now, it doubles ficlExec's
12143078Smsmith**    inner interpreter. (sobral)
12243078Smsmith** 7. colonParen must get the inner interpreter working on it's "case"
12343078Smsmith**    *before* returning, so that it becomes possible to execute them
12443078Smsmith**    inside other definitions without recreating the inner interpreter
12543078Smsmith**    or other such hacks. (sobral)
12643078Smsmith** 8. We now have EXCEPTION word set. Let's:
12743078Smsmith**    8.1. Use the appropriate exceptions throughout the code.
12843078Smsmith**    8.2. Print the error messages at ficlExec, so someone can catch
12943078Smsmith**         them first. (sobral)
13040843Smsmith**
13140843Smsmith** F o r   M o r e   I n f o r m a t i o n
13240843Smsmith**
13340843Smsmith** Web home of ficl
13440843Smsmith**   http://www.taygeta.com/forth/compilers
13540843Smsmith** Check this website for Forth literature (including the ANSI standard)
13640843Smsmith**   http://www.taygeta.com/forthlit.html
13740843Smsmith** and here for software and more links
13840843Smsmith**   http://www.taygeta.com/forth.html
13940843Smsmith**
14040843Smsmith** Obvious Performance enhancement opportunities
14140843Smsmith** Compile speed
14240843Smsmith** - work on interpret speed
14340843Smsmith** - turn off locals (FICL_WANT_LOCALS)
14440843Smsmith** Interpret speed
14540843Smsmith** - Change inner interpreter (and everything else)
14640843Smsmith**   so that a definition is a list of pointers to functions
14740843Smsmith**   and inline data rather than pointers to words. This gets
14840843Smsmith**   rid of vm->runningWord and a level of indirection in the
14940843Smsmith**   inner loop. I'll look at it for ficl 3.0
15040843Smsmith** - Make the main hash table a bigger prime (HASHSIZE)
15140843Smsmith** - FORGET about twiddling the hash function - my experience is
15240843Smsmith**   that that is a waste of time.
15340843Smsmith** - eliminate the need to pass the pVM parameter on the stack
15440843Smsmith**   by dedicating a register to it. Most words need access to the
15540843Smsmith**   vm, but the parameter passing overhead can be reduced. One way
15640843Smsmith**   requires that the host OS have a task switch callout. Create
15740843Smsmith**   a global variable for the running VM and refer to it in words
15840843Smsmith**   that need VM access. Alternative: use thread local storage.
15940843Smsmith**   For single threaded implementations, you can just use a global.
16040843Smsmith**   The first two solutions create portability problems, so I
16140843Smsmith**   haven't considered doing them. Another possibility is to
16240843Smsmith**   declare the pVm parameter to be "register", and hope the compiler
16340843Smsmith**   pays attention.
16440843Smsmith**
16540843Smsmith*/
16640843Smsmith
16740843Smsmith/*
16840843Smsmith** Revision History:
16943078Smsmith**
17043078Smsmith** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an
17143078Smsmith** "end" field, and all words respect this. ficlExec is passed a "size"
17243078Smsmith** of TIB, as well as vmPushTib. This size is used to calculate the "end"
17343078Smsmith** of the string, ie, base+size. If the size is not known, pass -1.
17443078Smsmith**
17543078Smsmith** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing
17643078Smsmith** words has been modified to conform to EXCEPTION EXT word set.
17743078Smsmith**
17840843Smsmith** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT,
17940843Smsmith**  SEARCH / SEARCH EXT, TOOLS / TOOLS EXT.
18040843Smsmith**  Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD,
18140843Smsmith**  EMPTY to clear stack.
18240843Smsmith**
18340843Smsmith** 29 jun 1998 (sadler) added variable sized hash table support
18440843Smsmith**  and ANS Forth optional SEARCH & SEARCH EXT word set.
18540843Smsmith** 26 May 1998 (sadler)
18640843Smsmith**  FICL_PROMPT macro
18740843Smsmith** 14 April 1998 (sadler) V1.04
18840843Smsmith**  Ficlwin: Windows version, Skip Carter's Linux port
18940843Smsmith** 5 March 1998 (sadler) V1.03
19040843Smsmith**  Bug fixes -- passes John Ryan's ANS test suite "core.fr"
19140843Smsmith**
19240843Smsmith** 24 February 1998 (sadler) V1.02
19340843Smsmith** -Fixed bugs in <# # #>
19440843Smsmith** -Changed FICL_WORD so that storage for the name characters
19540843Smsmith**  can be allocated from the dictionary as needed rather than
19640843Smsmith**  reserving 32 bytes in each word whether needed or not -
19740843Smsmith**  this saved 50% of the dictionary storage requirement.
19840843Smsmith** -Added words in testmain for Win32 functions system,chdir,cwd,
19940843Smsmith**  also added a word that loads and evaluates a file.
20040843Smsmith**
20140843Smsmith** December 1997 (sadler)
20240843Smsmith** -Added VM_RESTART exception handling in ficlExec -- this lets words
20340843Smsmith**  that require additional text to succeed (like :, create, variable...)
20440843Smsmith**  recover gracefully from an empty input buffer rather than emitting
20540843Smsmith**  an error message. Definitions can span multiple input blocks with
20640843Smsmith**  no restrictions.
20740843Smsmith** -Changed #include order so that <assert.h> is included in sysdep.h,
20840843Smsmith**  and sysdep is included in all other files. This lets you define
20940843Smsmith**  NDEBUG in sysdep.h to disable assertions if you want to.
21040843Smsmith** -Make PC specific system dependent code conditional on _M_IX86
21140843Smsmith**  defined so that ports can coexist in sysdep.h/sysdep.c
21240843Smsmith*/
21340843Smsmith
21440843Smsmith#ifdef __cplusplus
21540843Smsmithextern "C" {
21640843Smsmith#endif
21740843Smsmith
21840843Smsmith#include "sysdep.h"
21940843Smsmith#include <limits.h> /* UCHAR_MAX */
22040843Smsmith
22140843Smsmith/*
22240843Smsmith** Forward declarations... read on.
22340843Smsmith*/
22440843Smsmithstruct ficl_word;
22540843Smsmithstruct vm;
22640843Smsmithstruct ficl_dict;
22740843Smsmith
22840843Smsmith/*
22940843Smsmith** the Good Stuff starts here...
23040843Smsmith*/
23140949Smsmith#define FICL_VER   "2.02"
23240977Sjkh#ifndef FICL_PROMPT
23340949Smsmith# define FICL_PROMPT "ok> "
23440949Smsmith#endif
23540843Smsmith
23640843Smsmith/*
23740843Smsmith** ANS Forth requires false to be zero, and true to be the ones
23840843Smsmith** complement of false... that unifies logical and bitwise operations
23940843Smsmith** nicely.
24040843Smsmith*/
24140843Smsmith#define FICL_TRUE  (0xffffffffL)
24240843Smsmith#define FICL_FALSE (0)
24340843Smsmith#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE)
24440843Smsmith
24540843Smsmith
24640843Smsmith/*
24740843Smsmith** A CELL is the main storage type. It must be large enough
24840843Smsmith** to contain a pointer or a scalar. Let's be picky and make
24940843Smsmith** a 32 bit cell explicitly...
25040843Smsmith*/
25140843Smsmithtypedef union _cell
25240843Smsmith{
25340843Smsmith	INT32 i;
25440843Smsmith    UNS32 u;
25540843Smsmith	void *p;
25640843Smsmith} CELL;
25740843Smsmith
25840843Smsmith/*
25940843Smsmith** LVALUEtoCELL does a little pointer trickery to cast any 32 bit
26040843Smsmith** lvalue (informal definition: an expression whose result has an
26140843Smsmith** address) to CELL. Remember that constants and casts are NOT
26240843Smsmith** themselves lvalues!
26340843Smsmith*/
26440843Smsmith#define LVALUEtoCELL(v) (*(CELL *)&v)
26540843Smsmith
26640843Smsmith/*
26740843Smsmith** PTRtoCELL is a cast through void * intended to satisfy the
26840843Smsmith** most outrageously pedantic compiler... (I won't mention
26940843Smsmith** its name)
27040843Smsmith*/
27140843Smsmith#define PTRtoCELL (CELL *)(void *)
27240843Smsmith#define PTRtoSTRING (FICL_STRING *)(void *)
27340843Smsmith
27440843Smsmith/*
27540843Smsmith** Strings in FICL are stored in Pascal style - with a count
27640843Smsmith** preceding the text. We'll also NULL-terminate them so that
27740843Smsmith** they work with the usual C lib string functions. (Belt &
27840843Smsmith** suspenders? You decide.)
27940843Smsmith** STRINGINFO hides the implementation with a couple of
28040843Smsmith** macros for use in internal routines.
28140843Smsmith*/
28240843Smsmith
28340843Smsmithtypedef unsigned char FICL_COUNT;
28440843Smsmith#define FICL_STRING_MAX UCHAR_MAX
28540843Smsmithtypedef struct _ficl_string
28640843Smsmith{
28740843Smsmith    FICL_COUNT count;
28840843Smsmith    char text[1];
28940843Smsmith} FICL_STRING;
29040843Smsmith
29140843Smsmithtypedef struct
29240843Smsmith{
29340843Smsmith    UNS32 count;
29440843Smsmith    char *cp;
29540843Smsmith} STRINGINFO;
29640843Smsmith
29740843Smsmith#define SI_COUNT(si) (si.count)
29840843Smsmith#define SI_PTR(si)   (si.cp)
29940843Smsmith#define SI_SETLEN(si, len) (si.count = (UNS32)(len))
30040843Smsmith#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr))
30140843Smsmith/*
30240843Smsmith** Init a STRINGINFO from a pointer to NULL-terminated string
30340843Smsmith*/
30440843Smsmith#define SI_PSZ(si, psz) \
30540843Smsmith            {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);}
30640843Smsmith/*
30740843Smsmith** Init a STRINGINFO from a pointer to FICL_STRING
30840843Smsmith*/
30940843Smsmith#define SI_PFS(si, pfs) \
31040843Smsmith            {si.cp = pfs->text; si.count = pfs->count;}
31140843Smsmith
31240843Smsmith/*
31340843Smsmith** Ficl uses a this little structure to hold the address of
31440843Smsmith** the block of text it's working on and an index to the next
31540843Smsmith** unconsumed character in the string. Traditionally, this is
31640843Smsmith** done by a Text Input Buffer, so I've called this struct TIB.
31743078Smsmith**
31843078Smsmith** Since this structure also holds the size of the input buffer,
31943078Smsmith** and since evaluate requires that, let's put the size here.
32043078Smsmith** The size is stored as an end-pointer because that is what the
32143078Smsmith** null-terminated string aware functions find most easy to deal
32243078Smsmith** with.
32343078Smsmith** Notice, though, that nobody really uses this except evaluate,
32443078Smsmith** so it might just be moved to FICL_VM instead. (sobral)
32540843Smsmith*/
32640843Smsmithtypedef struct
32740843Smsmith{
32840843Smsmith    INT32 index;
32943078Smsmith    char *end;
33040843Smsmith    char *cp;
33140843Smsmith} TIB;
33240843Smsmith
33340843Smsmith
33440843Smsmith/*
33540843Smsmith** Stacks get heavy use in Ficl and Forth...
33640843Smsmith** Each virtual machine implements two of them:
33740843Smsmith** one holds parameters (data), and the other holds return
33840843Smsmith** addresses and control flow information for the virtual
33940843Smsmith** machine. (Note: C's automatic stack is implicitly used,
34040843Smsmith** but not modeled because it doesn't need to be...)
34140843Smsmith** Here's an abstract type for a stack
34240843Smsmith*/
34340843Smsmithtypedef struct _ficlStack
34440843Smsmith{
34540843Smsmith    UNS32 nCells;       /* size of the stack */
34640843Smsmith    CELL *pFrame;       /* link reg for stack frame */
34740843Smsmith    CELL *sp;           /* stack pointer */
34840843Smsmith    CELL base[1];       /* Bottom of the stack */
34940843Smsmith} FICL_STACK;
35040843Smsmith
35140843Smsmith/*
35240843Smsmith** Stack methods... many map closely to required Forth words.
35340843Smsmith*/
35440843SmsmithFICL_STACK *stackCreate(unsigned nCells);
35540843Smsmithvoid        stackDelete(FICL_STACK *pStack);
35640843Smsmithint         stackDepth (FICL_STACK *pStack);
35740843Smsmithvoid        stackDrop  (FICL_STACK *pStack, int n);
35840843SmsmithCELL        stackFetch (FICL_STACK *pStack, int n);
35940843SmsmithCELL        stackGetTop(FICL_STACK *pStack);
36040843Smsmithvoid        stackLink  (FICL_STACK *pStack, int nCells);
36140843Smsmithvoid        stackPick  (FICL_STACK *pStack, int n);
36240843SmsmithCELL        stackPop   (FICL_STACK *pStack);
36340843Smsmithvoid       *stackPopPtr   (FICL_STACK *pStack);
36440843SmsmithUNS32       stackPopUNS32 (FICL_STACK *pStack);
36540843SmsmithINT32       stackPopINT32 (FICL_STACK *pStack);
36640843Smsmithvoid        stackPush  (FICL_STACK *pStack, CELL c);
36740843Smsmithvoid        stackPushPtr  (FICL_STACK *pStack, void *ptr);
36840843Smsmithvoid        stackPushUNS32(FICL_STACK *pStack, UNS32 u);
36940843Smsmithvoid        stackPushINT32(FICL_STACK *pStack, INT32 i);
37040843Smsmithvoid        stackReset (FICL_STACK *pStack);
37140843Smsmithvoid        stackRoll  (FICL_STACK *pStack, int n);
37240843Smsmithvoid        stackSetTop(FICL_STACK *pStack, CELL c);
37340843Smsmithvoid        stackStore (FICL_STACK *pStack, int n, CELL c);
37440843Smsmithvoid        stackUnlink(FICL_STACK *pStack);
37540843Smsmith
37640843Smsmith/*
37740843Smsmith** The virtual machine (VM) contains the state for one interpreter.
37840843Smsmith** Defined operations include:
37940843Smsmith** Create & initialize
38040843Smsmith** Delete
38140843Smsmith** Execute a block of text
38240843Smsmith** Parse a word out of the input stream
38340843Smsmith** Call return, and branch
38440843Smsmith** Text output
38540843Smsmith** Throw an exception
38640843Smsmith*/
38740843Smsmith
38840843Smsmithtypedef struct ficl_word ** IPTYPE; /* the VM's instruction pointer */
38940843Smsmith
39040843Smsmith/*
39140843Smsmith** Each VM has a placeholder for an output function -
39240843Smsmith** this makes it possible to have each VM do I/O
39340843Smsmith** through a different device. If you specify no
39440843Smsmith** OUTFUNC, it defaults to ficlTextOut.
39540843Smsmith*/
39640843Smsmithtypedef void (*OUTFUNC)(struct vm *pVM, char *text, int fNewline);
39740843Smsmith
39840843Smsmith/*
39940843Smsmith** Each VM operates in one of two non-error states: interpreting
40040843Smsmith** or compiling. When interpreting, words are simply executed.
40140843Smsmith** When compiling, most words in the input stream have their
40240843Smsmith** addresses inserted into the word under construction. Some words
40340843Smsmith** (known as IMMEDIATE) are executed in the compile state, too.
40440843Smsmith*/
40540843Smsmith/* values of STATE */
40640843Smsmith#define INTERPRET 0
40740843Smsmith#define COMPILE   1
40840843Smsmith
40940843Smsmith/*
41040843Smsmith** The pad is a small scratch area for text manipulation. ANS Forth
41140843Smsmith** requires it to hold at least 84 characters.
41240843Smsmith*/
41340843Smsmith#if !defined nPAD
41440843Smsmith#define nPAD 256
41540843Smsmith#endif
41640843Smsmith
41740843Smsmith/*
41840843Smsmith** ANS Forth requires that a word's name contain {1..31} characters.
41940843Smsmith*/
42040843Smsmith#if !defined nFICLNAME
42140843Smsmith#define nFICLNAME		31
42240843Smsmith#endif
42340843Smsmith
42440843Smsmith/*
42540843Smsmith** OK - now we can really define the VM...
42640843Smsmith*/
42740843Smsmithtypedef struct vm
42840843Smsmith{
42940843Smsmith    struct vm      *link;       /* Ficl keeps a VM list for simple teardown */
43040843Smsmith    jmp_buf        *pState;     /* crude exception mechanism...     */
43140843Smsmith    OUTFUNC         textOut;    /* Output callback - see sysdep.c   */
43240843Smsmith    void *          pExtend;    /* vm extension pointer             */
43340843Smsmith    short           fRestart;   /* Set TRUE to restart runningWord  */
43440843Smsmith    IPTYPE          ip;         /* instruction pointer              */
43540843Smsmith    struct ficl_word
43640843Smsmith                   *runningWord;/* address of currently running word (often just *(ip-1) ) */
43740843Smsmith    UNS32           state;      /* compiling or interpreting        */
43840843Smsmith    UNS32           base;       /* number conversion base           */
43940843Smsmith    FICL_STACK     *pStack;     /* param stack                      */
44040843Smsmith    FICL_STACK     *rStack;     /* return stack                     */
44140843Smsmith    CELL            sourceID;   /* -1 if string, 0 if normal input  */
44240843Smsmith    TIB             tib;        /* address of incoming text string  */
44340843Smsmith#if FICL_WANT_USER
44440843Smsmith    CELL            user[FICL_USER_CELLS];
44540843Smsmith#endif
44640843Smsmith    char            pad[nPAD];  /* the scratch area (see above)     */
44740843Smsmith} FICL_VM;
44840843Smsmith
44940843Smsmith/*
45040843Smsmith** A FICL_CODE points to a function that gets called to help execute
45140843Smsmith** a word in the dictionary. It always gets passed a pointer to the
45240843Smsmith** running virtual machine, and from there it can get the address
45340843Smsmith** of the parameter area of the word it's supposed to operate on.
45440843Smsmith** For precompiled words, the code is all there is. For user defined
45540843Smsmith** words, the code assumes that the word's parameter area is a list
45640843Smsmith** of pointers to the code fields of other words to execute, and
45740843Smsmith** may also contain inline data. The first parameter is always
45840843Smsmith** a pointer to a code field.
45940843Smsmith*/
46040843Smsmithtypedef void (*FICL_CODE)(FICL_VM *pVm);
46140843Smsmith
46240843Smsmith/*
46340843Smsmith** Ficl models memory as a contiguous space divided into
46440843Smsmith** words in a linked list called the dictionary.
46540843Smsmith** A FICL_WORD starts each entry in the list.
46640843Smsmith** Version 1.02: space for the name characters is allotted from
46740843Smsmith** the dictionary ahead of the word struct - this saves about half
46840843Smsmith** the storage on average with very little runtime cost.
46940843Smsmith*/
47040843Smsmithtypedef struct ficl_word
47140843Smsmith{
47240843Smsmith    struct ficl_word *link;     /* Previous word in the dictionary      */
47340843Smsmith    UNS16 hash;
47440843Smsmith    UNS8 flags;                 /* Immediate, Smudge, Compile-only      */
47540843Smsmith    FICL_COUNT nName;           /* Number of chars in word name         */
47640843Smsmith    char *name;                 /* First nFICLNAME chars of word name   */
47740843Smsmith    FICL_CODE code;             /* Native code to execute the word      */
47840843Smsmith    CELL param[1];              /* First data cell of the word          */
47940843Smsmith} FICL_WORD;
48040843Smsmith
48140843Smsmith/*
48240843Smsmith** Worst-case size of a word header: nFICLNAME chars in name
48340843Smsmith*/
48440843Smsmith#define CELLS_PER_WORD  \
48540843Smsmith    ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \
48640843Smsmith                          / (sizeof (CELL)) )
48740843Smsmith
48840843Smsmithint wordIsImmediate(FICL_WORD *pFW);
48940843Smsmithint wordIsCompileOnly(FICL_WORD *pFW);
49040843Smsmith
49140843Smsmith/* flag values for word header */
49240843Smsmith#define FW_IMMEDIATE    1   /* execute me even if compiling */
49340843Smsmith#define FW_COMPILE      2   /* error if executed when not compiling */
49440843Smsmith#define FW_SMUDGE       4   /* definition in progress - hide me */
49540843Smsmith#define FW_CLASS        8   /* Word defines a class */
49640843Smsmith
49740843Smsmith#define FW_COMPIMMED    (FW_IMMEDIATE | FW_COMPILE)
49840843Smsmith#define FW_DEFAULT      0
49940843Smsmith
50040843Smsmith
50140843Smsmith/*
50240843Smsmith** Exit codes for vmThrow
50340843Smsmith*/
50443078Smsmith#define VM_OUTOFTEXT -256   /* hungry - normal exit */
50543078Smsmith#define VM_RESTART   -257   /* word needs more text to suxcceed - re-run it */
50643078Smsmith#define VM_USEREXIT  -258   /* user wants to quit */
50743078Smsmith#define VM_ERREXIT   -259   /* interp found an error */
50843078Smsmith#define VM_ABORT       -1   /* like errexit -- abort */
50943078Smsmith#define VM_ABORTQ      -2   /* like errexit -- abort" */
51043078Smsmith#define VM_QUIT       -56   /* like errexit, but leave pStack & base alone */
51140843Smsmith
51240843Smsmith
51340843Smsmithvoid        vmBranchRelative(FICL_VM *pVM, int offset);
51440843SmsmithFICL_VM *   vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack);
51540843Smsmithvoid        vmDelete (FICL_VM *pVM);
51640843Smsmithvoid        vmExecute(FICL_VM *pVM, FICL_WORD *pWord);
51740843Smsmithchar *      vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter);
51840843SmsmithSTRINGINFO  vmGetWord(FICL_VM *pVM);
51940843SmsmithSTRINGINFO  vmGetWord0(FICL_VM *pVM);
52040843Smsmithint         vmGetWordToPad(FICL_VM *pVM);
52140843SmsmithSTRINGINFO  vmParseString(FICL_VM *pVM, char delimiter);
52240843Smsmithvoid        vmPopIP  (FICL_VM *pVM);
52340843Smsmithvoid        vmPushIP (FICL_VM *pVM, IPTYPE newIP);
52440843Smsmithvoid        vmQuit   (FICL_VM *pVM);
52540843Smsmithvoid        vmReset  (FICL_VM *pVM);
52640843Smsmithvoid        vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut);
52740843Smsmithvoid        vmTextOut(FICL_VM *pVM, char *text, int fNewline);
52840843Smsmithvoid        vmThrow  (FICL_VM *pVM, int except);
52940843Smsmithvoid        vmThrowErr(FICL_VM *pVM, char *fmt, ...);
53040843Smsmith
53140843Smsmith/*
53240843Smsmith** vmCheckStack needs a vm pointer because it might have to say
53340843Smsmith** something if it finds a problem. Parms popCells and pushCells
53440843Smsmith** correspond to the number of parameters on the left and right of
53540843Smsmith** a word's stack effect comment.
53640843Smsmith*/
53740843Smsmithvoid        vmCheckStack(FICL_VM *pVM, int popCells, int pushCells);
53840843Smsmith
53940843Smsmith/*
54040843Smsmith** TIB access routines...
54140843Smsmith** ANS forth seems to require the input buffer to be represented
54240843Smsmith** as a pointer to the start of the buffer, and an index to the
54340843Smsmith** next character to read.
54440843Smsmith** PushTib points the VM to a new input string and optionally
54540843Smsmith**  returns a copy of the current state
54640843Smsmith** PopTib restores the TIB state given a saved TIB from PushTib
54740843Smsmith** GetInBuf returns a pointer to the next unused char of the TIB
54840843Smsmith*/
54943078Smsmithvoid        vmPushTib(FICL_VM *pVM, char *text, INT32 size, TIB *pSaveTib);
55040843Smsmithvoid        vmPopTib(FICL_VM *pVM, TIB *pTib);
55140843Smsmith#define     vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index)
55240843Smsmith#define     vmSetTibIndex(pVM, i) (pVM)->tib.index = i
55340843Smsmith#define     vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp
55440843Smsmith
55540843Smsmith/*
55640843Smsmith** Generally useful string manipulators omitted by ANSI C...
55740843Smsmith** ltoa complements strtol
55840843Smsmith*/
55940843Smsmith#if defined(_WIN32) && !FICL_MAIN
56040843Smsmith/* #SHEESH
56140843Smsmith** Why do Microsoft Meatballs insist on contaminating
56240843Smsmith** my namespace with their string functions???
56340843Smsmith*/
56440843Smsmith#pragma warning(disable: 4273)
56540843Smsmith#endif
56640843Smsmith
56740843Smsmithchar       *ltoa( INT32 value, char *string, int radix );
56840843Smsmithchar       *ultoa(UNS32 value, char *string, int radix );
56940843Smsmithchar        digit_to_char(int value);
57040843Smsmithchar       *strrev( char *string );
57143078Smsmithchar       *skipSpace(char *cp,char *end);
57240843Smsmithchar       *caseFold(char *cp);
57340843Smsmithint         strincmp(char *cp1, char *cp2, FICL_COUNT count);
57440843Smsmith
57540843Smsmith#if defined(_WIN32) && !FICL_MAIN
57640843Smsmith#pragma warning(default: 4273)
57740843Smsmith#endif
57840843Smsmith
57940843Smsmith/*
58040843Smsmith** Ficl hash table - variable size.
58140843Smsmith** assert(size > 0)
58240843Smsmith** If size is 1, the table degenerates into a linked list.
58340843Smsmith** A WORDLIST (see the search order word set in DPANS) is
58440843Smsmith** just a pointer to a FICL_HASH in this implementation.
58540843Smsmith*/
58640843Smsmith#if !defined HASHSIZE /* Default size of hash table. For best */
58740843Smsmith#define HASHSIZE 127  /*   performance, use a prime number!   */
58840843Smsmith#endif
58940843Smsmith
59040843Smsmithtypedef struct ficl_hash
59140843Smsmith{
59240843Smsmith    struct ficl_hash *link;  /* eventual inheritance support */
59340843Smsmith    unsigned   size;
59440843Smsmith    FICL_WORD *table[1];
59540843Smsmith} FICL_HASH;
59640843Smsmith
59740843Smsmithvoid        hashForget(FICL_HASH *pHash, void *where);
59840843SmsmithUNS16       hashHashCode(STRINGINFO si);
59940843Smsmithvoid        hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW);
60040843SmsmithFICL_WORD  *hashLookup(struct ficl_hash *pHash,
60140843Smsmith                       STRINGINFO si,
60240843Smsmith                       UNS16 hashCode);
60340843Smsmithvoid        hashReset(FICL_HASH *pHash);
60440843Smsmith
60540843Smsmith/*
60640843Smsmith** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's
60740843Smsmith** memory model. Description of fields:
60840843Smsmith**
60940843Smsmith** here -- points to the next free byte in the dictionary. This
61040843Smsmith**      pointer is forced to be CELL-aligned before a definition is added.
61140843Smsmith**      Do not assume any specific alignment otherwise - Use dictAlign().
61240843Smsmith**
61340843Smsmith** smudge -- pointer to word currently being defined (or last defined word)
61440843Smsmith**      If the definition completes successfully, the word will be
61540843Smsmith**      linked into the hash table. If unsuccessful, dictUnsmudge
61640843Smsmith**      uses this pointer to restore the previous state of the dictionary.
61740843Smsmith**      Smudge prevents unintentional recursion as a side-effect: the
61840843Smsmith**      dictionary search algo examines only completed definitions, so a
61940843Smsmith**      word cannot invoke itself by name. See the ficl word "recurse".
62040843Smsmith**      NOTE: smudge always points to the last word defined. IMMEDIATE
62140843Smsmith**      makes use of this fact. Smudge is initially NULL.
62240843Smsmith**
62340843Smsmith** pForthWords -- pointer to the default wordlist (FICL_HASH).
62440843Smsmith**      This is the initial compilation list, and contains all
62540843Smsmith**      ficl's precompiled words.
62640843Smsmith**
62740843Smsmith** pCompile -- compilation wordlist - initially equal to pForthWords
62840843Smsmith** pSearch  -- array of pointers to wordlists. Managed as a stack.
62940843Smsmith**      Highest index is the first list in the search order.
63040843Smsmith** nLists   -- number of lists in pSearch. nLists-1 is the highest
63140843Smsmith**      filled slot in pSearch, and points to the first wordlist
63240843Smsmith**      in the search order
63340843Smsmith** size -- number of cells in the dictionary (total)
63440843Smsmith** dict -- start of data area. Must be at the end of the struct.
63540843Smsmith*/
63640843Smsmithtypedef struct ficl_dict
63740843Smsmith{
63840843Smsmith    CELL *here;
63940843Smsmith    FICL_WORD *smudge;
64040843Smsmith    FICL_HASH *pForthWords;
64140843Smsmith    FICL_HASH *pCompile;
64240843Smsmith    FICL_HASH *pSearch[FICL_DEFAULT_VOCS];
64340843Smsmith    int        nLists;
64440843Smsmith    unsigned   size;    /* Number of cells in dict (total)*/
64540843Smsmith    CELL       dict[1]; /* Base of dictionary memory      */
64640843Smsmith} FICL_DICT;
64740843Smsmith
64840843Smsmithvoid       *alignPtr(void *ptr);
64940843Smsmithvoid        dictAbortDefinition(FICL_DICT *pDict);
65040843Smsmithvoid        dictAlign(FICL_DICT *pDict);
65140843Smsmithint         dictAllot(FICL_DICT *pDict, int n);
65240843Smsmithint         dictAllotCells(FICL_DICT *pDict, int nCells);
65340843Smsmithvoid        dictAppendCell(FICL_DICT *pDict, CELL c);
65440843Smsmithvoid        dictAppendChar(FICL_DICT *pDict, char c);
65540843SmsmithFICL_WORD  *dictAppendWord(FICL_DICT *pDict,
65640843Smsmith                           char *name,
65740843Smsmith                           FICL_CODE pCode,
65840843Smsmith                           UNS8 flags);
65940843SmsmithFICL_WORD  *dictAppendWord2(FICL_DICT *pDict,
66040843Smsmith                           STRINGINFO si,
66140843Smsmith                           FICL_CODE pCode,
66240843Smsmith                           UNS8 flags);
66340843Smsmithvoid        dictAppendUNS32(FICL_DICT *pDict, UNS32 u);
66440843Smsmithint         dictCellsAvail(FICL_DICT *pDict);
66540843Smsmithint         dictCellsUsed (FICL_DICT *pDict);
66640843Smsmithvoid        dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells);
66740843SmsmithFICL_DICT  *dictCreate(unsigned nCELLS);
66840843SmsmithFICL_DICT  *dictCreateHashed(unsigned nCells, unsigned nHash);
66940843Smsmithvoid        dictDelete(FICL_DICT *pDict);
67040843Smsmithvoid        dictEmpty(FICL_DICT *pDict, unsigned nHash);
67140843Smsmithvoid        dictHashSummary(FICL_VM *pVM);
67240843Smsmithint         dictIncludes(FICL_DICT *pDict, void *p);
67340843SmsmithFICL_WORD  *dictLookup(FICL_DICT *pDict, STRINGINFO si);
67440843Smsmith#if FICL_WANT_LOCALS
67540843SmsmithFICL_WORD  *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si);
67640843Smsmith#endif
67740843Smsmithvoid        dictResetSearchOrder(FICL_DICT *pDict);
67840843Smsmithvoid        dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr);
67940843Smsmithvoid        dictSetImmediate(FICL_DICT *pDict);
68040843Smsmithvoid        dictUnsmudge(FICL_DICT *pDict);
68140843SmsmithCELL       *dictWhere(FICL_DICT *pDict);
68240843Smsmith
68340843Smsmith
68440843Smsmith/*
68540843Smsmith** External interface to FICL...
68640843Smsmith*/
68740843Smsmith/*
68840843Smsmith** f i c l I n i t S y s t e m
68940843Smsmith** Binds a global dictionary to the interpreter system and initializes
69040843Smsmith** the dict to contain the ANSI CORE wordset.
69140843Smsmith** You specify the address and size of the allocated area.
69240843Smsmith** After that, ficl manages it.
69340843Smsmith** First step is to set up the static pointers to the area.
69440843Smsmith** Then write the "precompiled" portion of the dictionary in.
69540843Smsmith** The dictionary needs to be at least large enough to hold the
69640843Smsmith** precompiled part. Try 1K cells minimum. Use "words" to find
69740843Smsmith** out how much of the dictionary is used at any time.
69840843Smsmith*/
69940843Smsmithvoid       ficlInitSystem(int nDictCells);
70040843Smsmith
70140843Smsmith/*
70240843Smsmith** f i c l T e r m S y s t e m
70340843Smsmith** Deletes the system dictionary and all virtual machines that
70440843Smsmith** were created with ficlNewVM (see below). Call this function to
70540843Smsmith** reclaim all memory used by the dictionary and VMs.
70640843Smsmith*/
70740843Smsmithvoid       ficlTermSystem(void);
70840843Smsmith
70940843Smsmith/*
71040843Smsmith** f i c l E x e c
71140843Smsmith** Evaluates a block of input text in the context of the
71240843Smsmith** specified interpreter. Emits any requested output to the
71343078Smsmith** interpreter's output function. If the size of the input
71443078Smsmith** is not known, pass -1.
71540843Smsmith** Execution returns when the text block has been executed,
71640843Smsmith** or an error occurs.
71740843Smsmith** Returns one of the VM_XXXX codes defined in ficl.h:
71840843Smsmith** VM_OUTOFTEXT is the normal exit condition
71940843Smsmith** VM_ERREXIT means that the interp encountered a syntax error
72040843Smsmith**      and the vm has been reset to recover (some or all
72140843Smsmith**      of the text block got ignored
72240843Smsmith** VM_USEREXIT means that the user executed the "bye" command
72340843Smsmith**      to shut down the interpreter. This would be a good
72440843Smsmith**      time to delete the vm, etc -- or you can ignore this
72540843Smsmith**      signal.
72643078Smsmith** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"'
72743078Smsmith**      commands.
72840843Smsmith** Preconditions: successful execution of ficlInitSystem,
72940843Smsmith**      Successful creation and init of the VM by ficlNewVM (or equiv)
73040843Smsmith*/
73143078Smsmithint        ficlExec(FICL_VM *pVM, char *pText, INT32 size);
73240843Smsmith
73340843Smsmith/*
73440989Sjkh** ficlExecFD(FICL_VM *pVM, int fd);
73540989Sjkh * Evaluates text from file passed in via fd.
73640989Sjkh * Execution returns when all of file has been executed or an
73740989Sjkh * error occurs.
73840989Sjkh */
73940989Sjkhint        ficlExecFD(FICL_VM *pVM, int fd);
74040989Sjkh
74140989Sjkh/*
74240843Smsmith** Create a new VM from the heap, and link it into the system VM list.
74340843Smsmith** Initializes the VM and binds default sized stacks to it. Returns the
74440843Smsmith** address of the VM, or NULL if an error occurs.
74540843Smsmith** Precondition: successful execution of ficlInitSystem
74640843Smsmith*/
74740843SmsmithFICL_VM   *ficlNewVM(void);
74840843Smsmith
74940843Smsmith/*
75040843Smsmith** Returns the address of the most recently defined word in the system
75140843Smsmith** dictionary with the given name, or NULL if no match.
75240843Smsmith** Precondition: successful execution of ficlInitSystem
75340843Smsmith*/
75440843SmsmithFICL_WORD *ficlLookup(char *name);
75540843Smsmith
75640843Smsmith/*
75740843Smsmith** f i c l G e t D i c t
75840843Smsmith** Utility function - returns the address of the system dictionary.
75940843Smsmith** Precondition: successful execution of ficlInitSystem
76040843Smsmith*/
76140843SmsmithFICL_DICT *ficlGetDict(void);
76240843SmsmithFICL_DICT *ficlGetEnv(void);
76340843Smsmithvoid       ficlSetEnv(char *name, UNS32 value);
76440843Smsmithvoid       ficlSetEnvD(char *name, UNS32 hi, UNS32 lo);
76540843Smsmith#if FICL_WANT_LOCALS
76640843SmsmithFICL_DICT *ficlGetLoc(void);
76740843Smsmith#endif
76840843Smsmith/*
76940843Smsmith** f i c l B u i l d
77040843Smsmith** Builds a word into the system default dictionary in a thread-safe way.
77140843Smsmith** Preconditions: system must be initialized, and there must
77240843Smsmith** be enough space for the new word's header! Operation is
77340843Smsmith** controlled by ficlLockDictionary, so any initialization
77440843Smsmith** required by your version of the function (if you "overrode"
77540843Smsmith** it) must be complete at this point.
77640843Smsmith** Parameters:
77740843Smsmith** name  -- the name of the word to be built
77840843Smsmith** code  -- code to execute when the word is invoked - must take a single param
77940843Smsmith**          pointer to a FICL_VM
78040843Smsmith** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR!
78140843Smsmith**          Most words can use FW_DEFAULT.
78240843Smsmith** nAllot - number of extra cells to allocate in the parameter area (usually zero)
78340843Smsmith*/
78440843Smsmithint        ficlBuild(char *name, FICL_CODE code, char flags);
78540843Smsmith
78640843Smsmith/*
78740843Smsmith** f i c l C o m p i l e C o r e
78840843Smsmith** Builds the ANS CORE wordset into the dictionary - called by
78940843Smsmith** ficlInitSystem - no need to waste dict space by doing it again.
79040843Smsmith*/
79140843Smsmithvoid       ficlCompileCore(FICL_DICT *dp);
79240843Smsmithvoid       ficlCompileSoftCore(FICL_VM *pVM);
79340843Smsmith
79440843Smsmith/*
79540843Smsmith** from words.c...
79640843Smsmith*/
79740843Smsmithvoid       constantParen(FICL_VM *pVM);
79840843Smsmithvoid       twoConstParen(FICL_VM *pVM);
79940843Smsmith
80043139Smsmith/*
80143139Smsmith** So we can more easily debug...
80243139Smsmith*/
80343139Smsmith#ifdef FICL_TRACE
80443139Smsmithextern int ficl_trace;
80543139Smsmith#endif
80643139Smsmith
80742679Sabial#if defined(__i386__) && !defined(TESTMAIN)
80842679Sabialextern void ficlOutb(FICL_VM *pVM);
80942679Sabialextern void ficlInb(FICL_VM *pVM);
81042634Sabial#endif
81142634Sabial
81240843Smsmith#ifdef __cplusplus
81340843Smsmith}
81440843Smsmith#endif
81540843Smsmith
81640843Smsmith#endif /* __FICL_H__ */
817