ficl.h revision 42634
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.
11740843Smsmith**
11840843Smsmith** F o r   M o r e   I n f o r m a t i o n
11940843Smsmith**
12040843Smsmith** Web home of ficl
12140843Smsmith**   http://www.taygeta.com/forth/compilers
12240843Smsmith** Check this website for Forth literature (including the ANSI standard)
12340843Smsmith**   http://www.taygeta.com/forthlit.html
12440843Smsmith** and here for software and more links
12540843Smsmith**   http://www.taygeta.com/forth.html
12640843Smsmith**
12740843Smsmith** Obvious Performance enhancement opportunities
12840843Smsmith** Compile speed
12940843Smsmith** - work on interpret speed
13040843Smsmith** - turn off locals (FICL_WANT_LOCALS)
13140843Smsmith** Interpret speed
13240843Smsmith** - Change inner interpreter (and everything else)
13340843Smsmith**   so that a definition is a list of pointers to functions
13440843Smsmith**   and inline data rather than pointers to words. This gets
13540843Smsmith**   rid of vm->runningWord and a level of indirection in the
13640843Smsmith**   inner loop. I'll look at it for ficl 3.0
13740843Smsmith** - Make the main hash table a bigger prime (HASHSIZE)
13840843Smsmith** - FORGET about twiddling the hash function - my experience is
13940843Smsmith**   that that is a waste of time.
14040843Smsmith** - eliminate the need to pass the pVM parameter on the stack
14140843Smsmith**   by dedicating a register to it. Most words need access to the
14240843Smsmith**   vm, but the parameter passing overhead can be reduced. One way
14340843Smsmith**   requires that the host OS have a task switch callout. Create
14440843Smsmith**   a global variable for the running VM and refer to it in words
14540843Smsmith**   that need VM access. Alternative: use thread local storage.
14640843Smsmith**   For single threaded implementations, you can just use a global.
14740843Smsmith**   The first two solutions create portability problems, so I
14840843Smsmith**   haven't considered doing them. Another possibility is to
14940843Smsmith**   declare the pVm parameter to be "register", and hope the compiler
15040843Smsmith**   pays attention.
15140843Smsmith**
15240843Smsmith*/
15340843Smsmith
15440843Smsmith/*
15540843Smsmith** Revision History:
15640843Smsmith** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT,
15740843Smsmith**  SEARCH / SEARCH EXT, TOOLS / TOOLS EXT.
15840843Smsmith**  Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD,
15940843Smsmith**  EMPTY to clear stack.
16040843Smsmith**
16140843Smsmith** 29 jun 1998 (sadler) added variable sized hash table support
16240843Smsmith**  and ANS Forth optional SEARCH & SEARCH EXT word set.
16340843Smsmith** 26 May 1998 (sadler)
16440843Smsmith**  FICL_PROMPT macro
16540843Smsmith** 14 April 1998 (sadler) V1.04
16640843Smsmith**  Ficlwin: Windows version, Skip Carter's Linux port
16740843Smsmith** 5 March 1998 (sadler) V1.03
16840843Smsmith**  Bug fixes -- passes John Ryan's ANS test suite "core.fr"
16940843Smsmith**
17040843Smsmith** 24 February 1998 (sadler) V1.02
17140843Smsmith** -Fixed bugs in <# # #>
17240843Smsmith** -Changed FICL_WORD so that storage for the name characters
17340843Smsmith**  can be allocated from the dictionary as needed rather than
17440843Smsmith**  reserving 32 bytes in each word whether needed or not -
17540843Smsmith**  this saved 50% of the dictionary storage requirement.
17640843Smsmith** -Added words in testmain for Win32 functions system,chdir,cwd,
17740843Smsmith**  also added a word that loads and evaluates a file.
17840843Smsmith**
17940843Smsmith** December 1997 (sadler)
18040843Smsmith** -Added VM_RESTART exception handling in ficlExec -- this lets words
18140843Smsmith**  that require additional text to succeed (like :, create, variable...)
18240843Smsmith**  recover gracefully from an empty input buffer rather than emitting
18340843Smsmith**  an error message. Definitions can span multiple input blocks with
18440843Smsmith**  no restrictions.
18540843Smsmith** -Changed #include order so that <assert.h> is included in sysdep.h,
18640843Smsmith**  and sysdep is included in all other files. This lets you define
18740843Smsmith**  NDEBUG in sysdep.h to disable assertions if you want to.
18840843Smsmith** -Make PC specific system dependent code conditional on _M_IX86
18940843Smsmith**  defined so that ports can coexist in sysdep.h/sysdep.c
19040843Smsmith*/
19140843Smsmith
19240843Smsmith#ifdef __cplusplus
19340843Smsmithextern "C" {
19440843Smsmith#endif
19540843Smsmith
19640843Smsmith#include "sysdep.h"
19740843Smsmith#include <limits.h> /* UCHAR_MAX */
19840843Smsmith
19940843Smsmith/*
20040843Smsmith** Forward declarations... read on.
20140843Smsmith*/
20240843Smsmithstruct ficl_word;
20340843Smsmithstruct vm;
20440843Smsmithstruct ficl_dict;
20540843Smsmith
20640843Smsmith/*
20740843Smsmith** the Good Stuff starts here...
20840843Smsmith*/
20940949Smsmith#define FICL_VER   "2.02"
21040977Sjkh#ifndef FICL_PROMPT
21140949Smsmith# define FICL_PROMPT "ok> "
21240949Smsmith#endif
21340843Smsmith
21440843Smsmith/*
21540843Smsmith** ANS Forth requires false to be zero, and true to be the ones
21640843Smsmith** complement of false... that unifies logical and bitwise operations
21740843Smsmith** nicely.
21840843Smsmith*/
21940843Smsmith#define FICL_TRUE  (0xffffffffL)
22040843Smsmith#define FICL_FALSE (0)
22140843Smsmith#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE)
22240843Smsmith
22340843Smsmith
22440843Smsmith/*
22540843Smsmith** A CELL is the main storage type. It must be large enough
22640843Smsmith** to contain a pointer or a scalar. Let's be picky and make
22740843Smsmith** a 32 bit cell explicitly...
22840843Smsmith*/
22940843Smsmithtypedef union _cell
23040843Smsmith{
23140843Smsmith	INT32 i;
23240843Smsmith    UNS32 u;
23340843Smsmith	void *p;
23440843Smsmith} CELL;
23540843Smsmith
23640843Smsmith/*
23740843Smsmith** LVALUEtoCELL does a little pointer trickery to cast any 32 bit
23840843Smsmith** lvalue (informal definition: an expression whose result has an
23940843Smsmith** address) to CELL. Remember that constants and casts are NOT
24040843Smsmith** themselves lvalues!
24140843Smsmith*/
24240843Smsmith#define LVALUEtoCELL(v) (*(CELL *)&v)
24340843Smsmith
24440843Smsmith/*
24540843Smsmith** PTRtoCELL is a cast through void * intended to satisfy the
24640843Smsmith** most outrageously pedantic compiler... (I won't mention
24740843Smsmith** its name)
24840843Smsmith*/
24940843Smsmith#define PTRtoCELL (CELL *)(void *)
25040843Smsmith#define PTRtoSTRING (FICL_STRING *)(void *)
25140843Smsmith
25240843Smsmith/*
25340843Smsmith** Strings in FICL are stored in Pascal style - with a count
25440843Smsmith** preceding the text. We'll also NULL-terminate them so that
25540843Smsmith** they work with the usual C lib string functions. (Belt &
25640843Smsmith** suspenders? You decide.)
25740843Smsmith** STRINGINFO hides the implementation with a couple of
25840843Smsmith** macros for use in internal routines.
25940843Smsmith*/
26040843Smsmith
26140843Smsmithtypedef unsigned char FICL_COUNT;
26240843Smsmith#define FICL_STRING_MAX UCHAR_MAX
26340843Smsmithtypedef struct _ficl_string
26440843Smsmith{
26540843Smsmith    FICL_COUNT count;
26640843Smsmith    char text[1];
26740843Smsmith} FICL_STRING;
26840843Smsmith
26940843Smsmithtypedef struct
27040843Smsmith{
27140843Smsmith    UNS32 count;
27240843Smsmith    char *cp;
27340843Smsmith} STRINGINFO;
27440843Smsmith
27540843Smsmith#define SI_COUNT(si) (si.count)
27640843Smsmith#define SI_PTR(si)   (si.cp)
27740843Smsmith#define SI_SETLEN(si, len) (si.count = (UNS32)(len))
27840843Smsmith#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr))
27940843Smsmith/*
28040843Smsmith** Init a STRINGINFO from a pointer to NULL-terminated string
28140843Smsmith*/
28240843Smsmith#define SI_PSZ(si, psz) \
28340843Smsmith            {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);}
28440843Smsmith/*
28540843Smsmith** Init a STRINGINFO from a pointer to FICL_STRING
28640843Smsmith*/
28740843Smsmith#define SI_PFS(si, pfs) \
28840843Smsmith            {si.cp = pfs->text; si.count = pfs->count;}
28940843Smsmith
29040843Smsmith/*
29140843Smsmith** Ficl uses a this little structure to hold the address of
29240843Smsmith** the block of text it's working on and an index to the next
29340843Smsmith** unconsumed character in the string. Traditionally, this is
29440843Smsmith** done by a Text Input Buffer, so I've called this struct TIB.
29540843Smsmith*/
29640843Smsmithtypedef struct
29740843Smsmith{
29840843Smsmith    INT32 index;
29940843Smsmith    char *cp;
30040843Smsmith} TIB;
30140843Smsmith
30240843Smsmith
30340843Smsmith/*
30440843Smsmith** Stacks get heavy use in Ficl and Forth...
30540843Smsmith** Each virtual machine implements two of them:
30640843Smsmith** one holds parameters (data), and the other holds return
30740843Smsmith** addresses and control flow information for the virtual
30840843Smsmith** machine. (Note: C's automatic stack is implicitly used,
30940843Smsmith** but not modeled because it doesn't need to be...)
31040843Smsmith** Here's an abstract type for a stack
31140843Smsmith*/
31240843Smsmithtypedef struct _ficlStack
31340843Smsmith{
31440843Smsmith    UNS32 nCells;       /* size of the stack */
31540843Smsmith    CELL *pFrame;       /* link reg for stack frame */
31640843Smsmith    CELL *sp;           /* stack pointer */
31740843Smsmith    CELL base[1];       /* Bottom of the stack */
31840843Smsmith} FICL_STACK;
31940843Smsmith
32040843Smsmith/*
32140843Smsmith** Stack methods... many map closely to required Forth words.
32240843Smsmith*/
32340843SmsmithFICL_STACK *stackCreate(unsigned nCells);
32440843Smsmithvoid        stackDelete(FICL_STACK *pStack);
32540843Smsmithint         stackDepth (FICL_STACK *pStack);
32640843Smsmithvoid        stackDrop  (FICL_STACK *pStack, int n);
32740843SmsmithCELL        stackFetch (FICL_STACK *pStack, int n);
32840843SmsmithCELL        stackGetTop(FICL_STACK *pStack);
32940843Smsmithvoid        stackLink  (FICL_STACK *pStack, int nCells);
33040843Smsmithvoid        stackPick  (FICL_STACK *pStack, int n);
33140843SmsmithCELL        stackPop   (FICL_STACK *pStack);
33240843Smsmithvoid       *stackPopPtr   (FICL_STACK *pStack);
33340843SmsmithUNS32       stackPopUNS32 (FICL_STACK *pStack);
33440843SmsmithINT32       stackPopINT32 (FICL_STACK *pStack);
33540843Smsmithvoid        stackPush  (FICL_STACK *pStack, CELL c);
33640843Smsmithvoid        stackPushPtr  (FICL_STACK *pStack, void *ptr);
33740843Smsmithvoid        stackPushUNS32(FICL_STACK *pStack, UNS32 u);
33840843Smsmithvoid        stackPushINT32(FICL_STACK *pStack, INT32 i);
33940843Smsmithvoid        stackReset (FICL_STACK *pStack);
34040843Smsmithvoid        stackRoll  (FICL_STACK *pStack, int n);
34140843Smsmithvoid        stackSetTop(FICL_STACK *pStack, CELL c);
34240843Smsmithvoid        stackStore (FICL_STACK *pStack, int n, CELL c);
34340843Smsmithvoid        stackUnlink(FICL_STACK *pStack);
34440843Smsmith
34540843Smsmith/*
34640843Smsmith** The virtual machine (VM) contains the state for one interpreter.
34740843Smsmith** Defined operations include:
34840843Smsmith** Create & initialize
34940843Smsmith** Delete
35040843Smsmith** Execute a block of text
35140843Smsmith** Parse a word out of the input stream
35240843Smsmith** Call return, and branch
35340843Smsmith** Text output
35440843Smsmith** Throw an exception
35540843Smsmith*/
35640843Smsmith
35740843Smsmithtypedef struct ficl_word ** IPTYPE; /* the VM's instruction pointer */
35840843Smsmith
35940843Smsmith/*
36040843Smsmith** Each VM has a placeholder for an output function -
36140843Smsmith** this makes it possible to have each VM do I/O
36240843Smsmith** through a different device. If you specify no
36340843Smsmith** OUTFUNC, it defaults to ficlTextOut.
36440843Smsmith*/
36540843Smsmithtypedef void (*OUTFUNC)(struct vm *pVM, char *text, int fNewline);
36640843Smsmith
36740843Smsmith/*
36840843Smsmith** Each VM operates in one of two non-error states: interpreting
36940843Smsmith** or compiling. When interpreting, words are simply executed.
37040843Smsmith** When compiling, most words in the input stream have their
37140843Smsmith** addresses inserted into the word under construction. Some words
37240843Smsmith** (known as IMMEDIATE) are executed in the compile state, too.
37340843Smsmith*/
37440843Smsmith/* values of STATE */
37540843Smsmith#define INTERPRET 0
37640843Smsmith#define COMPILE   1
37740843Smsmith
37840843Smsmith/*
37940843Smsmith** The pad is a small scratch area for text manipulation. ANS Forth
38040843Smsmith** requires it to hold at least 84 characters.
38140843Smsmith*/
38240843Smsmith#if !defined nPAD
38340843Smsmith#define nPAD 256
38440843Smsmith#endif
38540843Smsmith
38640843Smsmith/*
38740843Smsmith** ANS Forth requires that a word's name contain {1..31} characters.
38840843Smsmith*/
38940843Smsmith#if !defined nFICLNAME
39040843Smsmith#define nFICLNAME		31
39140843Smsmith#endif
39240843Smsmith
39340843Smsmith/*
39440843Smsmith** OK - now we can really define the VM...
39540843Smsmith*/
39640843Smsmithtypedef struct vm
39740843Smsmith{
39840843Smsmith    struct vm      *link;       /* Ficl keeps a VM list for simple teardown */
39940843Smsmith    jmp_buf        *pState;     /* crude exception mechanism...     */
40040843Smsmith    OUTFUNC         textOut;    /* Output callback - see sysdep.c   */
40140843Smsmith    void *          pExtend;    /* vm extension pointer             */
40240843Smsmith    short           fRestart;   /* Set TRUE to restart runningWord  */
40340843Smsmith    IPTYPE          ip;         /* instruction pointer              */
40440843Smsmith    struct ficl_word
40540843Smsmith                   *runningWord;/* address of currently running word (often just *(ip-1) ) */
40640843Smsmith    UNS32           state;      /* compiling or interpreting        */
40740843Smsmith    UNS32           base;       /* number conversion base           */
40840843Smsmith    FICL_STACK     *pStack;     /* param stack                      */
40940843Smsmith    FICL_STACK     *rStack;     /* return stack                     */
41040843Smsmith    CELL            sourceID;   /* -1 if string, 0 if normal input  */
41140843Smsmith    TIB             tib;        /* address of incoming text string  */
41240843Smsmith#if FICL_WANT_USER
41340843Smsmith    CELL            user[FICL_USER_CELLS];
41440843Smsmith#endif
41540843Smsmith    char            pad[nPAD];  /* the scratch area (see above)     */
41640843Smsmith} FICL_VM;
41740843Smsmith
41840843Smsmith/*
41940843Smsmith** A FICL_CODE points to a function that gets called to help execute
42040843Smsmith** a word in the dictionary. It always gets passed a pointer to the
42140843Smsmith** running virtual machine, and from there it can get the address
42240843Smsmith** of the parameter area of the word it's supposed to operate on.
42340843Smsmith** For precompiled words, the code is all there is. For user defined
42440843Smsmith** words, the code assumes that the word's parameter area is a list
42540843Smsmith** of pointers to the code fields of other words to execute, and
42640843Smsmith** may also contain inline data. The first parameter is always
42740843Smsmith** a pointer to a code field.
42840843Smsmith*/
42940843Smsmithtypedef void (*FICL_CODE)(FICL_VM *pVm);
43040843Smsmith
43140843Smsmith/*
43240843Smsmith** Ficl models memory as a contiguous space divided into
43340843Smsmith** words in a linked list called the dictionary.
43440843Smsmith** A FICL_WORD starts each entry in the list.
43540843Smsmith** Version 1.02: space for the name characters is allotted from
43640843Smsmith** the dictionary ahead of the word struct - this saves about half
43740843Smsmith** the storage on average with very little runtime cost.
43840843Smsmith*/
43940843Smsmithtypedef struct ficl_word
44040843Smsmith{
44140843Smsmith    struct ficl_word *link;     /* Previous word in the dictionary      */
44240843Smsmith    UNS16 hash;
44340843Smsmith    UNS8 flags;                 /* Immediate, Smudge, Compile-only      */
44440843Smsmith    FICL_COUNT nName;           /* Number of chars in word name         */
44540843Smsmith    char *name;                 /* First nFICLNAME chars of word name   */
44640843Smsmith    FICL_CODE code;             /* Native code to execute the word      */
44740843Smsmith    CELL param[1];              /* First data cell of the word          */
44840843Smsmith} FICL_WORD;
44940843Smsmith
45040843Smsmith/*
45140843Smsmith** Worst-case size of a word header: nFICLNAME chars in name
45240843Smsmith*/
45340843Smsmith#define CELLS_PER_WORD  \
45440843Smsmith    ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \
45540843Smsmith                          / (sizeof (CELL)) )
45640843Smsmith
45740843Smsmithint wordIsImmediate(FICL_WORD *pFW);
45840843Smsmithint wordIsCompileOnly(FICL_WORD *pFW);
45940843Smsmith
46040843Smsmith/* flag values for word header */
46140843Smsmith#define FW_IMMEDIATE    1   /* execute me even if compiling */
46240843Smsmith#define FW_COMPILE      2   /* error if executed when not compiling */
46340843Smsmith#define FW_SMUDGE       4   /* definition in progress - hide me */
46440843Smsmith#define FW_CLASS        8   /* Word defines a class */
46540843Smsmith
46640843Smsmith#define FW_COMPIMMED    (FW_IMMEDIATE | FW_COMPILE)
46740843Smsmith#define FW_DEFAULT      0
46840843Smsmith
46940843Smsmith
47040843Smsmith/*
47140843Smsmith** Exit codes for vmThrow
47240843Smsmith*/
47340843Smsmith#define VM_OUTOFTEXT    1   /* hungry - normal exit */
47440843Smsmith#define VM_RESTART      2   /* word needs more text to suxcceed - re-run it */
47540843Smsmith#define VM_USEREXIT     3   /* user wants to quit */
47640843Smsmith#define VM_ERREXIT      4   /* interp found an error */
47740843Smsmith#define VM_QUIT         5   /* like errexit, but leave pStack & base alone */
47840843Smsmith
47940843Smsmith
48040843Smsmithvoid        vmBranchRelative(FICL_VM *pVM, int offset);
48140843SmsmithFICL_VM *   vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack);
48240843Smsmithvoid        vmDelete (FICL_VM *pVM);
48340843Smsmithvoid        vmExecute(FICL_VM *pVM, FICL_WORD *pWord);
48440843Smsmithchar *      vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter);
48540843SmsmithSTRINGINFO  vmGetWord(FICL_VM *pVM);
48640843SmsmithSTRINGINFO  vmGetWord0(FICL_VM *pVM);
48740843Smsmithint         vmGetWordToPad(FICL_VM *pVM);
48840843SmsmithSTRINGINFO  vmParseString(FICL_VM *pVM, char delimiter);
48940843Smsmithvoid        vmPopIP  (FICL_VM *pVM);
49040843Smsmithvoid        vmPushIP (FICL_VM *pVM, IPTYPE newIP);
49140843Smsmithvoid        vmQuit   (FICL_VM *pVM);
49240843Smsmithvoid        vmReset  (FICL_VM *pVM);
49340843Smsmithvoid        vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut);
49440843Smsmithvoid        vmTextOut(FICL_VM *pVM, char *text, int fNewline);
49540843Smsmithvoid        vmThrow  (FICL_VM *pVM, int except);
49640843Smsmithvoid        vmThrowErr(FICL_VM *pVM, char *fmt, ...);
49740843Smsmith
49840843Smsmith/*
49940843Smsmith** vmCheckStack needs a vm pointer because it might have to say
50040843Smsmith** something if it finds a problem. Parms popCells and pushCells
50140843Smsmith** correspond to the number of parameters on the left and right of
50240843Smsmith** a word's stack effect comment.
50340843Smsmith*/
50440843Smsmithvoid        vmCheckStack(FICL_VM *pVM, int popCells, int pushCells);
50540843Smsmith
50640843Smsmith/*
50740843Smsmith** TIB access routines...
50840843Smsmith** ANS forth seems to require the input buffer to be represented
50940843Smsmith** as a pointer to the start of the buffer, and an index to the
51040843Smsmith** next character to read.
51140843Smsmith** PushTib points the VM to a new input string and optionally
51240843Smsmith**  returns a copy of the current state
51340843Smsmith** PopTib restores the TIB state given a saved TIB from PushTib
51440843Smsmith** GetInBuf returns a pointer to the next unused char of the TIB
51540843Smsmith*/
51640843Smsmithvoid        vmPushTib(FICL_VM *pVM, char *text, TIB *pSaveTib);
51740843Smsmithvoid        vmPopTib(FICL_VM *pVM, TIB *pTib);
51840843Smsmith#define     vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index)
51940843Smsmith#define     vmSetTibIndex(pVM, i) (pVM)->tib.index = i
52040843Smsmith#define     vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp
52140843Smsmith
52240843Smsmith/*
52340843Smsmith** Generally useful string manipulators omitted by ANSI C...
52440843Smsmith** ltoa complements strtol
52540843Smsmith*/
52640843Smsmith#if defined(_WIN32) && !FICL_MAIN
52740843Smsmith/* #SHEESH
52840843Smsmith** Why do Microsoft Meatballs insist on contaminating
52940843Smsmith** my namespace with their string functions???
53040843Smsmith*/
53140843Smsmith#pragma warning(disable: 4273)
53240843Smsmith#endif
53340843Smsmith
53440843Smsmithchar       *ltoa( INT32 value, char *string, int radix );
53540843Smsmithchar       *ultoa(UNS32 value, char *string, int radix );
53640843Smsmithchar        digit_to_char(int value);
53740843Smsmithchar       *strrev( char *string );
53840843Smsmithchar       *skipSpace(char *cp);
53940843Smsmithchar       *caseFold(char *cp);
54040843Smsmithint         strincmp(char *cp1, char *cp2, FICL_COUNT count);
54140843Smsmith
54240843Smsmith#if defined(_WIN32) && !FICL_MAIN
54340843Smsmith#pragma warning(default: 4273)
54440843Smsmith#endif
54540843Smsmith
54640843Smsmith/*
54740843Smsmith** Ficl hash table - variable size.
54840843Smsmith** assert(size > 0)
54940843Smsmith** If size is 1, the table degenerates into a linked list.
55040843Smsmith** A WORDLIST (see the search order word set in DPANS) is
55140843Smsmith** just a pointer to a FICL_HASH in this implementation.
55240843Smsmith*/
55340843Smsmith#if !defined HASHSIZE /* Default size of hash table. For best */
55440843Smsmith#define HASHSIZE 127  /*   performance, use a prime number!   */
55540843Smsmith#endif
55640843Smsmith
55740843Smsmithtypedef struct ficl_hash
55840843Smsmith{
55940843Smsmith    struct ficl_hash *link;  /* eventual inheritance support */
56040843Smsmith    unsigned   size;
56140843Smsmith    FICL_WORD *table[1];
56240843Smsmith} FICL_HASH;
56340843Smsmith
56440843Smsmithvoid        hashForget(FICL_HASH *pHash, void *where);
56540843SmsmithUNS16       hashHashCode(STRINGINFO si);
56640843Smsmithvoid        hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW);
56740843SmsmithFICL_WORD  *hashLookup(struct ficl_hash *pHash,
56840843Smsmith                       STRINGINFO si,
56940843Smsmith                       UNS16 hashCode);
57040843Smsmithvoid        hashReset(FICL_HASH *pHash);
57140843Smsmith
57240843Smsmith/*
57340843Smsmith** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's
57440843Smsmith** memory model. Description of fields:
57540843Smsmith**
57640843Smsmith** here -- points to the next free byte in the dictionary. This
57740843Smsmith**      pointer is forced to be CELL-aligned before a definition is added.
57840843Smsmith**      Do not assume any specific alignment otherwise - Use dictAlign().
57940843Smsmith**
58040843Smsmith** smudge -- pointer to word currently being defined (or last defined word)
58140843Smsmith**      If the definition completes successfully, the word will be
58240843Smsmith**      linked into the hash table. If unsuccessful, dictUnsmudge
58340843Smsmith**      uses this pointer to restore the previous state of the dictionary.
58440843Smsmith**      Smudge prevents unintentional recursion as a side-effect: the
58540843Smsmith**      dictionary search algo examines only completed definitions, so a
58640843Smsmith**      word cannot invoke itself by name. See the ficl word "recurse".
58740843Smsmith**      NOTE: smudge always points to the last word defined. IMMEDIATE
58840843Smsmith**      makes use of this fact. Smudge is initially NULL.
58940843Smsmith**
59040843Smsmith** pForthWords -- pointer to the default wordlist (FICL_HASH).
59140843Smsmith**      This is the initial compilation list, and contains all
59240843Smsmith**      ficl's precompiled words.
59340843Smsmith**
59440843Smsmith** pCompile -- compilation wordlist - initially equal to pForthWords
59540843Smsmith** pSearch  -- array of pointers to wordlists. Managed as a stack.
59640843Smsmith**      Highest index is the first list in the search order.
59740843Smsmith** nLists   -- number of lists in pSearch. nLists-1 is the highest
59840843Smsmith**      filled slot in pSearch, and points to the first wordlist
59940843Smsmith**      in the search order
60040843Smsmith** size -- number of cells in the dictionary (total)
60140843Smsmith** dict -- start of data area. Must be at the end of the struct.
60240843Smsmith*/
60340843Smsmithtypedef struct ficl_dict
60440843Smsmith{
60540843Smsmith    CELL *here;
60640843Smsmith    FICL_WORD *smudge;
60740843Smsmith    FICL_HASH *pForthWords;
60840843Smsmith    FICL_HASH *pCompile;
60940843Smsmith    FICL_HASH *pSearch[FICL_DEFAULT_VOCS];
61040843Smsmith    int        nLists;
61140843Smsmith    unsigned   size;    /* Number of cells in dict (total)*/
61240843Smsmith    CELL       dict[1]; /* Base of dictionary memory      */
61340843Smsmith} FICL_DICT;
61440843Smsmith
61540843Smsmithvoid       *alignPtr(void *ptr);
61640843Smsmithvoid        dictAbortDefinition(FICL_DICT *pDict);
61740843Smsmithvoid        dictAlign(FICL_DICT *pDict);
61840843Smsmithint         dictAllot(FICL_DICT *pDict, int n);
61940843Smsmithint         dictAllotCells(FICL_DICT *pDict, int nCells);
62040843Smsmithvoid        dictAppendCell(FICL_DICT *pDict, CELL c);
62140843Smsmithvoid        dictAppendChar(FICL_DICT *pDict, char c);
62240843SmsmithFICL_WORD  *dictAppendWord(FICL_DICT *pDict,
62340843Smsmith                           char *name,
62440843Smsmith                           FICL_CODE pCode,
62540843Smsmith                           UNS8 flags);
62640843SmsmithFICL_WORD  *dictAppendWord2(FICL_DICT *pDict,
62740843Smsmith                           STRINGINFO si,
62840843Smsmith                           FICL_CODE pCode,
62940843Smsmith                           UNS8 flags);
63040843Smsmithvoid        dictAppendUNS32(FICL_DICT *pDict, UNS32 u);
63140843Smsmithint         dictCellsAvail(FICL_DICT *pDict);
63240843Smsmithint         dictCellsUsed (FICL_DICT *pDict);
63340843Smsmithvoid        dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells);
63440843SmsmithFICL_DICT  *dictCreate(unsigned nCELLS);
63540843SmsmithFICL_DICT  *dictCreateHashed(unsigned nCells, unsigned nHash);
63640843Smsmithvoid        dictDelete(FICL_DICT *pDict);
63740843Smsmithvoid        dictEmpty(FICL_DICT *pDict, unsigned nHash);
63840843Smsmithvoid        dictHashSummary(FICL_VM *pVM);
63940843Smsmithint         dictIncludes(FICL_DICT *pDict, void *p);
64040843SmsmithFICL_WORD  *dictLookup(FICL_DICT *pDict, STRINGINFO si);
64140843Smsmith#if FICL_WANT_LOCALS
64240843SmsmithFICL_WORD  *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si);
64340843Smsmith#endif
64440843Smsmithvoid        dictResetSearchOrder(FICL_DICT *pDict);
64540843Smsmithvoid        dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr);
64640843Smsmithvoid        dictSetImmediate(FICL_DICT *pDict);
64740843Smsmithvoid        dictUnsmudge(FICL_DICT *pDict);
64840843SmsmithCELL       *dictWhere(FICL_DICT *pDict);
64940843Smsmith
65040843Smsmith
65140843Smsmith/*
65240843Smsmith** External interface to FICL...
65340843Smsmith*/
65440843Smsmith/*
65540843Smsmith** f i c l I n i t S y s t e m
65640843Smsmith** Binds a global dictionary to the interpreter system and initializes
65740843Smsmith** the dict to contain the ANSI CORE wordset.
65840843Smsmith** You specify the address and size of the allocated area.
65940843Smsmith** After that, ficl manages it.
66040843Smsmith** First step is to set up the static pointers to the area.
66140843Smsmith** Then write the "precompiled" portion of the dictionary in.
66240843Smsmith** The dictionary needs to be at least large enough to hold the
66340843Smsmith** precompiled part. Try 1K cells minimum. Use "words" to find
66440843Smsmith** out how much of the dictionary is used at any time.
66540843Smsmith*/
66640843Smsmithvoid       ficlInitSystem(int nDictCells);
66740843Smsmith
66840843Smsmith/*
66940843Smsmith** f i c l T e r m S y s t e m
67040843Smsmith** Deletes the system dictionary and all virtual machines that
67140843Smsmith** were created with ficlNewVM (see below). Call this function to
67240843Smsmith** reclaim all memory used by the dictionary and VMs.
67340843Smsmith*/
67440843Smsmithvoid       ficlTermSystem(void);
67540843Smsmith
67640843Smsmith/*
67740843Smsmith** f i c l E x e c
67840843Smsmith** Evaluates a block of input text in the context of the
67940843Smsmith** specified interpreter. Emits any requested output to the
68040843Smsmith** interpreter's output function
68140843Smsmith** Execution returns when the text block has been executed,
68240843Smsmith** or an error occurs.
68340843Smsmith** Returns one of the VM_XXXX codes defined in ficl.h:
68440843Smsmith** VM_OUTOFTEXT is the normal exit condition
68540843Smsmith** VM_ERREXIT means that the interp encountered a syntax error
68640843Smsmith**      and the vm has been reset to recover (some or all
68740843Smsmith**      of the text block got ignored
68840843Smsmith** VM_USEREXIT means that the user executed the "bye" command
68940843Smsmith**      to shut down the interpreter. This would be a good
69040843Smsmith**      time to delete the vm, etc -- or you can ignore this
69140843Smsmith**      signal.
69240843Smsmith** Preconditions: successful execution of ficlInitSystem,
69340843Smsmith**      Successful creation and init of the VM by ficlNewVM (or equiv)
69440843Smsmith*/
69540843Smsmithint        ficlExec(FICL_VM *pVM, char *pText);
69640843Smsmith
69740843Smsmith/*
69840989Sjkh** ficlExecFD(FICL_VM *pVM, int fd);
69940989Sjkh * Evaluates text from file passed in via fd.
70040989Sjkh * Execution returns when all of file has been executed or an
70140989Sjkh * error occurs.
70240989Sjkh */
70340989Sjkhint        ficlExecFD(FICL_VM *pVM, int fd);
70440989Sjkh
70540989Sjkh/*
70640843Smsmith** Create a new VM from the heap, and link it into the system VM list.
70740843Smsmith** Initializes the VM and binds default sized stacks to it. Returns the
70840843Smsmith** address of the VM, or NULL if an error occurs.
70940843Smsmith** Precondition: successful execution of ficlInitSystem
71040843Smsmith*/
71140843SmsmithFICL_VM   *ficlNewVM(void);
71240843Smsmith
71340843Smsmith/*
71440843Smsmith** Returns the address of the most recently defined word in the system
71540843Smsmith** dictionary with the given name, or NULL if no match.
71640843Smsmith** Precondition: successful execution of ficlInitSystem
71740843Smsmith*/
71840843SmsmithFICL_WORD *ficlLookup(char *name);
71940843Smsmith
72040843Smsmith/*
72140843Smsmith** f i c l G e t D i c t
72240843Smsmith** Utility function - returns the address of the system dictionary.
72340843Smsmith** Precondition: successful execution of ficlInitSystem
72440843Smsmith*/
72540843SmsmithFICL_DICT *ficlGetDict(void);
72640843SmsmithFICL_DICT *ficlGetEnv(void);
72740843Smsmithvoid       ficlSetEnv(char *name, UNS32 value);
72840843Smsmithvoid       ficlSetEnvD(char *name, UNS32 hi, UNS32 lo);
72940843Smsmith#if FICL_WANT_LOCALS
73040843SmsmithFICL_DICT *ficlGetLoc(void);
73140843Smsmith#endif
73240843Smsmith/*
73340843Smsmith** f i c l B u i l d
73440843Smsmith** Builds a word into the system default dictionary in a thread-safe way.
73540843Smsmith** Preconditions: system must be initialized, and there must
73640843Smsmith** be enough space for the new word's header! Operation is
73740843Smsmith** controlled by ficlLockDictionary, so any initialization
73840843Smsmith** required by your version of the function (if you "overrode"
73940843Smsmith** it) must be complete at this point.
74040843Smsmith** Parameters:
74140843Smsmith** name  -- the name of the word to be built
74240843Smsmith** code  -- code to execute when the word is invoked - must take a single param
74340843Smsmith**          pointer to a FICL_VM
74440843Smsmith** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR!
74540843Smsmith**          Most words can use FW_DEFAULT.
74640843Smsmith** nAllot - number of extra cells to allocate in the parameter area (usually zero)
74740843Smsmith*/
74840843Smsmithint        ficlBuild(char *name, FICL_CODE code, char flags);
74940843Smsmith
75040843Smsmith/*
75140843Smsmith** f i c l C o m p i l e C o r e
75240843Smsmith** Builds the ANS CORE wordset into the dictionary - called by
75340843Smsmith** ficlInitSystem - no need to waste dict space by doing it again.
75440843Smsmith*/
75540843Smsmithvoid       ficlCompileCore(FICL_DICT *dp);
75640843Smsmithvoid       ficlCompileSoftCore(FICL_VM *pVM);
75740843Smsmith
75840843Smsmith/*
75940843Smsmith** from words.c...
76040843Smsmith*/
76140843Smsmithvoid       constantParen(FICL_VM *pVM);
76240843Smsmithvoid       twoConstParen(FICL_VM *pVM);
76340843Smsmith
76442634Sabial#ifdef __i386__
76542634Sabialextern void pc_fetch(FICL_VM *pVM);
76642634Sabialextern void pc_store(FICL_VM *pVM);
76742634Sabial#endif
76842634Sabial
76940843Smsmith#ifdef __cplusplus
77040843Smsmith}
77140843Smsmith#endif
77240843Smsmith
77340843Smsmith#endif /* __FICL_H__ */
774