ficl.h revision 77443
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
676116Sdcs** $Id: ficl.h,v 1.11 2001-04-26 21:41:48-07 jsadler Exp jsadler $
740843Smsmith*******************************************************************/
840843Smsmith/*
976116Sdcs** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
1076116Sdcs** All rights reserved.
1176116Sdcs**
1276116Sdcs** Get the latest Ficl release at http://ficl.sourceforge.net
1376116Sdcs**
1476116Sdcs** L I C E N S E  and  D I S C L A I M E R
1540843Smsmith**
1676116Sdcs** Redistribution and use in source and binary forms, with or without
1776116Sdcs** modification, are permitted provided that the following conditions
1876116Sdcs** are met:
1976116Sdcs** 1. Redistributions of source code must retain the above copyright
2076116Sdcs**    notice, this list of conditions and the following disclaimer.
2176116Sdcs** 2. Redistributions in binary form must reproduce the above copyright
2276116Sdcs**    notice, this list of conditions and the following disclaimer in the
2376116Sdcs**    documentation and/or other materials provided with the distribution.
2476116Sdcs**
2576116Sdcs** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2676116Sdcs** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2776116Sdcs** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2876116Sdcs** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2976116Sdcs** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3076116Sdcs** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3176116Sdcs** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3276116Sdcs** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3376116Sdcs** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3476116Sdcs** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3576116Sdcs** SUCH DAMAGE.
3676116Sdcs**
3740843Smsmith** I am interested in hearing from anyone who uses ficl. If you have
3840843Smsmith** a problem, a success story, a defect, an enhancement request, or
3976116Sdcs** if you would like to contribute to the ficl release, please send
4076116Sdcs** contact me by email at the address above.
4176116Sdcs**
4276116Sdcs** $Id: ficl.h,v 1.11 2001-04-26 21:41:48-07 jsadler Exp jsadler $
4340843Smsmith*/
4440843Smsmith
4551786Sdcs/* $FreeBSD: head/sys/boot/ficl/ficl.h 77443 2001-05-29 23:44:12Z dcs $ */
4651786Sdcs
4740843Smsmith#if !defined (__FICL_H__)
4840843Smsmith#define __FICL_H__
4940843Smsmith/*
5040843Smsmith** Ficl (Forth-inspired command language) is an ANS Forth
5140843Smsmith** interpreter written in C. Unlike traditional Forths, this
5240843Smsmith** interpreter is designed to be embedded into other systems
5340843Smsmith** as a command/macro/development prototype language.
5440843Smsmith**
5540843Smsmith** Where Forths usually view themselves as the center of the system
5640843Smsmith** and expect the rest of the system to be coded in Forth, Ficl
5740843Smsmith** acts as a component of the system. It is easy to export
5840843Smsmith** code written in C or ASM to Ficl in the style of TCL, or to invoke
5940843Smsmith** Ficl code from a compiled module. This allows you to do incremental
6040843Smsmith** development in a way that combines the best features of threaded
6140843Smsmith** languages (rapid development, quick code/test/debug cycle,
6240843Smsmith** reasonably fast) with the best features of C (everyone knows it,
6340843Smsmith** easier to support large blocks of code, efficient, type checking).
6440843Smsmith**
6540843Smsmith** Ficl provides facilities for interoperating
6640843Smsmith** with programs written in C: C functions can be exported to Ficl,
6740843Smsmith** and Ficl commands can be executed via a C calling interface. The
6840843Smsmith** interpreter is re-entrant, so it can be used in multiple instances
6940843Smsmith** in a multitasking system. Unlike Forth, Ficl's outer interpreter
7040843Smsmith** expects a text block as input, and returns to the caller after each
7140843Smsmith** text block, so the "data pump" is somewhere in external code. This
7240843Smsmith** is more like TCL than Forth, which usually expcets to be at the center
7340843Smsmith** of the system, requesting input at its convenience. Each Ficl virtual
7440843Smsmith** machine can be bound to a different I/O channel, and is independent
7540843Smsmith** of all others in in the same address space except that all virtual
7640843Smsmith** machines share a common dictionary (a sort or open symbol table that
7740843Smsmith** defines all of the elements of the language).
7840843Smsmith**
7940843Smsmith** Code is written in ANSI C for portability.
8040843Smsmith**
8140843Smsmith** Summary of Ficl features and constraints:
8240843Smsmith** - Standard: Implements the ANSI Forth CORE word set and part
8340843Smsmith**   of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and
8440843Smsmith**   TOOLS EXT, LOCAL and LOCAL ext and various extras.
8540843Smsmith** - Extensible: you can export code written in Forth, C,
8640843Smsmith**   or asm in a straightforward way. Ficl provides open
8740843Smsmith**   facilities for extending the language in an application
8840843Smsmith**   specific way. You can even add new control structures!
8940843Smsmith** - Ficl and C can interact in two ways: Ficl can encapsulate
9040843Smsmith**   C code, or C code can invoke Ficl code.
9140843Smsmith** - Thread-safe, re-entrant: The shared system dictionary
9240843Smsmith**   uses a locking mechanism that you can either supply
9340843Smsmith**   or stub out to provide exclusive access. Each Ficl
9440843Smsmith**   virtual machine has an otherwise complete state, and
9540843Smsmith**   each can be bound to a separate I/O channel (or none at all).
9640843Smsmith** - Simple encapsulation into existing systems: a basic implementation
9740843Smsmith**   requires three function calls (see the example program in testmain.c).
9840843Smsmith** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data
9940843Smsmith**   environments. It does require somewhat more memory than a pure
10040843Smsmith**   ROM implementation because it builds its system dictionary in
10140843Smsmith**   RAM at startup time.
10240843Smsmith** - Written an ANSI C to be as simple as I can make it to understand,
10340843Smsmith**   support, debug, and port. Compiles without complaint at /Az /W4
10440843Smsmith**   (require ANSI C, max warnings) under Microsoft VC++ 5.
10540843Smsmith** - Does full 32 bit math (but you need to implement
10640843Smsmith**   two mixed precision math primitives (see sysdep.c))
10740843Smsmith** - Indirect threaded interpreter is not the fastest kind of
10840843Smsmith**   Forth there is (see pForth 68K for a really fast subroutine
10940843Smsmith**   threaded interpreter), but it's the cleanest match to a
11040843Smsmith**   pure C implementation.
11140843Smsmith**
11240843Smsmith** P O R T I N G   F i c l
11340843Smsmith**
11440843Smsmith** To install Ficl on your target system, you need an ANSI C compiler
11540843Smsmith** and its runtime library. Inspect the system dependent macros and
11640843Smsmith** functions in sysdep.h and sysdep.c and edit them to suit your
11740843Smsmith** system. For example, INT16 is a short on some compilers and an
11840843Smsmith** int on others. Check the default CELL alignment controlled by
11940843Smsmith** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree,
12040843Smsmith** ficlLockDictionary, and ficlTextOut to work with your operating system.
12140843Smsmith** Finally, use testmain.c as a guide to installing the Ficl system and
12240843Smsmith** one or more virtual machines into your code. You do not need to include
12340843Smsmith** testmain.c in your build.
12440843Smsmith**
12540843Smsmith** T o   D o   L i s t
12640843Smsmith**
12740843Smsmith** 1. Unimplemented system dependent CORE word: key
12840843Smsmith** 2. Kludged CORE word: ACCEPT
12940843Smsmith** 3. Dictionary locking is full of holes - only one vm at a time
13040843Smsmith**    can alter the dict.
13140843Smsmith** 4. Ficl uses the pad in CORE words - this violates the standard,
13240843Smsmith**    but it's cleaner for a multithreaded system. I'll have to make a
13340843Smsmith**    second pad for reference by the word PAD to fix this.
13440843Smsmith**
13540843Smsmith** F o r   M o r e   I n f o r m a t i o n
13640843Smsmith**
13740843Smsmith** Web home of ficl
13840843Smsmith**   http://www.taygeta.com/forth/compilers
13940843Smsmith** Check this website for Forth literature (including the ANSI standard)
14040843Smsmith**   http://www.taygeta.com/forthlit.html
14140843Smsmith** and here for software and more links
14240843Smsmith**   http://www.taygeta.com/forth.html
14340843Smsmith**
14440843Smsmith** Obvious Performance enhancement opportunities
14540843Smsmith** Compile speed
14640843Smsmith** - work on interpret speed
14740843Smsmith** - turn off locals (FICL_WANT_LOCALS)
14840843Smsmith** Interpret speed
14940843Smsmith** - Change inner interpreter (and everything else)
15040843Smsmith**   so that a definition is a list of pointers to functions
15140843Smsmith**   and inline data rather than pointers to words. This gets
15240843Smsmith**   rid of vm->runningWord and a level of indirection in the
15340843Smsmith**   inner loop. I'll look at it for ficl 3.0
15440843Smsmith** - Make the main hash table a bigger prime (HASHSIZE)
15540843Smsmith** - FORGET about twiddling the hash function - my experience is
15640843Smsmith**   that that is a waste of time.
15740843Smsmith** - eliminate the need to pass the pVM parameter on the stack
15840843Smsmith**   by dedicating a register to it. Most words need access to the
15940843Smsmith**   vm, but the parameter passing overhead can be reduced. One way
16040843Smsmith**   requires that the host OS have a task switch callout. Create
16140843Smsmith**   a global variable for the running VM and refer to it in words
16240843Smsmith**   that need VM access. Alternative: use thread local storage.
16340843Smsmith**   For single threaded implementations, you can just use a global.
16440843Smsmith**   The first two solutions create portability problems, so I
16540843Smsmith**   haven't considered doing them. Another possibility is to
16640843Smsmith**   declare the pVm parameter to be "register", and hope the compiler
16740843Smsmith**   pays attention.
16840843Smsmith**
16940843Smsmith*/
17040843Smsmith
17140843Smsmith/*
17240843Smsmith** Revision History:
17351786Sdcs**
17451786Sdcs** 15 Apr 1999 (sadler) Merged FreeBSD changes for exception wordset and
17551786Sdcs** counted strings in ficlExec.
17643078Smsmith** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an
17743078Smsmith** "end" field, and all words respect this. ficlExec is passed a "size"
17843078Smsmith** of TIB, as well as vmPushTib. This size is used to calculate the "end"
17943078Smsmith** of the string, ie, base+size. If the size is not known, pass -1.
18043078Smsmith**
18143078Smsmith** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing
18243078Smsmith** words has been modified to conform to EXCEPTION EXT word set.
18343078Smsmith**
18440843Smsmith** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT,
18540843Smsmith**  SEARCH / SEARCH EXT, TOOLS / TOOLS EXT.
18640843Smsmith**  Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD,
18740843Smsmith**  EMPTY to clear stack.
18840843Smsmith**
18940843Smsmith** 29 jun 1998 (sadler) added variable sized hash table support
19040843Smsmith**  and ANS Forth optional SEARCH & SEARCH EXT word set.
19140843Smsmith** 26 May 1998 (sadler)
19240843Smsmith**  FICL_PROMPT macro
19340843Smsmith** 14 April 1998 (sadler) V1.04
19440843Smsmith**  Ficlwin: Windows version, Skip Carter's Linux port
19540843Smsmith** 5 March 1998 (sadler) V1.03
19640843Smsmith**  Bug fixes -- passes John Ryan's ANS test suite "core.fr"
19740843Smsmith**
19840843Smsmith** 24 February 1998 (sadler) V1.02
19940843Smsmith** -Fixed bugs in <# # #>
20040843Smsmith** -Changed FICL_WORD so that storage for the name characters
20140843Smsmith**  can be allocated from the dictionary as needed rather than
20240843Smsmith**  reserving 32 bytes in each word whether needed or not -
20340843Smsmith**  this saved 50% of the dictionary storage requirement.
20440843Smsmith** -Added words in testmain for Win32 functions system,chdir,cwd,
20540843Smsmith**  also added a word that loads and evaluates a file.
20640843Smsmith**
20740843Smsmith** December 1997 (sadler)
20840843Smsmith** -Added VM_RESTART exception handling in ficlExec -- this lets words
20940843Smsmith**  that require additional text to succeed (like :, create, variable...)
21040843Smsmith**  recover gracefully from an empty input buffer rather than emitting
21140843Smsmith**  an error message. Definitions can span multiple input blocks with
21240843Smsmith**  no restrictions.
21340843Smsmith** -Changed #include order so that <assert.h> is included in sysdep.h,
21440843Smsmith**  and sysdep is included in all other files. This lets you define
21540843Smsmith**  NDEBUG in sysdep.h to disable assertions if you want to.
21640843Smsmith** -Make PC specific system dependent code conditional on _M_IX86
21740843Smsmith**  defined so that ports can coexist in sysdep.h/sysdep.c
21840843Smsmith*/
21940843Smsmith
22040843Smsmith#ifdef __cplusplus
22140843Smsmithextern "C" {
22240843Smsmith#endif
22340843Smsmith
22440843Smsmith#include "sysdep.h"
22540843Smsmith#include <limits.h> /* UCHAR_MAX */
22640843Smsmith
22740843Smsmith/*
22840843Smsmith** Forward declarations... read on.
22940843Smsmith*/
23040843Smsmithstruct ficl_word;
23140843Smsmithstruct vm;
23240843Smsmithstruct ficl_dict;
23376116Sdcsstruct ficl_system;
23476116Sdcstypedef struct ficl_system FICL_SYSTEM;
23540843Smsmith
23640843Smsmith/*
23740843Smsmith** the Good Stuff starts here...
23840843Smsmith*/
23976116Sdcs#define FICL_VER    "2.05"
24051786Sdcs#if !defined (FICL_PROMPT)
24151786Sdcs#define FICL_PROMPT "ok> "
24240949Smsmith#endif
24340843Smsmith
24440843Smsmith/*
24540843Smsmith** ANS Forth requires false to be zero, and true to be the ones
24640843Smsmith** complement of false... that unifies logical and bitwise operations
24740843Smsmith** nicely.
24840843Smsmith*/
24976116Sdcs#define FICL_TRUE  ((unsigned long)~(0L))
25040843Smsmith#define FICL_FALSE (0)
25140843Smsmith#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE)
25240843Smsmith
25340843Smsmith
25440843Smsmith/*
25540843Smsmith** A CELL is the main storage type. It must be large enough
25651786Sdcs** to contain a pointer or a scalar. In order to accommodate
25751786Sdcs** 32 bit and 64 bit processors, use abstract types for i and u.
25840843Smsmith*/
25940843Smsmithtypedef union _cell
26040843Smsmith{
26176116Sdcs    FICL_INT i;
26251786Sdcs    FICL_UNS u;
26376116Sdcs#if (FICL_WANT_FLOAT)
26476116Sdcs    FICL_FLOAT f;
26576116Sdcs#endif
26676116Sdcs    void *p;
26776116Sdcs    void (*fn)(void);
26840843Smsmith} CELL;
26940843Smsmith
27040843Smsmith/*
27140843Smsmith** LVALUEtoCELL does a little pointer trickery to cast any 32 bit
27240843Smsmith** lvalue (informal definition: an expression whose result has an
27340843Smsmith** address) to CELL. Remember that constants and casts are NOT
27440843Smsmith** themselves lvalues!
27540843Smsmith*/
27640843Smsmith#define LVALUEtoCELL(v) (*(CELL *)&v)
27740843Smsmith
27840843Smsmith/*
27940843Smsmith** PTRtoCELL is a cast through void * intended to satisfy the
28040843Smsmith** most outrageously pedantic compiler... (I won't mention
28140843Smsmith** its name)
28240843Smsmith*/
28340843Smsmith#define PTRtoCELL (CELL *)(void *)
28440843Smsmith#define PTRtoSTRING (FICL_STRING *)(void *)
28540843Smsmith
28640843Smsmith/*
28740843Smsmith** Strings in FICL are stored in Pascal style - with a count
28840843Smsmith** preceding the text. We'll also NULL-terminate them so that
28940843Smsmith** they work with the usual C lib string functions. (Belt &
29040843Smsmith** suspenders? You decide.)
29140843Smsmith** STRINGINFO hides the implementation with a couple of
29240843Smsmith** macros for use in internal routines.
29340843Smsmith*/
29440843Smsmith
29540843Smsmithtypedef unsigned char FICL_COUNT;
29640843Smsmith#define FICL_STRING_MAX UCHAR_MAX
29740843Smsmithtypedef struct _ficl_string
29840843Smsmith{
29940843Smsmith    FICL_COUNT count;
30040843Smsmith    char text[1];
30140843Smsmith} FICL_STRING;
30240843Smsmith
30340843Smsmithtypedef struct
30440843Smsmith{
30561182Sdcs    FICL_UNS count;
30640843Smsmith    char *cp;
30740843Smsmith} STRINGINFO;
30840843Smsmith
30940843Smsmith#define SI_COUNT(si) (si.count)
31040843Smsmith#define SI_PTR(si)   (si.cp)
31161182Sdcs#define SI_SETLEN(si, len) (si.count = (FICL_UNS)(len))
31240843Smsmith#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr))
31340843Smsmith/*
31440843Smsmith** Init a STRINGINFO from a pointer to NULL-terminated string
31540843Smsmith*/
31640843Smsmith#define SI_PSZ(si, psz) \
31740843Smsmith            {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);}
31840843Smsmith/*
31940843Smsmith** Init a STRINGINFO from a pointer to FICL_STRING
32040843Smsmith*/
32140843Smsmith#define SI_PFS(si, pfs) \
32240843Smsmith            {si.cp = pfs->text; si.count = pfs->count;}
32340843Smsmith
32440843Smsmith/*
32576116Sdcs** Ficl uses this little structure to hold the address of
32640843Smsmith** the block of text it's working on and an index to the next
32740843Smsmith** unconsumed character in the string. Traditionally, this is
32840843Smsmith** done by a Text Input Buffer, so I've called this struct TIB.
32943078Smsmith**
33043078Smsmith** Since this structure also holds the size of the input buffer,
33143078Smsmith** and since evaluate requires that, let's put the size here.
33243078Smsmith** The size is stored as an end-pointer because that is what the
33343078Smsmith** null-terminated string aware functions find most easy to deal
33443078Smsmith** with.
33543078Smsmith** Notice, though, that nobody really uses this except evaluate,
33643078Smsmith** so it might just be moved to FICL_VM instead. (sobral)
33740843Smsmith*/
33840843Smsmithtypedef struct
33940843Smsmith{
34061149Sdcs    FICL_INT index;
34143078Smsmith    char *end;
34240843Smsmith    char *cp;
34340843Smsmith} TIB;
34440843Smsmith
34540843Smsmith
34640843Smsmith/*
34740843Smsmith** Stacks get heavy use in Ficl and Forth...
34840843Smsmith** Each virtual machine implements two of them:
34940843Smsmith** one holds parameters (data), and the other holds return
35040843Smsmith** addresses and control flow information for the virtual
35140843Smsmith** machine. (Note: C's automatic stack is implicitly used,
35240843Smsmith** but not modeled because it doesn't need to be...)
35340843Smsmith** Here's an abstract type for a stack
35440843Smsmith*/
35540843Smsmithtypedef struct _ficlStack
35640843Smsmith{
35751786Sdcs    FICL_UNS nCells;    /* size of the stack */
35840843Smsmith    CELL *pFrame;       /* link reg for stack frame */
35940843Smsmith    CELL *sp;           /* stack pointer */
36076116Sdcs    CELL base[1];       /* Top of stack */
36140843Smsmith} FICL_STACK;
36240843Smsmith
36340843Smsmith/*
36440843Smsmith** Stack methods... many map closely to required Forth words.
36540843Smsmith*/
36640843SmsmithFICL_STACK *stackCreate(unsigned nCells);
36740843Smsmithvoid        stackDelete(FICL_STACK *pStack);
36840843Smsmithint         stackDepth (FICL_STACK *pStack);
36940843Smsmithvoid        stackDrop  (FICL_STACK *pStack, int n);
37040843SmsmithCELL        stackFetch (FICL_STACK *pStack, int n);
37140843SmsmithCELL        stackGetTop(FICL_STACK *pStack);
37240843Smsmithvoid        stackLink  (FICL_STACK *pStack, int nCells);
37340843Smsmithvoid        stackPick  (FICL_STACK *pStack, int n);
37440843SmsmithCELL        stackPop   (FICL_STACK *pStack);
37576116Sdcsvoid       *stackPopPtr(FICL_STACK *pStack);
37651786SdcsFICL_UNS    stackPopUNS(FICL_STACK *pStack);
37751786SdcsFICL_INT    stackPopINT(FICL_STACK *pStack);
37840843Smsmithvoid        stackPush  (FICL_STACK *pStack, CELL c);
37940843Smsmithvoid        stackPushPtr  (FICL_STACK *pStack, void *ptr);
38051786Sdcsvoid        stackPushUNS(FICL_STACK *pStack, FICL_UNS u);
38151786Sdcsvoid        stackPushINT(FICL_STACK *pStack, FICL_INT i);
38240843Smsmithvoid        stackReset (FICL_STACK *pStack);
38340843Smsmithvoid        stackRoll  (FICL_STACK *pStack, int n);
38440843Smsmithvoid        stackSetTop(FICL_STACK *pStack, CELL c);
38540843Smsmithvoid        stackStore (FICL_STACK *pStack, int n, CELL c);
38640843Smsmithvoid        stackUnlink(FICL_STACK *pStack);
38740843Smsmith
38876116Sdcs#if (FICL_WANT_FLOAT)
38976116Sdcsfloat       stackPopFloat (FICL_STACK *pStack);
39076116Sdcsvoid        stackPushFloat(FICL_STACK *pStack, float f);
39176116Sdcs#endif
39276116Sdcs
39376116Sdcs/*
39476116Sdcs** Shortcuts (Guy Carver)
39576116Sdcs*/
39676116Sdcs#define PUSHPTR(p)  stackPushPtr(pVM->pStack,p)
39776116Sdcs#define PUSHUNS(u)  stackPushUNS(pVM->pStack,u)
39876116Sdcs#define PUSHINT(i)  stackPushINT(pVM->pStack,i)
39976116Sdcs#define PUSHFLOAT(f)    stackPushFloat(pVM->fStack,f)
40076116Sdcs#define PUSH(c)     stackPush(pVM->pStack,c)
40176116Sdcs#define POPPTR()    stackPopPtr(pVM->pStack)
40276116Sdcs#define POPUNS()    stackPopUNS(pVM->pStack)
40376116Sdcs#define POPINT()    stackPopINT(pVM->pStack)
40476116Sdcs#define POPFLOAT()  stackPopFloat(pVM->fStack)
40576116Sdcs#define POP()       stackPop(pVM->pStack)
40676116Sdcs#define GETTOP()    stackGetTop(pVM->pStack)
40776116Sdcs#define SETTOP(c)   stackSetTop(pVM->pStack,LVALUEtoCELL(c))
40876116Sdcs#define GETTOPF()   stackGetTop(pVM->fStack)
40976116Sdcs#define SETTOPF(c)  stackSetTop(pVM->fStack,LVALUEtoCELL(c))
41076116Sdcs#define STORE(n,c)  stackStore(pVM->pStack,n,LVALUEtoCELL(c))
41176116Sdcs#define DEPTH()     stackDepth(pVM->pStack)
41276116Sdcs#define DROP(n)     stackDrop(pVM->pStack,n)
41376116Sdcs#define DROPF(n)    stackDrop(pVM->fStack,n)
41476116Sdcs#define FETCH(n)    stackFetch(pVM->pStack,n)
41576116Sdcs#define PICK(n)     stackPick(pVM->pStack,n)
41676116Sdcs#define PICKF(n)    stackPick(pVM->fStack,n)
41776116Sdcs#define ROLL(n)     stackRoll(pVM->pStack,n)
41876116Sdcs#define ROLLF(n)    stackRoll(pVM->fStack,n)
41976116Sdcs
42040843Smsmith/*
42140843Smsmith** The virtual machine (VM) contains the state for one interpreter.
42240843Smsmith** Defined operations include:
42340843Smsmith** Create & initialize
42440843Smsmith** Delete
42540843Smsmith** Execute a block of text
42640843Smsmith** Parse a word out of the input stream
42740843Smsmith** Call return, and branch
42840843Smsmith** Text output
42940843Smsmith** Throw an exception
43040843Smsmith*/
43140843Smsmith
43240843Smsmithtypedef struct ficl_word ** IPTYPE; /* the VM's instruction pointer */
43340843Smsmith
43440843Smsmith/*
43540843Smsmith** Each VM has a placeholder for an output function -
43640843Smsmith** this makes it possible to have each VM do I/O
43740843Smsmith** through a different device. If you specify no
43840843Smsmith** OUTFUNC, it defaults to ficlTextOut.
43940843Smsmith*/
44040843Smsmithtypedef void (*OUTFUNC)(struct vm *pVM, char *text, int fNewline);
44140843Smsmith
44240843Smsmith/*
44340843Smsmith** Each VM operates in one of two non-error states: interpreting
44440843Smsmith** or compiling. When interpreting, words are simply executed.
44540843Smsmith** When compiling, most words in the input stream have their
44640843Smsmith** addresses inserted into the word under construction. Some words
44740843Smsmith** (known as IMMEDIATE) are executed in the compile state, too.
44840843Smsmith*/
44940843Smsmith/* values of STATE */
45040843Smsmith#define INTERPRET 0
45140843Smsmith#define COMPILE   1
45240843Smsmith
45340843Smsmith/*
45440843Smsmith** The pad is a small scratch area for text manipulation. ANS Forth
45540843Smsmith** requires it to hold at least 84 characters.
45640843Smsmith*/
45740843Smsmith#if !defined nPAD
45840843Smsmith#define nPAD 256
45940843Smsmith#endif
46040843Smsmith
46140843Smsmith/*
46240843Smsmith** ANS Forth requires that a word's name contain {1..31} characters.
46340843Smsmith*/
46440843Smsmith#if !defined nFICLNAME
46576116Sdcs#define nFICLNAME       31
46640843Smsmith#endif
46740843Smsmith
46840843Smsmith/*
46940843Smsmith** OK - now we can really define the VM...
47040843Smsmith*/
47140843Smsmithtypedef struct vm
47240843Smsmith{
47376116Sdcs    FICL_SYSTEM    *pSys;       /* Which system this VM belongs to  */
47440843Smsmith    struct vm      *link;       /* Ficl keeps a VM list for simple teardown */
47540843Smsmith    jmp_buf        *pState;     /* crude exception mechanism...     */
47640843Smsmith    OUTFUNC         textOut;    /* Output callback - see sysdep.c   */
47740843Smsmith    void *          pExtend;    /* vm extension pointer             */
47840843Smsmith    short           fRestart;   /* Set TRUE to restart runningWord  */
47940843Smsmith    IPTYPE          ip;         /* instruction pointer              */
48040843Smsmith    struct ficl_word
48140843Smsmith                   *runningWord;/* address of currently running word (often just *(ip-1) ) */
48261182Sdcs    FICL_UNS        state;      /* compiling or interpreting        */
48361182Sdcs    FICL_UNS        base;       /* number conversion base           */
48440843Smsmith    FICL_STACK     *pStack;     /* param stack                      */
48540843Smsmith    FICL_STACK     *rStack;     /* return stack                     */
48676116Sdcs#if FICL_WANT_FLOAT
48776116Sdcs    FICL_STACK     *fStack;     /* float stack (optional)           */
48876116Sdcs#endif
48940843Smsmith    CELL            sourceID;   /* -1 if string, 0 if normal input  */
49040843Smsmith    TIB             tib;        /* address of incoming text string  */
49140843Smsmith#if FICL_WANT_USER
49240843Smsmith    CELL            user[FICL_USER_CELLS];
49340843Smsmith#endif
49440843Smsmith    char            pad[nPAD];  /* the scratch area (see above)     */
49540843Smsmith} FICL_VM;
49640843Smsmith
49740843Smsmith/*
49840843Smsmith** A FICL_CODE points to a function that gets called to help execute
49940843Smsmith** a word in the dictionary. It always gets passed a pointer to the
50040843Smsmith** running virtual machine, and from there it can get the address
50140843Smsmith** of the parameter area of the word it's supposed to operate on.
50240843Smsmith** For precompiled words, the code is all there is. For user defined
50340843Smsmith** words, the code assumes that the word's parameter area is a list
50440843Smsmith** of pointers to the code fields of other words to execute, and
50540843Smsmith** may also contain inline data. The first parameter is always
50640843Smsmith** a pointer to a code field.
50740843Smsmith*/
50840843Smsmithtypedef void (*FICL_CODE)(FICL_VM *pVm);
50940843Smsmith
51051786Sdcs#if 0
51151786Sdcs#define VM_ASSERT(pVM) assert((*(pVM->ip - 1)) == pVM->runningWord)
51251786Sdcs#else
51351786Sdcs#define VM_ASSERT(pVM)
51451786Sdcs#endif
51551786Sdcs
51640843Smsmith/*
51740843Smsmith** Ficl models memory as a contiguous space divided into
51840843Smsmith** words in a linked list called the dictionary.
51940843Smsmith** A FICL_WORD starts each entry in the list.
52040843Smsmith** Version 1.02: space for the name characters is allotted from
52140843Smsmith** the dictionary ahead of the word struct - this saves about half
52240843Smsmith** the storage on average with very little runtime cost.
52340843Smsmith*/
52440843Smsmithtypedef struct ficl_word
52540843Smsmith{
52640843Smsmith    struct ficl_word *link;     /* Previous word in the dictionary      */
52740843Smsmith    UNS16 hash;
52840843Smsmith    UNS8 flags;                 /* Immediate, Smudge, Compile-only      */
52940843Smsmith    FICL_COUNT nName;           /* Number of chars in word name         */
53040843Smsmith    char *name;                 /* First nFICLNAME chars of word name   */
53140843Smsmith    FICL_CODE code;             /* Native code to execute the word      */
53240843Smsmith    CELL param[1];              /* First data cell of the word          */
53340843Smsmith} FICL_WORD;
53440843Smsmith
53540843Smsmith/*
53640843Smsmith** Worst-case size of a word header: nFICLNAME chars in name
53740843Smsmith*/
53840843Smsmith#define CELLS_PER_WORD  \
53940843Smsmith    ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \
54040843Smsmith                          / (sizeof (CELL)) )
54140843Smsmith
54240843Smsmithint wordIsImmediate(FICL_WORD *pFW);
54340843Smsmithint wordIsCompileOnly(FICL_WORD *pFW);
54440843Smsmith
54540843Smsmith/* flag values for word header */
54640843Smsmith#define FW_IMMEDIATE    1   /* execute me even if compiling */
54740843Smsmith#define FW_COMPILE      2   /* error if executed when not compiling */
54840843Smsmith#define FW_SMUDGE       4   /* definition in progress - hide me */
54940843Smsmith
55040843Smsmith#define FW_COMPIMMED    (FW_IMMEDIATE | FW_COMPILE)
55140843Smsmith#define FW_DEFAULT      0
55240843Smsmith
55340843Smsmith
55440843Smsmith/*
55540843Smsmith** Exit codes for vmThrow
55640843Smsmith*/
55751786Sdcs#define VM_INNEREXIT -256   /* tell ficlExecXT to exit inner loop */
55851786Sdcs#define VM_OUTOFTEXT -257   /* hungry - normal exit */
55951786Sdcs#define VM_RESTART   -258   /* word needs more text to succeed - re-run it */
56051786Sdcs#define VM_USEREXIT  -259   /* user wants to quit */
56151786Sdcs#define VM_ERREXIT   -260   /* interp found an error */
56276116Sdcs#define VM_BREAK     -261   /* debugger breakpoint */
56343078Smsmith#define VM_ABORT       -1   /* like errexit -- abort */
56443078Smsmith#define VM_ABORTQ      -2   /* like errexit -- abort" */
56543078Smsmith#define VM_QUIT       -56   /* like errexit, but leave pStack & base alone */
56640843Smsmith
56740843Smsmith
56840843Smsmithvoid        vmBranchRelative(FICL_VM *pVM, int offset);
56940843SmsmithFICL_VM *   vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack);
57040843Smsmithvoid        vmDelete (FICL_VM *pVM);
57140843Smsmithvoid        vmExecute(FICL_VM *pVM, FICL_WORD *pWord);
57240843Smsmithchar *      vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter);
57340843SmsmithSTRINGINFO  vmGetWord(FICL_VM *pVM);
57440843SmsmithSTRINGINFO  vmGetWord0(FICL_VM *pVM);
57540843Smsmithint         vmGetWordToPad(FICL_VM *pVM);
57640843SmsmithSTRINGINFO  vmParseString(FICL_VM *pVM, char delimiter);
57760959SdcsSTRINGINFO  vmParseStringEx(FICL_VM *pVM, char delimiter, char fSkipLeading);
57860959SdcsCELL        vmPop(FICL_VM *pVM);
57960959Sdcsvoid        vmPush(FICL_VM *pVM, CELL c);
58040843Smsmithvoid        vmPopIP  (FICL_VM *pVM);
58140843Smsmithvoid        vmPushIP (FICL_VM *pVM, IPTYPE newIP);
58240843Smsmithvoid        vmQuit   (FICL_VM *pVM);
58340843Smsmithvoid        vmReset  (FICL_VM *pVM);
58440843Smsmithvoid        vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut);
58560959Sdcs#if FICL_WANT_DEBUGGER
58660959Sdcsvoid        vmStep(FICL_VM *pVM);
58760959Sdcs#endif
58840843Smsmithvoid        vmTextOut(FICL_VM *pVM, char *text, int fNewline);
58940843Smsmithvoid        vmThrow  (FICL_VM *pVM, int except);
59040843Smsmithvoid        vmThrowErr(FICL_VM *pVM, char *fmt, ...);
59140843Smsmith
59251786Sdcs#define vmGetRunningWord(pVM) ((pVM)->runningWord)
59351786Sdcs
59451786Sdcs
59540843Smsmith/*
59651786Sdcs** The inner interpreter - coded as a macro (see note for
59751786Sdcs** INLINE_INNER_LOOP in sysdep.h for complaints about VC++ 5
59851786Sdcs*/
59960959Sdcs#define M_VM_STEP(pVM) \
60051786Sdcs        FICL_WORD *tempFW = *(pVM)->ip++; \
60151786Sdcs        (pVM)->runningWord = tempFW; \
60251786Sdcs        tempFW->code(pVM); \
60351786Sdcs
60460959Sdcs#define M_INNER_LOOP(pVM) \
60560959Sdcs    for (;;)  { M_VM_STEP(pVM) }
60651786Sdcs
60760959Sdcs
60851786Sdcs#if INLINE_INNER_LOOP != 0
60951786Sdcs#define     vmInnerLoop(pVM) M_INNER_LOOP(pVM)
61051786Sdcs#else
61151786Sdcsvoid        vmInnerLoop(FICL_VM *pVM);
61251786Sdcs#endif
61351786Sdcs
61451786Sdcs/*
61540843Smsmith** vmCheckStack needs a vm pointer because it might have to say
61640843Smsmith** something if it finds a problem. Parms popCells and pushCells
61740843Smsmith** correspond to the number of parameters on the left and right of
61840843Smsmith** a word's stack effect comment.
61940843Smsmith*/
62040843Smsmithvoid        vmCheckStack(FICL_VM *pVM, int popCells, int pushCells);
62176116Sdcs#if FICL_WANT_FLOAT
62276116Sdcsvoid        vmCheckFStack(FICL_VM *pVM, int popCells, int pushCells);
62376116Sdcs#endif
62440843Smsmith
62540843Smsmith/*
62640843Smsmith** TIB access routines...
62740843Smsmith** ANS forth seems to require the input buffer to be represented
62840843Smsmith** as a pointer to the start of the buffer, and an index to the
62940843Smsmith** next character to read.
63040843Smsmith** PushTib points the VM to a new input string and optionally
63140843Smsmith**  returns a copy of the current state
63240843Smsmith** PopTib restores the TIB state given a saved TIB from PushTib
63340843Smsmith** GetInBuf returns a pointer to the next unused char of the TIB
63440843Smsmith*/
63561182Sdcsvoid        vmPushTib(FICL_VM *pVM, char *text, FICL_INT nChars, TIB *pSaveTib);
63640843Smsmithvoid        vmPopTib(FICL_VM *pVM, TIB *pTib);
63740843Smsmith#define     vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index)
63851786Sdcs#define     vmGetInBufLen(pVM) ((pVM)->tib.end - (pVM)->tib.cp)
63951786Sdcs#define     vmGetInBufEnd(pVM) ((pVM)->tib.end)
64076116Sdcs#define     vmGetTibIndex(pVM)    (pVM)->tib.index
64140843Smsmith#define     vmSetTibIndex(pVM, i) (pVM)->tib.index = i
64240843Smsmith#define     vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp
64340843Smsmith
64440843Smsmith/*
64540843Smsmith** Generally useful string manipulators omitted by ANSI C...
64640843Smsmith** ltoa complements strtol
64740843Smsmith*/
64840843Smsmith#if defined(_WIN32) && !FICL_MAIN
64940843Smsmith/* #SHEESH
65040843Smsmith** Why do Microsoft Meatballs insist on contaminating
65140843Smsmith** my namespace with their string functions???
65240843Smsmith*/
65340843Smsmith#pragma warning(disable: 4273)
65440843Smsmith#endif
65540843Smsmith
65651786Sdcsint        isPowerOfTwo(FICL_UNS u);
65751786Sdcs
65851786Sdcschar       *ltoa( FICL_INT value, char *string, int radix );
65951786Sdcschar       *ultoa(FICL_UNS value, char *string, int radix );
66040843Smsmithchar        digit_to_char(int value);
66140843Smsmithchar       *strrev( char *string );
66251786Sdcschar       *skipSpace(char *cp, char *end);
66340843Smsmithchar       *caseFold(char *cp);
66476116Sdcsint         strincmp(char *cp1, char *cp2, FICL_UNS count);
66540843Smsmith
66640843Smsmith#if defined(_WIN32) && !FICL_MAIN
66740843Smsmith#pragma warning(default: 4273)
66840843Smsmith#endif
66940843Smsmith
67040843Smsmith/*
67140843Smsmith** Ficl hash table - variable size.
67240843Smsmith** assert(size > 0)
67340843Smsmith** If size is 1, the table degenerates into a linked list.
67440843Smsmith** A WORDLIST (see the search order word set in DPANS) is
67540843Smsmith** just a pointer to a FICL_HASH in this implementation.
67640843Smsmith*/
67751786Sdcs#if !defined HASHSIZE /* Default size of hash table. For most uniform */
67876116Sdcs#define HASHSIZE 241  /*   performance, use a prime number!   */
67940843Smsmith#endif
68040843Smsmith
68140843Smsmithtypedef struct ficl_hash
68240843Smsmith{
68376116Sdcs    struct ficl_hash *link;  /* link to parent class wordlist for OO */
68476116Sdcs    char      *name;         /* optional pointer to \0 terminated wordlist name */
68576116Sdcs    unsigned   size;         /* number of buckets in the hash */
68640843Smsmith    FICL_WORD *table[1];
68740843Smsmith} FICL_HASH;
68840843Smsmith
68940843Smsmithvoid        hashForget(FICL_HASH *pHash, void *where);
69040843SmsmithUNS16       hashHashCode(STRINGINFO si);
69140843Smsmithvoid        hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW);
69240843SmsmithFICL_WORD  *hashLookup(struct ficl_hash *pHash,
69340843Smsmith                       STRINGINFO si,
69440843Smsmith                       UNS16 hashCode);
69540843Smsmithvoid        hashReset(FICL_HASH *pHash);
69640843Smsmith
69740843Smsmith/*
69840843Smsmith** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's
69940843Smsmith** memory model. Description of fields:
70040843Smsmith**
70140843Smsmith** here -- points to the next free byte in the dictionary. This
70240843Smsmith**      pointer is forced to be CELL-aligned before a definition is added.
70340843Smsmith**      Do not assume any specific alignment otherwise - Use dictAlign().
70440843Smsmith**
70540843Smsmith** smudge -- pointer to word currently being defined (or last defined word)
70640843Smsmith**      If the definition completes successfully, the word will be
70740843Smsmith**      linked into the hash table. If unsuccessful, dictUnsmudge
70840843Smsmith**      uses this pointer to restore the previous state of the dictionary.
70940843Smsmith**      Smudge prevents unintentional recursion as a side-effect: the
71040843Smsmith**      dictionary search algo examines only completed definitions, so a
71140843Smsmith**      word cannot invoke itself by name. See the ficl word "recurse".
71240843Smsmith**      NOTE: smudge always points to the last word defined. IMMEDIATE
71340843Smsmith**      makes use of this fact. Smudge is initially NULL.
71440843Smsmith**
71540843Smsmith** pForthWords -- pointer to the default wordlist (FICL_HASH).
71640843Smsmith**      This is the initial compilation list, and contains all
71740843Smsmith**      ficl's precompiled words.
71840843Smsmith**
71940843Smsmith** pCompile -- compilation wordlist - initially equal to pForthWords
72040843Smsmith** pSearch  -- array of pointers to wordlists. Managed as a stack.
72140843Smsmith**      Highest index is the first list in the search order.
72240843Smsmith** nLists   -- number of lists in pSearch. nLists-1 is the highest
72340843Smsmith**      filled slot in pSearch, and points to the first wordlist
72440843Smsmith**      in the search order
72540843Smsmith** size -- number of cells in the dictionary (total)
72640843Smsmith** dict -- start of data area. Must be at the end of the struct.
72740843Smsmith*/
72840843Smsmithtypedef struct ficl_dict
72940843Smsmith{
73040843Smsmith    CELL *here;
73140843Smsmith    FICL_WORD *smudge;
73240843Smsmith    FICL_HASH *pForthWords;
73340843Smsmith    FICL_HASH *pCompile;
73440843Smsmith    FICL_HASH *pSearch[FICL_DEFAULT_VOCS];
73540843Smsmith    int        nLists;
73640843Smsmith    unsigned   size;    /* Number of cells in dict (total)*/
73760014Sdcs    CELL       *dict;   /* Base of dictionary memory      */
73840843Smsmith} FICL_DICT;
73940843Smsmith
74040843Smsmithvoid       *alignPtr(void *ptr);
74140843Smsmithvoid        dictAbortDefinition(FICL_DICT *pDict);
74240843Smsmithvoid        dictAlign(FICL_DICT *pDict);
74340843Smsmithint         dictAllot(FICL_DICT *pDict, int n);
74440843Smsmithint         dictAllotCells(FICL_DICT *pDict, int nCells);
74540843Smsmithvoid        dictAppendCell(FICL_DICT *pDict, CELL c);
74640843Smsmithvoid        dictAppendChar(FICL_DICT *pDict, char c);
74740843SmsmithFICL_WORD  *dictAppendWord(FICL_DICT *pDict,
74840843Smsmith                           char *name,
74940843Smsmith                           FICL_CODE pCode,
75040843Smsmith                           UNS8 flags);
75140843SmsmithFICL_WORD  *dictAppendWord2(FICL_DICT *pDict,
75240843Smsmith                           STRINGINFO si,
75340843Smsmith                           FICL_CODE pCode,
75440843Smsmith                           UNS8 flags);
75551786Sdcsvoid        dictAppendUNS(FICL_DICT *pDict, FICL_UNS u);
75640843Smsmithint         dictCellsAvail(FICL_DICT *pDict);
75740843Smsmithint         dictCellsUsed (FICL_DICT *pDict);
75840843Smsmithvoid        dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells);
75940843SmsmithFICL_DICT  *dictCreate(unsigned nCELLS);
76040843SmsmithFICL_DICT  *dictCreateHashed(unsigned nCells, unsigned nHash);
76176116SdcsFICL_HASH  *dictCreateWordlist(FICL_DICT *dp, int nBuckets);
76240843Smsmithvoid        dictDelete(FICL_DICT *pDict);
76340843Smsmithvoid        dictEmpty(FICL_DICT *pDict, unsigned nHash);
76440843Smsmithint         dictIncludes(FICL_DICT *pDict, void *p);
76540843SmsmithFICL_WORD  *dictLookup(FICL_DICT *pDict, STRINGINFO si);
76640843Smsmith#if FICL_WANT_LOCALS
76740843SmsmithFICL_WORD  *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si);
76840843Smsmith#endif
76940843Smsmithvoid        dictResetSearchOrder(FICL_DICT *pDict);
77040843Smsmithvoid        dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr);
77140843Smsmithvoid        dictSetImmediate(FICL_DICT *pDict);
77240843Smsmithvoid        dictUnsmudge(FICL_DICT *pDict);
77340843SmsmithCELL       *dictWhere(FICL_DICT *pDict);
77440843Smsmith
77540843Smsmith
77676116Sdcs/*
77776116Sdcs** P A R S E   S T E P
77876116Sdcs** (New for 2.05)
77976116Sdcs** See words.c: interpWord
78076116Sdcs** By default, ficl goes through two attempts to parse each token from its input
78176116Sdcs** stream: it first attempts to match it with a word in the dictionary, and
78276116Sdcs** if that fails, it attempts to convert it into a number. This mechanism is now
78376116Sdcs** extensible by additional steps. This allows extensions like floating point and
78476116Sdcs** double number support to be factored cleanly.
78576116Sdcs**
78676116Sdcs** Each parse step is a function that receives the next input token as a STRINGINFO.
78776116Sdcs** If the parse step matches the token, it must apply semantics to the token appropriate
78876116Sdcs** to the present value of VM.state (compiling or interpreting), and return FICL_TRUE.
78976116Sdcs** Otherwise it returns FICL_FALSE. See words.c: isNumber for an example
79076116Sdcs**
79176116Sdcs** Note: for the sake of efficiency, it's a good idea both to limit the number
79276116Sdcs** of parse steps and to code each parse step so that it rejects tokens that
79376116Sdcs** do not match as quickly as possible.
79476116Sdcs*/
79576116Sdcs
79676116Sdcstypedef int (*FICL_PARSE_STEP)(FICL_VM *pVM, STRINGINFO si);
79776116Sdcs
79840843Smsmith/*
79976116Sdcs** Appends a parse step function to the end of the parse list (see
80076116Sdcs** FICL_PARSE_STEP notes in ficl.h for details). Returns 0 if successful,
80176116Sdcs** nonzero if there's no more room in the list. Each parse step is a word in
80276116Sdcs** the dictionary. Precompiled parse steps can use (PARSE-STEP) as their
80376116Sdcs** CFA - see parenParseStep in words.c.
80476116Sdcs*/
80576116Sdcsint  ficlAddParseStep(FICL_SYSTEM *pSys, FICL_WORD *pFW); /* ficl.c */
80676116Sdcsvoid ficlAddPrecompiledParseStep(FICL_SYSTEM *pSys, char *name, FICL_PARSE_STEP pStep);
80776116Sdcsvoid ficlListParseSteps(FICL_VM *pVM);
80876116Sdcs
80976116Sdcs/*
81076116Sdcs** F I C L _ S Y S T E M
81176116Sdcs** The top level data structure of the system - ficl_system ties a list of
81276116Sdcs** virtual machines with their corresponding dictionaries. Ficl 3.0 will
81376116Sdcs** support multiple Ficl systems, allowing multiple concurrent sessions
81476116Sdcs** to separate dictionaries with some constraints.
81576116Sdcs** The present model allows multiple sessions to one dictionary provided
81676116Sdcs** you implement ficlLockDictionary() as specified in sysdep.h
81776116Sdcs**
81876116Sdcs** RESTRICTIONS: due to the use of static variables in words.c for compiling
81976116Sdcs** comtrol structures faster, if you use multiple ficl systems these variables
82076116Sdcs** will point into the most recently initialized dictionary - this is probably
82176116Sdcs** not a problem provided the precompiled dictionaries are identical for
82276116Sdcs** all systems.
82376116Sdcs*/
82476116Sdcsstruct ficl_system
82576116Sdcs{
82676116Sdcs    FICL_SYSTEM *link;
82776116Sdcs    FICL_WORD *parseList[FICL_MAX_PARSE_STEPS];
82876116Sdcs    FICL_VM *vmList;
82976116Sdcs    FICL_DICT *dp;
83076116Sdcs    FICL_DICT *envp;
83176116Sdcs#ifdef FICL_WANT_LOCALS
83276116Sdcs    FICL_DICT *localp;
83376116Sdcs#endif
83476116Sdcs    FICL_WORD *pInterp[3];
83576116Sdcs};
83676116Sdcs
83776116Sdcs/*
83840843Smsmith** External interface to FICL...
83940843Smsmith*/
84040843Smsmith/*
84140843Smsmith** f i c l I n i t S y s t e m
84240843Smsmith** Binds a global dictionary to the interpreter system and initializes
84340843Smsmith** the dict to contain the ANSI CORE wordset.
84440843Smsmith** You specify the address and size of the allocated area.
84540843Smsmith** After that, ficl manages it.
84640843Smsmith** First step is to set up the static pointers to the area.
84740843Smsmith** Then write the "precompiled" portion of the dictionary in.
84840843Smsmith** The dictionary needs to be at least large enough to hold the
84940843Smsmith** precompiled part. Try 1K cells minimum. Use "words" to find
85040843Smsmith** out how much of the dictionary is used at any time.
85140843Smsmith*/
85240843Smsmithvoid       ficlInitSystem(int nDictCells);
85340843Smsmith
85440843Smsmith/*
85540843Smsmith** f i c l T e r m S y s t e m
85640843Smsmith** Deletes the system dictionary and all virtual machines that
85740843Smsmith** were created with ficlNewVM (see below). Call this function to
85840843Smsmith** reclaim all memory used by the dictionary and VMs.
85940843Smsmith*/
86040843Smsmithvoid       ficlTermSystem(void);
86140843Smsmith
86240843Smsmith/*
86340843Smsmith** f i c l E x e c
86440843Smsmith** Evaluates a block of input text in the context of the
86540843Smsmith** specified interpreter. Emits any requested output to the
86651786Sdcs** interpreter's output function. If the input string is NULL
86751786Sdcs** terminated, you can pass -1 as nChars rather than count it.
86840843Smsmith** Execution returns when the text block has been executed,
86940843Smsmith** or an error occurs.
87040843Smsmith** Returns one of the VM_XXXX codes defined in ficl.h:
87140843Smsmith** VM_OUTOFTEXT is the normal exit condition
87240843Smsmith** VM_ERREXIT means that the interp encountered a syntax error
87340843Smsmith**      and the vm has been reset to recover (some or all
87440843Smsmith**      of the text block got ignored
87540843Smsmith** VM_USEREXIT means that the user executed the "bye" command
87640843Smsmith**      to shut down the interpreter. This would be a good
87740843Smsmith**      time to delete the vm, etc -- or you can ignore this
87840843Smsmith**      signal.
87943078Smsmith** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"'
88043078Smsmith**      commands.
88140843Smsmith** Preconditions: successful execution of ficlInitSystem,
88240843Smsmith**      Successful creation and init of the VM by ficlNewVM (or equiv)
88340843Smsmith*/
88451786Sdcsint        ficlExec (FICL_VM *pVM, char *pText);
88561182Sdcsint        ficlExecC(FICL_VM *pVM, char *pText, FICL_INT nChars);
88651786Sdcsint        ficlExecXT(FICL_VM *pVM, FICL_WORD *pWord);
88740843Smsmith
88840843Smsmith/*
88940989Sjkh** ficlExecFD(FICL_VM *pVM, int fd);
89040989Sjkh * Evaluates text from file passed in via fd.
89140989Sjkh * Execution returns when all of file has been executed or an
89240989Sjkh * error occurs.
89340989Sjkh */
89440989Sjkhint        ficlExecFD(FICL_VM *pVM, int fd);
89540989Sjkh
89640989Sjkh/*
89740843Smsmith** Create a new VM from the heap, and link it into the system VM list.
89840843Smsmith** Initializes the VM and binds default sized stacks to it. Returns the
89940843Smsmith** address of the VM, or NULL if an error occurs.
90040843Smsmith** Precondition: successful execution of ficlInitSystem
90140843Smsmith*/
90240843SmsmithFICL_VM   *ficlNewVM(void);
90340843Smsmith
90440843Smsmith/*
90560959Sdcs** Force deletion of a VM. You do not need to do this
90660959Sdcs** unless you're creating and discarding a lot of VMs.
90760959Sdcs** For systems that use a constant pool of VMs for the life
90860959Sdcs** of the system, ficltermSystem takes care of VM cleanup
90960959Sdcs** automatically.
91060959Sdcs*/
91160959Sdcsvoid ficlFreeVM(FICL_VM *pVM);
91260959Sdcs
91360959Sdcs
91460959Sdcs/*
91551786Sdcs** Set the stack sizes (return and parameter) to be used for all
91651786Sdcs** subsequently created VMs. Returns actual stack size to be used.
91751786Sdcs*/
91851786Sdcsint ficlSetStackSize(int nStackCells);
91951786Sdcs
92051786Sdcs/*
92140843Smsmith** Returns the address of the most recently defined word in the system
92240843Smsmith** dictionary with the given name, or NULL if no match.
92340843Smsmith** Precondition: successful execution of ficlInitSystem
92440843Smsmith*/
92540843SmsmithFICL_WORD *ficlLookup(char *name);
92640843Smsmith
92740843Smsmith/*
92840843Smsmith** f i c l G e t D i c t
92940843Smsmith** Utility function - returns the address of the system dictionary.
93040843Smsmith** Precondition: successful execution of ficlInitSystem
93140843Smsmith*/
93240843SmsmithFICL_DICT *ficlGetDict(void);
93340843SmsmithFICL_DICT *ficlGetEnv(void);
93461182Sdcsvoid       ficlSetEnv(char *name, FICL_UNS value);
93561182Sdcsvoid       ficlSetEnvD(char *name, FICL_UNS hi, FICL_UNS lo);
93640843Smsmith#if FICL_WANT_LOCALS
93740843SmsmithFICL_DICT *ficlGetLoc(void);
93840843Smsmith#endif
93940843Smsmith/*
94040843Smsmith** f i c l B u i l d
94140843Smsmith** Builds a word into the system default dictionary in a thread-safe way.
94240843Smsmith** Preconditions: system must be initialized, and there must
94340843Smsmith** be enough space for the new word's header! Operation is
94440843Smsmith** controlled by ficlLockDictionary, so any initialization
94540843Smsmith** required by your version of the function (if you "overrode"
94640843Smsmith** it) must be complete at this point.
94740843Smsmith** Parameters:
94840843Smsmith** name  -- the name of the word to be built
94940843Smsmith** code  -- code to execute when the word is invoked - must take a single param
95040843Smsmith**          pointer to a FICL_VM
95140843Smsmith** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR!
95240843Smsmith**          Most words can use FW_DEFAULT.
95340843Smsmith** nAllot - number of extra cells to allocate in the parameter area (usually zero)
95440843Smsmith*/
95540843Smsmithint        ficlBuild(char *name, FICL_CODE code, char flags);
95640843Smsmith
95740843Smsmith/*
95840843Smsmith** f i c l C o m p i l e C o r e
95940843Smsmith** Builds the ANS CORE wordset into the dictionary - called by
96040843Smsmith** ficlInitSystem - no need to waste dict space by doing it again.
96140843Smsmith*/
96276116Sdcsvoid       ficlCompileCore(FICL_SYSTEM *pSys);
96376116Sdcsvoid       ficlCompilePrefix(FICL_SYSTEM *pSys);
96476116Sdcsvoid       ficlCompileSearch(FICL_SYSTEM *pSys);
96576116Sdcsvoid       ficlCompileSoftCore(FICL_SYSTEM *pSys);
96676116Sdcsvoid       ficlCompileTools(FICL_SYSTEM *pSys);
96776116Sdcs#if FICL_WANT_FLOAT
96876116Sdcsvoid       ficlCompileFloat(FICL_SYSTEM *pSys);
96976116Sdcs#endif
97076116Sdcs#if FICL_PLATFORM_EXTEND
97176116Sdcsvoid       ficlCompilePlatform(FICL_SYSTEM *pSys);
97276116Sdcs#endif
97340843Smsmith
97440843Smsmith/*
97540843Smsmith** from words.c...
97640843Smsmith*/
97740843Smsmithvoid       constantParen(FICL_VM *pVM);
97840843Smsmithvoid       twoConstParen(FICL_VM *pVM);
97976116Sdcsint        ficlParseNumber(FICL_VM *pVM, STRINGINFO si);
98076116Sdcsvoid       ficlTick(FICL_VM *pVM);
98176116Sdcsvoid       parseStepParen(FICL_VM *pVM);
98240843Smsmith
98343139Smsmith/*
98476116Sdcs** From tools.c
98576116Sdcs*/
98676116Sdcsint        isAFiclWord(FICL_WORD *pFW);
98776116Sdcs
98876116Sdcs/*
98976116Sdcs** The following supports SEE and the debugger.
99076116Sdcs*/
99176116Sdcstypedef enum
99276116Sdcs{
99376116Sdcs    BRANCH,
99476116Sdcs    COLON,
99576116Sdcs    CONSTANT,
99676116Sdcs    CREATE,
99776116Sdcs    DO,
99876116Sdcs    DOES,
99976116Sdcs    IF,
100076116Sdcs    LITERAL,
100176116Sdcs    LOOP,
100276116Sdcs    PLOOP,
100376116Sdcs    PRIMITIVE,
100476116Sdcs    QDO,
100576116Sdcs    STRINGLIT,
100676116Sdcs    USER,
100776116Sdcs    VARIABLE,
100876116Sdcs} WORDKIND;
100976116SdcsWORDKIND   ficlWordClassify(FICL_WORD *pFW);
101076116Sdcs
101176116Sdcs/*
101260014Sdcs** Dictionary on-demand resizing
101360014Sdcs*/
101477443Sdcsextern CELL dictThreshold;
101577443Sdcsextern CELL dictIncrease;
101660014Sdcs
101760014Sdcs/*
101861374Sdcs** Various FreeBSD goodies
101961374Sdcs*/
102061374Sdcs
102142679Sabial#if defined(__i386__) && !defined(TESTMAIN)
102242679Sabialextern void ficlOutb(FICL_VM *pVM);
102342679Sabialextern void ficlInb(FICL_VM *pVM);
102442634Sabial#endif
102542634Sabial
102661374Sdcs#if !defined(TESTMAIN)
102761374Sdcsextern void ficlSetenv(FICL_VM *pVM);
102861374Sdcsextern void ficlSetenvq(FICL_VM *pVM);
102961374Sdcsextern void ficlGetenv(FICL_VM *pVM);
103061374Sdcsextern void ficlUnsetenv(FICL_VM *pVM);
103161374Sdcsextern void ficlCopyin(FICL_VM *pVM);
103261374Sdcsextern void ficlCopyout(FICL_VM *pVM);
103365617Sdcsextern void ficlFindfile(FICL_VM *pVM);
103465617Sdcsextern void ficlPnpdevices(FICL_VM *pVM);
103565617Sdcsextern void ficlPnphandlers(FICL_VM *pVM);
103665617Sdcsextern void ficlCcall(FICL_VM *pVM);
103761374Sdcs#endif
103861374Sdcs
103940843Smsmith#ifdef __cplusplus
104040843Smsmith}
104140843Smsmith#endif
104240843Smsmith
104340843Smsmith#endif /* __FICL_H__ */
1044