ficl.h revision 40977
11553Srgrimes/*******************************************************************
21553Srgrimes** f i c l . h
31553Srgrimes** Forth Inspired Command Language
41553Srgrimes** Author: John Sadler (john_sadler@alum.mit.edu)
51553Srgrimes** Created: 19 July 1997
61553Srgrimes**
71553Srgrimes*******************************************************************/
81553Srgrimes/*
91553Srgrimes** N O T I C E -- DISCLAIMER OF WARRANTY
101553Srgrimes**
111553Srgrimes** Ficl is freeware. Use it in any way that you like, with
121553Srgrimes** the understanding that the code is supported on a "best effort"
131553Srgrimes** basis only.
141553Srgrimes**
151553Srgrimes** Any third party may reproduce, distribute, or modify the ficl
161553Srgrimes** software code or any derivative  works thereof without any
171553Srgrimes** compensation or license, provided that the author information
181553Srgrimes** and this disclaimer text are retained in the source code files.
191553Srgrimes** The ficl software code is provided on an "as is"  basis without
201553Srgrimes** warranty of any kind, including, without limitation, the implied
211553Srgrimes** warranties of merchantability and fitness for a particular purpose
221553Srgrimes** and their equivalents under the laws of any jurisdiction.
231553Srgrimes**
241553Srgrimes** I am interested in hearing from anyone who uses ficl. If you have
251553Srgrimes** a problem, a success story, a defect, an enhancement request, or
261553Srgrimes** if you would like to contribute to the ficl release (yay!), please
271553Srgrimes** send me email at the address above.
281553Srgrimes*/
291553Srgrimes
30114601Sobrien#if !defined (__FICL_H__)
311553Srgrimes#define __FICL_H__
3230643Scharnier/*
331553Srgrimes** Ficl (Forth-inspired command language) is an ANS Forth
341553Srgrimes** interpreter written in C. Unlike traditional Forths, this
351553Srgrimes** interpreter is designed to be embedded into other systems
361553Srgrimes** as a command/macro/development prototype language.
371553Srgrimes**
381553Srgrimes** Where Forths usually view themselves as the center of the system
39114601Sobrien** and expect the rest of the system to be coded in Forth, Ficl
4030643Scharnier** acts as a component of the system. It is easy to export
41114601Sobrien** code written in C or ASM to Ficl in the style of TCL, or to invoke
42114601Sobrien** Ficl code from a compiled module. This allows you to do incremental
431553Srgrimes** development in a way that combines the best features of threaded
441553Srgrimes** languages (rapid development, quick code/test/debug cycle,
4514544Sdg** reasonably fast) with the best features of C (everyone knows it,
461553Srgrimes** easier to support large blocks of code, efficient, type checking).
471553Srgrimes**
481553Srgrimes** Ficl provides facilities for interoperating
491553Srgrimes** with programs written in C: C functions can be exported to Ficl,
501553Srgrimes** and Ficl commands can be executed via a C calling interface. The
5120287Swollman** interpreter is re-entrant, so it can be used in multiple instances
521553Srgrimes** in a multitasking system. Unlike Forth, Ficl's outer interpreter
531553Srgrimes** expects a text block as input, and returns to the caller after each
541553Srgrimes** text block, so the "data pump" is somewhere in external code. This
551553Srgrimes** is more like TCL than Forth, which usually expcets to be at the center
561553Srgrimes** of the system, requesting input at its convenience. Each Ficl virtual
571553Srgrimes** machine can be bound to a different I/O channel, and is independent
581553Srgrimes** of all others in in the same address space except that all virtual
5955679Sshin** machines share a common dictionary (a sort or open symbol table that
6055679Sshin** defines all of the elements of the language).
6155679Sshin**
621553Srgrimes** Code is written in ANSI C for portability.
631553Srgrimes**
641553Srgrimes** Summary of Ficl features and constraints:
651553Srgrimes** - Standard: Implements the ANSI Forth CORE word set and part
661553Srgrimes**   of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and
671553Srgrimes**   TOOLS EXT, LOCAL and LOCAL ext and various extras.
681553Srgrimes** - Extensible: you can export code written in Forth, C,
691553Srgrimes**   or asm in a straightforward way. Ficl provides open
701553Srgrimes**   facilities for extending the language in an application
711553Srgrimes**   specific way. You can even add new control structures!
721553Srgrimes** - Ficl and C can interact in two ways: Ficl can encapsulate
731553Srgrimes**   C code, or C code can invoke Ficl code.
741553Srgrimes** - Thread-safe, re-entrant: The shared system dictionary
751553Srgrimes**   uses a locking mechanism that you can either supply
7630643Scharnier**   or stub out to provide exclusive access. Each Ficl
771553Srgrimes**   virtual machine has an otherwise complete state, and
781553Srgrimes**   each can be bound to a separate I/O channel (or none at all).
7930643Scharnier** - Simple encapsulation into existing systems: a basic implementation
8030643Scharnier**   requires three function calls (see the example program in testmain.c).
81100114Salfred** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data
8230643Scharnier**   environments. It does require somewhat more memory than a pure
831553Srgrimes**   ROM implementation because it builds its system dictionary in
84100114Salfred**   RAM at startup time.
851553Srgrimes** - Written an ANSI C to be as simple as I can make it to understand,
861553Srgrimes**   support, debug, and port. Compiles without complaint at /Az /W4
871553Srgrimes**   (require ANSI C, max warnings) under Microsoft VC++ 5.
881553Srgrimes** - Does full 32 bit math (but you need to implement
891553Srgrimes**   two mixed precision math primitives (see sysdep.c))
901553Srgrimes** - Indirect threaded interpreter is not the fastest kind of
911553Srgrimes**   Forth there is (see pForth 68K for a really fast subroutine
92100114Salfred**   threaded interpreter), but it's the cleanest match to a
93100114Salfred**   pure C implementation.
94100114Salfred**
95100114Salfred** P O R T I N G   F i c l
96100114Salfred**
9730643Scharnier** To install Ficl on your target system, you need an ANSI C compiler
9830643Scharnier** and its runtime library. Inspect the system dependent macros and
99100114Salfred** functions in sysdep.h and sysdep.c and edit them to suit your
1001553Srgrimes** system. For example, INT16 is a short on some compilers and an
10130643Scharnier** int on others. Check the default CELL alignment controlled by
102100114Salfred** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree,
1031553Srgrimes** ficlLockDictionary, and ficlTextOut to work with your operating system.
104100114Salfred** Finally, use testmain.c as a guide to installing the Ficl system and
105100114Salfred** one or more virtual machines into your code. You do not need to include
106100114Salfred** testmain.c in your build.
1071553Srgrimes**
10824428Simp** T o   D o   L i s t
1091553Srgrimes**
1101553Srgrimes** 1. Unimplemented system dependent CORE word: key
1111553Srgrimes** 2. Kludged CORE word: ACCEPT
1121553Srgrimes** 3. Dictionary locking is full of holes - only one vm at a time
1131553Srgrimes**    can alter the dict.
1141553Srgrimes** 4. Ficl uses the pad in CORE words - this violates the standard,
1151553Srgrimes**    but it's cleaner for a multithreaded system. I'll have to make a
1161553Srgrimes**    second pad for reference by the word PAD to fix this.
1171553Srgrimes**
1181553Srgrimes** F o r   M o r e   I n f o r m a t i o n
1191553Srgrimes**
1201553Srgrimes** Web home of ficl
12130643Scharnier**   http://www.taygeta.com/forth/compilers
12230643Scharnier** Check this website for Forth literature (including the ANSI standard)
1231553Srgrimes**   http://www.taygeta.com/forthlit.html
1241553Srgrimes** and here for software and more links
1251553Srgrimes**   http://www.taygeta.com/forth.html
1261553Srgrimes**
1271553Srgrimes** Obvious Performance enhancement opportunities
1281553Srgrimes** Compile speed
1291553Srgrimes** - work on interpret speed
1301553Srgrimes** - turn off locals (FICL_WANT_LOCALS)
1311553Srgrimes** Interpret speed
1321553Srgrimes** - Change inner interpreter (and everything else)
13330643Scharnier**   so that a definition is a list of pointers to functions
1341553Srgrimes**   and inline data rather than pointers to words. This gets
1351553Srgrimes**   rid of vm->runningWord and a level of indirection in the
1361553Srgrimes**   inner loop. I'll look at it for ficl 3.0
1371553Srgrimes** - Make the main hash table a bigger prime (HASHSIZE)
1381553Srgrimes** - FORGET about twiddling the hash function - my experience is
1391553Srgrimes**   that that is a waste of time.
140100114Salfred** - eliminate the need to pass the pVM parameter on the stack
1411553Srgrimes**   by dedicating a register to it. Most words need access to the
1421553Srgrimes**   vm, but the parameter passing overhead can be reduced. One way
1431553Srgrimes**   requires that the host OS have a task switch callout. Create
1441553Srgrimes**   a global variable for the running VM and refer to it in words
1451553Srgrimes**   that need VM access. Alternative: use thread local storage.
1461553Srgrimes**   For single threaded implementations, you can just use a global.
1471553Srgrimes**   The first two solutions create portability problems, so I
1481553Srgrimes**   haven't considered doing them. Another possibility is to
1491553Srgrimes**   declare the pVm parameter to be "register", and hope the compiler
1501553Srgrimes**   pays attention.
1511553Srgrimes**
1521553Srgrimes*/
1531553Srgrimes
154100114Salfred/*
1551553Srgrimes** Revision History:
156100114Salfred** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT,
157100114Salfred**  SEARCH / SEARCH EXT, TOOLS / TOOLS EXT.
15830643Scharnier**  Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD,
15930643Scharnier**  EMPTY to clear stack.
16082664Sru**
16130643Scharnier** 29 jun 1998 (sadler) added variable sized hash table support
16230643Scharnier**  and ANS Forth optional SEARCH & SEARCH EXT word set.
1631553Srgrimes** 26 May 1998 (sadler)
1641553Srgrimes**  FICL_PROMPT macro
16530643Scharnier** 14 April 1998 (sadler) V1.04
16630643Scharnier**  Ficlwin: Windows version, Skip Carter's Linux port
1671553Srgrimes** 5 March 1998 (sadler) V1.03
1681553Srgrimes**  Bug fixes -- passes John Ryan's ANS test suite "core.fr"
16930643Scharnier**
17030643Scharnier** 24 February 1998 (sadler) V1.02
1711553Srgrimes** -Fixed bugs in <# # #>
1721553Srgrimes** -Changed FICL_WORD so that storage for the name characters
1731553Srgrimes**  can be allocated from the dictionary as needed rather than
1741553Srgrimes**  reserving 32 bytes in each word whether needed or not -
1751553Srgrimes**  this saved 50% of the dictionary storage requirement.
1761553Srgrimes** -Added words in testmain for Win32 functions system,chdir,cwd,
1771553Srgrimes**  also added a word that loads and evaluates a file.
1781553Srgrimes**
1791553Srgrimes** December 1997 (sadler)
1801553Srgrimes** -Added VM_RESTART exception handling in ficlExec -- this lets words
1811553Srgrimes**  that require additional text to succeed (like :, create, variable...)
1821553Srgrimes**  recover gracefully from an empty input buffer rather than emitting
1831553Srgrimes**  an error message. Definitions can span multiple input blocks with
1841553Srgrimes**  no restrictions.
1851553Srgrimes** -Changed #include order so that <assert.h> is included in sysdep.h,
1861553Srgrimes**  and sysdep is included in all other files. This lets you define
1871553Srgrimes**  NDEBUG in sysdep.h to disable assertions if you want to.
1881553Srgrimes** -Make PC specific system dependent code conditional on _M_IX86
1891553Srgrimes**  defined so that ports can coexist in sysdep.h/sysdep.c
1901553Srgrimes*/
1911553Srgrimes
1921553Srgrimes#ifdef __cplusplus
1931553Srgrimesextern "C" {
1941553Srgrimes#endif
1951553Srgrimes
196100114Salfred#include "sysdep.h"
1971553Srgrimes#include <limits.h> /* UCHAR_MAX */
1981553Srgrimes
1991553Srgrimes/*
2001553Srgrimes** Forward declarations... read on.
2011553Srgrimes*/
2021553Srgrimesstruct ficl_word;
2031553Srgrimesstruct vm;
204100165Sdesstruct ficl_dict;
2051553Srgrimes
2061553Srgrimes/*
2071553Srgrimes** the Good Stuff starts here...
2081553Srgrimes*/
2091553Srgrimes#define FICL_VER   "2.02"
21030643Scharnier#ifndef FICL_PROMPT
21130643Scharnier# define FICL_PROMPT "ok> "
21230643Scharnier#endif
21330643Scharnier
21430643Scharnier/*
21530643Scharnier** ANS Forth requires false to be zero, and true to be the ones
21630643Scharnier** complement of false... that unifies logical and bitwise operations
21730643Scharnier** nicely.
21830643Scharnier*/
2191553Srgrimes#define FICL_TRUE  (0xffffffffL)
2201553Srgrimes#define FICL_FALSE (0)
2211553Srgrimes#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE)
2221553Srgrimes
2231553Srgrimes
22456801Sshin/*
2251553Srgrimes** A CELL is the main storage type. It must be large enough
2261553Srgrimes** to contain a pointer or a scalar. Let's be picky and make
2271553Srgrimes** a 32 bit cell explicitly...
2281553Srgrimes*/
2291553Srgrimestypedef union _cell
2301553Srgrimes{
2311553Srgrimes	INT32 i;
2321553Srgrimes    UNS32 u;
23356801Sshin	void *p;
23456801Sshin} CELL;
23556801Sshin
23656801Sshin/*
23756801Sshin** LVALUEtoCELL does a little pointer trickery to cast any 32 bit
23856801Sshin** lvalue (informal definition: an expression whose result has an
23956801Sshin** address) to CELL. Remember that constants and casts are NOT
24056801Sshin** themselves lvalues!
24156801Sshin*/
24256801Sshin#define LVALUEtoCELL(v) (*(CELL *)&v)
24356801Sshin
24456801Sshin/*
24556801Sshin** PTRtoCELL is a cast through void * intended to satisfy the
24656801Sshin** most outrageously pedantic compiler... (I won't mention
24756801Sshin** its name)
24856801Sshin*/
24956801Sshin#define PTRtoCELL (CELL *)(void *)
25056801Sshin#define PTRtoSTRING (FICL_STRING *)(void *)
25156801Sshin
2521553Srgrimes/*
2531553Srgrimes** Strings in FICL are stored in Pascal style - with a count
2541553Srgrimes** preceding the text. We'll also NULL-terminate them so that
2551553Srgrimes** they work with the usual C lib string functions. (Belt &
2561553Srgrimes** suspenders? You decide.)
2571553Srgrimes** STRINGINFO hides the implementation with a couple of
2581553Srgrimes** macros for use in internal routines.
2591553Srgrimes*/
26056801Sshin
26156801Sshintypedef unsigned char FICL_COUNT;
26256801Sshin#define FICL_STRING_MAX UCHAR_MAX
26356801Sshintypedef struct _ficl_string
26456801Sshin{
26556801Sshin    FICL_COUNT count;
26656801Sshin    char text[1];
26756801Sshin} FICL_STRING;
26856801Sshin
26956801Sshintypedef struct
27056801Sshin{
27156801Sshin    UNS32 count;
27256801Sshin    char *cp;
27356801Sshin} STRINGINFO;
27456801Sshin
27556801Sshin#define SI_COUNT(si) (si.count)
27656801Sshin#define SI_PTR(si)   (si.cp)
27756801Sshin#define SI_SETLEN(si, len) (si.count = (UNS32)(len))
27856801Sshin#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr))
2791553Srgrimes/*
2801553Srgrimes** Init a STRINGINFO from a pointer to NULL-terminated string
2811553Srgrimes*/
2821553Srgrimes#define SI_PSZ(si, psz) \
2831553Srgrimes            {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);}
2841553Srgrimes/*
2851553Srgrimes** Init a STRINGINFO from a pointer to FICL_STRING
2861553Srgrimes*/
2871553Srgrimes#define SI_PFS(si, pfs) \
28830643Scharnier            {si.cp = pfs->text; si.count = pfs->count;}
28930643Scharnier
2901553Srgrimes/*
2911553Srgrimes** Ficl uses a this little structure to hold the address of
2921553Srgrimes** the block of text it's working on and an index to the next
29330643Scharnier** unconsumed character in the string. Traditionally, this is
29430643Scharnier** done by a Text Input Buffer, so I've called this struct TIB.
2951553Srgrimes*/
2961553Srgrimestypedef struct
2971553Srgrimes{
2981553Srgrimes    INT32 index;
2991553Srgrimes    char *cp;
3001553Srgrimes} TIB;
3011553Srgrimes
3021553Srgrimes
30330643Scharnier/*
304189090Sed** Stacks get heavy use in Ficl and Forth...
305189090Sed** Each virtual machine implements two of them:
3061553Srgrimes** one holds parameters (data), and the other holds return
3071553Srgrimes** addresses and control flow information for the virtual
3081553Srgrimes** machine. (Note: C's automatic stack is implicitly used,
30955679Sshin** but not modeled because it doesn't need to be...)
31055679Sshin** Here's an abstract type for a stack
31155679Sshin*/
31255679Sshintypedef struct _ficlStack
31355679Sshin{
31455679Sshin    UNS32 nCells;       /* size of the stack */
3151553Srgrimes    CELL *pFrame;       /* link reg for stack frame */
31655679Sshin    CELL *sp;           /* stack pointer */
31756801Sshin    CELL base[1];       /* Bottom of the stack */
31856801Sshin} FICL_STACK;
31955679Sshin
32056801Sshin/*
32155679Sshin** Stack methods... many map closely to required Forth words.
32255679Sshin*/
32356801SshinFICL_STACK *stackCreate(unsigned nCells);
32455679Sshinvoid        stackDelete(FICL_STACK *pStack);
32555679Sshinint         stackDepth (FICL_STACK *pStack);
32655679Sshinvoid        stackDrop  (FICL_STACK *pStack, int n);
32755679SshinCELL        stackFetch (FICL_STACK *pStack, int n);
32855679SshinCELL        stackGetTop(FICL_STACK *pStack);
32955679Sshinvoid        stackLink  (FICL_STACK *pStack, int nCells);
33055679Sshinvoid        stackPick  (FICL_STACK *pStack, int n);
33155679SshinCELL        stackPop   (FICL_STACK *pStack);
33255679Sshinvoid       *stackPopPtr   (FICL_STACK *pStack);
33355679SshinUNS32       stackPopUNS32 (FICL_STACK *pStack);
334100114SalfredINT32       stackPopINT32 (FICL_STACK *pStack);
3351553Srgrimesvoid        stackPush  (FICL_STACK *pStack, CELL c);
3361553Srgrimesvoid        stackPushPtr  (FICL_STACK *pStack, void *ptr);
3371553Srgrimesvoid        stackPushUNS32(FICL_STACK *pStack, UNS32 u);
3381553Srgrimesvoid        stackPushINT32(FICL_STACK *pStack, INT32 i);
3391553Srgrimesvoid        stackReset (FICL_STACK *pStack);
34055679Sshinvoid        stackRoll  (FICL_STACK *pStack, int n);
34155679Sshinvoid        stackSetTop(FICL_STACK *pStack, CELL c);
34255679Sshinvoid        stackStore (FICL_STACK *pStack, int n, CELL c);
34355679Sshinvoid        stackUnlink(FICL_STACK *pStack);
3441553Srgrimes
3451553Srgrimes/*
34655679Sshin** The virtual machine (VM) contains the state for one interpreter.
34755679Sshin** Defined operations include:
34855679Sshin** Create & initialize
34955679Sshin** Delete
35055679Sshin** Execute a block of text
35155679Sshin** Parse a word out of the input stream
35255679Sshin** Call return, and branch
35355679Sshin** Text output
3541553Srgrimes** Throw an exception
35555679Sshin*/
35655679Sshin
35755679Sshintypedef struct ficl_word ** IPTYPE; /* the VM's instruction pointer */
35855679Sshin
35955679Sshin/*
36055679Sshin** Each VM has a placeholder for an output function -
36155679Sshin** this makes it possible to have each VM do I/O
3621553Srgrimes** through a different device. If you specify no
36355679Sshin** OUTFUNC, it defaults to ficlTextOut.
36455679Sshin*/
36555679Sshintypedef void (*OUTFUNC)(struct vm *pVM, char *text, int fNewline);
36655679Sshin
36755679Sshin/*
36855679Sshin** Each VM operates in one of two non-error states: interpreting
36955679Sshin** or compiling. When interpreting, words are simply executed.
37055679Sshin** When compiling, most words in the input stream have their
37155679Sshin** addresses inserted into the word under construction. Some words
3721553Srgrimes** (known as IMMEDIATE) are executed in the compile state, too.
3731553Srgrimes*/
3741553Srgrimes/* values of STATE */
3751553Srgrimes#define INTERPRET 0
3761553Srgrimes#define COMPILE   1
3771553Srgrimes
3781553Srgrimes/*
3791553Srgrimes** The pad is a small scratch area for text manipulation. ANS Forth
3801553Srgrimes** requires it to hold at least 84 characters.
381100114Salfred*/
3821553Srgrimes#if !defined nPAD
383100114Salfred#define nPAD 256
384100114Salfred#endif
3851553Srgrimes
3861553Srgrimes/*
38755679Sshin** ANS Forth requires that a word's name contain {1..31} characters.
3881553Srgrimes*/
389100114Salfred#if !defined nFICLNAME
3901553Srgrimes#define nFICLNAME		31
39155679Sshin#endif
3921553Srgrimes
3931553Srgrimes/*
3941553Srgrimes** OK - now we can really define the VM...
3951553Srgrimes*/
3961553Srgrimestypedef struct vm
3971553Srgrimes{
3981553Srgrimes    struct vm      *link;       /* Ficl keeps a VM list for simple teardown */
3991553Srgrimes    jmp_buf        *pState;     /* crude exception mechanism...     */
4001553Srgrimes    OUTFUNC         textOut;    /* Output callback - see sysdep.c   */
4011553Srgrimes    void *          pExtend;    /* vm extension pointer             */
4021553Srgrimes    short           fRestart;   /* Set TRUE to restart runningWord  */
4031553Srgrimes    IPTYPE          ip;         /* instruction pointer              */
4041553Srgrimes    struct ficl_word
4051553Srgrimes                   *runningWord;/* address of currently running word (often just *(ip-1) ) */
4061553Srgrimes    UNS32           state;      /* compiling or interpreting        */
4071553Srgrimes    UNS32           base;       /* number conversion base           */
4081553Srgrimes    FICL_STACK     *pStack;     /* param stack                      */
4091553Srgrimes    FICL_STACK     *rStack;     /* return stack                     */
4101553Srgrimes    CELL            sourceID;   /* -1 if string, 0 if normal input  */
4111553Srgrimes    TIB             tib;        /* address of incoming text string  */
4121553Srgrimes#if FICL_WANT_USER
4131553Srgrimes    CELL            user[FICL_USER_CELLS];
4141553Srgrimes#endif
4151553Srgrimes    char            pad[nPAD];  /* the scratch area (see above)     */
4161553Srgrimes} FICL_VM;
417100114Salfred
418100114Salfred/*
419100114Salfred** A FICL_CODE points to a function that gets called to help execute
420100114Salfred** a word in the dictionary. It always gets passed a pointer to the
421100114Salfred** running virtual machine, and from there it can get the address
422100114Salfred** of the parameter area of the word it's supposed to operate on.
423100114Salfred** For precompiled words, the code is all there is. For user defined
4241553Srgrimes** words, the code assumes that the word's parameter area is a list
4251553Srgrimes** of pointers to the code fields of other words to execute, and
42650680Sjlemon** may also contain inline data. The first parameter is always
42750680Sjlemon** a pointer to a code field.
42850680Sjlemon*/
42950680Sjlemontypedef void (*FICL_CODE)(FICL_VM *pVm);
43050680Sjlemon
4311553Srgrimes/*
4321553Srgrimes** Ficl models memory as a contiguous space divided into
4331553Srgrimes** words in a linked list called the dictionary.
4341553Srgrimes** A FICL_WORD starts each entry in the list.
4351553Srgrimes** Version 1.02: space for the name characters is allotted from
4361553Srgrimes** the dictionary ahead of the word struct - this saves about half
4371553Srgrimes** the storage on average with very little runtime cost.
4381553Srgrimes*/
4391553Srgrimestypedef struct ficl_word
4401553Srgrimes{
4411553Srgrimes    struct ficl_word *link;     /* Previous word in the dictionary      */
4421553Srgrimes    UNS16 hash;
4431553Srgrimes    UNS8 flags;                 /* Immediate, Smudge, Compile-only      */
4441553Srgrimes    FICL_COUNT nName;           /* Number of chars in word name         */
4451553Srgrimes    char *name;                 /* First nFICLNAME chars of word name   */
44650680Sjlemon    FICL_CODE code;             /* Native code to execute the word      */
4471553Srgrimes    CELL param[1];              /* First data cell of the word          */
4481553Srgrimes} FICL_WORD;
44930643Scharnier
45073732Sdwmalone/*
45173732Sdwmalone** Worst-case size of a word header: nFICLNAME chars in name
4521553Srgrimes*/
45373732Sdwmalone#define CELLS_PER_WORD  \
4541553Srgrimes    ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \
4551553Srgrimes                          / (sizeof (CELL)) )
4561553Srgrimes
45730643Scharnierint wordIsImmediate(FICL_WORD *pFW);
4581553Srgrimesint wordIsCompileOnly(FICL_WORD *pFW);
4591553Srgrimes
4601553Srgrimes/* flag values for word header */
4611553Srgrimes#define FW_IMMEDIATE    1   /* execute me even if compiling */
4621553Srgrimes#define FW_COMPILE      2   /* error if executed when not compiling */
4631553Srgrimes#define FW_SMUDGE       4   /* definition in progress - hide me */
464#define FW_CLASS        8   /* Word defines a class */
465
466#define FW_COMPIMMED    (FW_IMMEDIATE | FW_COMPILE)
467#define FW_DEFAULT      0
468
469
470/*
471** Exit codes for vmThrow
472*/
473#define VM_OUTOFTEXT    1   /* hungry - normal exit */
474#define VM_RESTART      2   /* word needs more text to suxcceed - re-run it */
475#define VM_USEREXIT     3   /* user wants to quit */
476#define VM_ERREXIT      4   /* interp found an error */
477#define VM_QUIT         5   /* like errexit, but leave pStack & base alone */
478
479
480void        vmBranchRelative(FICL_VM *pVM, int offset);
481FICL_VM *   vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack);
482void        vmDelete (FICL_VM *pVM);
483void        vmExecute(FICL_VM *pVM, FICL_WORD *pWord);
484char *      vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter);
485STRINGINFO  vmGetWord(FICL_VM *pVM);
486STRINGINFO  vmGetWord0(FICL_VM *pVM);
487int         vmGetWordToPad(FICL_VM *pVM);
488STRINGINFO  vmParseString(FICL_VM *pVM, char delimiter);
489void        vmPopIP  (FICL_VM *pVM);
490void        vmPushIP (FICL_VM *pVM, IPTYPE newIP);
491void        vmQuit   (FICL_VM *pVM);
492void        vmReset  (FICL_VM *pVM);
493void        vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut);
494void        vmTextOut(FICL_VM *pVM, char *text, int fNewline);
495void        vmThrow  (FICL_VM *pVM, int except);
496void        vmThrowErr(FICL_VM *pVM, char *fmt, ...);
497
498/*
499** vmCheckStack needs a vm pointer because it might have to say
500** something if it finds a problem. Parms popCells and pushCells
501** correspond to the number of parameters on the left and right of
502** a word's stack effect comment.
503*/
504void        vmCheckStack(FICL_VM *pVM, int popCells, int pushCells);
505
506/*
507** TIB access routines...
508** ANS forth seems to require the input buffer to be represented
509** as a pointer to the start of the buffer, and an index to the
510** next character to read.
511** PushTib points the VM to a new input string and optionally
512**  returns a copy of the current state
513** PopTib restores the TIB state given a saved TIB from PushTib
514** GetInBuf returns a pointer to the next unused char of the TIB
515*/
516void        vmPushTib(FICL_VM *pVM, char *text, TIB *pSaveTib);
517void        vmPopTib(FICL_VM *pVM, TIB *pTib);
518#define     vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index)
519#define     vmSetTibIndex(pVM, i) (pVM)->tib.index = i
520#define     vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp
521
522/*
523** Generally useful string manipulators omitted by ANSI C...
524** ltoa complements strtol
525*/
526#if defined(_WIN32) && !FICL_MAIN
527/* #SHEESH
528** Why do Microsoft Meatballs insist on contaminating
529** my namespace with their string functions???
530*/
531#pragma warning(disable: 4273)
532#endif
533
534char       *ltoa( INT32 value, char *string, int radix );
535char       *ultoa(UNS32 value, char *string, int radix );
536char        digit_to_char(int value);
537char       *strrev( char *string );
538char       *skipSpace(char *cp);
539char       *caseFold(char *cp);
540int         strincmp(char *cp1, char *cp2, FICL_COUNT count);
541
542#if defined(_WIN32) && !FICL_MAIN
543#pragma warning(default: 4273)
544#endif
545
546/*
547** Ficl hash table - variable size.
548** assert(size > 0)
549** If size is 1, the table degenerates into a linked list.
550** A WORDLIST (see the search order word set in DPANS) is
551** just a pointer to a FICL_HASH in this implementation.
552*/
553#if !defined HASHSIZE /* Default size of hash table. For best */
554#define HASHSIZE 127  /*   performance, use a prime number!   */
555#endif
556
557typedef struct ficl_hash
558{
559    struct ficl_hash *link;  /* eventual inheritance support */
560    unsigned   size;
561    FICL_WORD *table[1];
562} FICL_HASH;
563
564void        hashForget(FICL_HASH *pHash, void *where);
565UNS16       hashHashCode(STRINGINFO si);
566void        hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW);
567FICL_WORD  *hashLookup(struct ficl_hash *pHash,
568                       STRINGINFO si,
569                       UNS16 hashCode);
570void        hashReset(FICL_HASH *pHash);
571
572/*
573** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's
574** memory model. Description of fields:
575**
576** here -- points to the next free byte in the dictionary. This
577**      pointer is forced to be CELL-aligned before a definition is added.
578**      Do not assume any specific alignment otherwise - Use dictAlign().
579**
580** smudge -- pointer to word currently being defined (or last defined word)
581**      If the definition completes successfully, the word will be
582**      linked into the hash table. If unsuccessful, dictUnsmudge
583**      uses this pointer to restore the previous state of the dictionary.
584**      Smudge prevents unintentional recursion as a side-effect: the
585**      dictionary search algo examines only completed definitions, so a
586**      word cannot invoke itself by name. See the ficl word "recurse".
587**      NOTE: smudge always points to the last word defined. IMMEDIATE
588**      makes use of this fact. Smudge is initially NULL.
589**
590** pForthWords -- pointer to the default wordlist (FICL_HASH).
591**      This is the initial compilation list, and contains all
592**      ficl's precompiled words.
593**
594** pCompile -- compilation wordlist - initially equal to pForthWords
595** pSearch  -- array of pointers to wordlists. Managed as a stack.
596**      Highest index is the first list in the search order.
597** nLists   -- number of lists in pSearch. nLists-1 is the highest
598**      filled slot in pSearch, and points to the first wordlist
599**      in the search order
600** size -- number of cells in the dictionary (total)
601** dict -- start of data area. Must be at the end of the struct.
602*/
603typedef struct ficl_dict
604{
605    CELL *here;
606    FICL_WORD *smudge;
607    FICL_HASH *pForthWords;
608    FICL_HASH *pCompile;
609    FICL_HASH *pSearch[FICL_DEFAULT_VOCS];
610    int        nLists;
611    unsigned   size;    /* Number of cells in dict (total)*/
612    CELL       dict[1]; /* Base of dictionary memory      */
613} FICL_DICT;
614
615void       *alignPtr(void *ptr);
616void        dictAbortDefinition(FICL_DICT *pDict);
617void        dictAlign(FICL_DICT *pDict);
618int         dictAllot(FICL_DICT *pDict, int n);
619int         dictAllotCells(FICL_DICT *pDict, int nCells);
620void        dictAppendCell(FICL_DICT *pDict, CELL c);
621void        dictAppendChar(FICL_DICT *pDict, char c);
622FICL_WORD  *dictAppendWord(FICL_DICT *pDict,
623                           char *name,
624                           FICL_CODE pCode,
625                           UNS8 flags);
626FICL_WORD  *dictAppendWord2(FICL_DICT *pDict,
627                           STRINGINFO si,
628                           FICL_CODE pCode,
629                           UNS8 flags);
630void        dictAppendUNS32(FICL_DICT *pDict, UNS32 u);
631int         dictCellsAvail(FICL_DICT *pDict);
632int         dictCellsUsed (FICL_DICT *pDict);
633void        dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells);
634FICL_DICT  *dictCreate(unsigned nCELLS);
635FICL_DICT  *dictCreateHashed(unsigned nCells, unsigned nHash);
636void        dictDelete(FICL_DICT *pDict);
637void        dictEmpty(FICL_DICT *pDict, unsigned nHash);
638void        dictHashSummary(FICL_VM *pVM);
639int         dictIncludes(FICL_DICT *pDict, void *p);
640FICL_WORD  *dictLookup(FICL_DICT *pDict, STRINGINFO si);
641#if FICL_WANT_LOCALS
642FICL_WORD  *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si);
643#endif
644void        dictResetSearchOrder(FICL_DICT *pDict);
645void        dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr);
646void        dictSetImmediate(FICL_DICT *pDict);
647void        dictUnsmudge(FICL_DICT *pDict);
648CELL       *dictWhere(FICL_DICT *pDict);
649
650
651/*
652** External interface to FICL...
653*/
654/*
655** f i c l I n i t S y s t e m
656** Binds a global dictionary to the interpreter system and initializes
657** the dict to contain the ANSI CORE wordset.
658** You specify the address and size of the allocated area.
659** After that, ficl manages it.
660** First step is to set up the static pointers to the area.
661** Then write the "precompiled" portion of the dictionary in.
662** The dictionary needs to be at least large enough to hold the
663** precompiled part. Try 1K cells minimum. Use "words" to find
664** out how much of the dictionary is used at any time.
665*/
666void       ficlInitSystem(int nDictCells);
667
668/*
669** f i c l T e r m S y s t e m
670** Deletes the system dictionary and all virtual machines that
671** were created with ficlNewVM (see below). Call this function to
672** reclaim all memory used by the dictionary and VMs.
673*/
674void       ficlTermSystem(void);
675
676/*
677** f i c l E x e c
678** Evaluates a block of input text in the context of the
679** specified interpreter. Emits any requested output to the
680** interpreter's output function
681** Execution returns when the text block has been executed,
682** or an error occurs.
683** Returns one of the VM_XXXX codes defined in ficl.h:
684** VM_OUTOFTEXT is the normal exit condition
685** VM_ERREXIT means that the interp encountered a syntax error
686**      and the vm has been reset to recover (some or all
687**      of the text block got ignored
688** VM_USEREXIT means that the user executed the "bye" command
689**      to shut down the interpreter. This would be a good
690**      time to delete the vm, etc -- or you can ignore this
691**      signal.
692** Preconditions: successful execution of ficlInitSystem,
693**      Successful creation and init of the VM by ficlNewVM (or equiv)
694*/
695int        ficlExec(FICL_VM *pVM, char *pText);
696
697/*
698** Create a new VM from the heap, and link it into the system VM list.
699** Initializes the VM and binds default sized stacks to it. Returns the
700** address of the VM, or NULL if an error occurs.
701** Precondition: successful execution of ficlInitSystem
702*/
703FICL_VM   *ficlNewVM(void);
704
705/*
706** Returns the address of the most recently defined word in the system
707** dictionary with the given name, or NULL if no match.
708** Precondition: successful execution of ficlInitSystem
709*/
710FICL_WORD *ficlLookup(char *name);
711
712/*
713** f i c l G e t D i c t
714** Utility function - returns the address of the system dictionary.
715** Precondition: successful execution of ficlInitSystem
716*/
717FICL_DICT *ficlGetDict(void);
718FICL_DICT *ficlGetEnv(void);
719void       ficlSetEnv(char *name, UNS32 value);
720void       ficlSetEnvD(char *name, UNS32 hi, UNS32 lo);
721#if FICL_WANT_LOCALS
722FICL_DICT *ficlGetLoc(void);
723#endif
724/*
725** f i c l B u i l d
726** Builds a word into the system default dictionary in a thread-safe way.
727** Preconditions: system must be initialized, and there must
728** be enough space for the new word's header! Operation is
729** controlled by ficlLockDictionary, so any initialization
730** required by your version of the function (if you "overrode"
731** it) must be complete at this point.
732** Parameters:
733** name  -- the name of the word to be built
734** code  -- code to execute when the word is invoked - must take a single param
735**          pointer to a FICL_VM
736** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR!
737**          Most words can use FW_DEFAULT.
738** nAllot - number of extra cells to allocate in the parameter area (usually zero)
739*/
740int        ficlBuild(char *name, FICL_CODE code, char flags);
741
742/*
743** f i c l C o m p i l e C o r e
744** Builds the ANS CORE wordset into the dictionary - called by
745** ficlInitSystem - no need to waste dict space by doing it again.
746*/
747void       ficlCompileCore(FICL_DICT *dp);
748void       ficlCompileSoftCore(FICL_VM *pVM);
749
750/*
751** from words.c...
752*/
753void       constantParen(FICL_VM *pVM);
754void       twoConstParen(FICL_VM *pVM);
755
756#ifdef __cplusplus
757}
758#endif
759
760#endif /* __FICL_H__ */
761