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
694290Sdcs** Dedicated to RHS, in loving memory
794290Sdcs** $Id: ficl.h,v 1.18 2001/12/05 07:21:34 jsadler Exp $
840843Smsmith*******************************************************************/
940843Smsmith/*
1076116Sdcs** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
1176116Sdcs** All rights reserved.
1276116Sdcs**
1376116Sdcs** Get the latest Ficl release at http://ficl.sourceforge.net
1476116Sdcs**
1594290Sdcs** I am interested in hearing from anyone who uses ficl. If you have
1694290Sdcs** a problem, a success story, a defect, an enhancement request, or
1794290Sdcs** if you would like to contribute to the ficl release, please
1894290Sdcs** contact me by email at the address above.
1994290Sdcs**
2076116Sdcs** L I C E N S E  and  D I S C L A I M E R
2140843Smsmith**
2276116Sdcs** Redistribution and use in source and binary forms, with or without
2376116Sdcs** modification, are permitted provided that the following conditions
2476116Sdcs** are met:
2576116Sdcs** 1. Redistributions of source code must retain the above copyright
2676116Sdcs**    notice, this list of conditions and the following disclaimer.
2776116Sdcs** 2. Redistributions in binary form must reproduce the above copyright
2876116Sdcs**    notice, this list of conditions and the following disclaimer in the
2976116Sdcs**    documentation and/or other materials provided with the distribution.
3076116Sdcs**
3176116Sdcs** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
3276116Sdcs** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3376116Sdcs** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3476116Sdcs** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
3576116Sdcs** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3676116Sdcs** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3776116Sdcs** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3876116Sdcs** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3976116Sdcs** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4076116Sdcs** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4176116Sdcs** SUCH DAMAGE.
4240843Smsmith*/
4340843Smsmith
4451786Sdcs/* $FreeBSD$ */
4551786Sdcs
4640843Smsmith#if !defined (__FICL_H__)
4740843Smsmith#define __FICL_H__
4840843Smsmith/*
4940843Smsmith** Ficl (Forth-inspired command language) is an ANS Forth
5040843Smsmith** interpreter written in C. Unlike traditional Forths, this
5140843Smsmith** interpreter is designed to be embedded into other systems
5240843Smsmith** as a command/macro/development prototype language.
5340843Smsmith**
5440843Smsmith** Where Forths usually view themselves as the center of the system
5540843Smsmith** and expect the rest of the system to be coded in Forth, Ficl
5640843Smsmith** acts as a component of the system. It is easy to export
5740843Smsmith** code written in C or ASM to Ficl in the style of TCL, or to invoke
5840843Smsmith** Ficl code from a compiled module. This allows you to do incremental
5940843Smsmith** development in a way that combines the best features of threaded
6040843Smsmith** languages (rapid development, quick code/test/debug cycle,
6140843Smsmith** reasonably fast) with the best features of C (everyone knows it,
6240843Smsmith** easier to support large blocks of code, efficient, type checking).
6340843Smsmith**
6440843Smsmith** Ficl provides facilities for interoperating
6540843Smsmith** with programs written in C: C functions can be exported to Ficl,
6640843Smsmith** and Ficl commands can be executed via a C calling interface. The
6740843Smsmith** interpreter is re-entrant, so it can be used in multiple instances
6840843Smsmith** in a multitasking system. Unlike Forth, Ficl's outer interpreter
6940843Smsmith** expects a text block as input, and returns to the caller after each
7040843Smsmith** text block, so the "data pump" is somewhere in external code. This
7140843Smsmith** is more like TCL than Forth, which usually expcets to be at the center
7240843Smsmith** of the system, requesting input at its convenience. Each Ficl virtual
7340843Smsmith** machine can be bound to a different I/O channel, and is independent
7440843Smsmith** of all others in in the same address space except that all virtual
7540843Smsmith** machines share a common dictionary (a sort or open symbol table that
7640843Smsmith** defines all of the elements of the language).
7740843Smsmith**
7840843Smsmith** Code is written in ANSI C for portability.
7940843Smsmith**
8040843Smsmith** Summary of Ficl features and constraints:
8140843Smsmith** - Standard: Implements the ANSI Forth CORE word set and part
8240843Smsmith**   of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and
8340843Smsmith**   TOOLS EXT, LOCAL and LOCAL ext and various extras.
8440843Smsmith** - Extensible: you can export code written in Forth, C,
8540843Smsmith**   or asm in a straightforward way. Ficl provides open
8640843Smsmith**   facilities for extending the language in an application
8740843Smsmith**   specific way. You can even add new control structures!
8840843Smsmith** - Ficl and C can interact in two ways: Ficl can encapsulate
8940843Smsmith**   C code, or C code can invoke Ficl code.
9040843Smsmith** - Thread-safe, re-entrant: The shared system dictionary
9140843Smsmith**   uses a locking mechanism that you can either supply
9240843Smsmith**   or stub out to provide exclusive access. Each Ficl
9340843Smsmith**   virtual machine has an otherwise complete state, and
9440843Smsmith**   each can be bound to a separate I/O channel (or none at all).
9540843Smsmith** - Simple encapsulation into existing systems: a basic implementation
9640843Smsmith**   requires three function calls (see the example program in testmain.c).
9740843Smsmith** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data
9840843Smsmith**   environments. It does require somewhat more memory than a pure
9940843Smsmith**   ROM implementation because it builds its system dictionary in
10040843Smsmith**   RAM at startup time.
10140843Smsmith** - Written an ANSI C to be as simple as I can make it to understand,
10240843Smsmith**   support, debug, and port. Compiles without complaint at /Az /W4
10340843Smsmith**   (require ANSI C, max warnings) under Microsoft VC++ 5.
10440843Smsmith** - Does full 32 bit math (but you need to implement
10540843Smsmith**   two mixed precision math primitives (see sysdep.c))
10640843Smsmith** - Indirect threaded interpreter is not the fastest kind of
10740843Smsmith**   Forth there is (see pForth 68K for a really fast subroutine
10840843Smsmith**   threaded interpreter), but it's the cleanest match to a
10940843Smsmith**   pure C implementation.
11040843Smsmith**
11140843Smsmith** P O R T I N G   F i c l
11240843Smsmith**
11340843Smsmith** To install Ficl on your target system, you need an ANSI C compiler
11440843Smsmith** and its runtime library. Inspect the system dependent macros and
11540843Smsmith** functions in sysdep.h and sysdep.c and edit them to suit your
11640843Smsmith** system. For example, INT16 is a short on some compilers and an
11740843Smsmith** int on others. Check the default CELL alignment controlled by
11840843Smsmith** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree,
11940843Smsmith** ficlLockDictionary, and ficlTextOut to work with your operating system.
12040843Smsmith** Finally, use testmain.c as a guide to installing the Ficl system and
12140843Smsmith** one or more virtual machines into your code. You do not need to include
12240843Smsmith** testmain.c in your build.
12340843Smsmith**
12440843Smsmith** T o   D o   L i s t
12540843Smsmith**
12640843Smsmith** 1. Unimplemented system dependent CORE word: key
12794290Sdcs** 2. Ficl uses the PAD in some CORE words - this violates the standard,
12840843Smsmith**    but it's cleaner for a multithreaded system. I'll have to make a
12940843Smsmith**    second pad for reference by the word PAD to fix this.
13040843Smsmith**
13140843Smsmith** F o r   M o r e   I n f o r m a t i o n
13240843Smsmith**
13340843Smsmith** Web home of ficl
13494290Sdcs**   http://ficl.sourceforge.net
13540843Smsmith** Check this website for Forth literature (including the ANSI standard)
13640843Smsmith**   http://www.taygeta.com/forthlit.html
13740843Smsmith** and here for software and more links
13840843Smsmith**   http://www.taygeta.com/forth.html
13940843Smsmith**
14040843Smsmith** Obvious Performance enhancement opportunities
14140843Smsmith** Compile speed
14240843Smsmith** - work on interpret speed
14340843Smsmith** - turn off locals (FICL_WANT_LOCALS)
14440843Smsmith** Interpret speed
14540843Smsmith** - Change inner interpreter (and everything else)
14640843Smsmith**   so that a definition is a list of pointers to functions
14740843Smsmith**   and inline data rather than pointers to words. This gets
14840843Smsmith**   rid of vm->runningWord and a level of indirection in the
14940843Smsmith**   inner loop. I'll look at it for ficl 3.0
15040843Smsmith** - Make the main hash table a bigger prime (HASHSIZE)
15140843Smsmith** - FORGET about twiddling the hash function - my experience is
15240843Smsmith**   that that is a waste of time.
15394290Sdcs** - Eliminate the need to pass the pVM parameter on the stack
15440843Smsmith**   by dedicating a register to it. Most words need access to the
15540843Smsmith**   vm, but the parameter passing overhead can be reduced. One way
15640843Smsmith**   requires that the host OS have a task switch callout. Create
15740843Smsmith**   a global variable for the running VM and refer to it in words
15840843Smsmith**   that need VM access. Alternative: use thread local storage.
15940843Smsmith**   For single threaded implementations, you can just use a global.
16040843Smsmith**   The first two solutions create portability problems, so I
16140843Smsmith**   haven't considered doing them. Another possibility is to
16240843Smsmith**   declare the pVm parameter to be "register", and hope the compiler
16340843Smsmith**   pays attention.
16440843Smsmith**
16540843Smsmith*/
16640843Smsmith
16740843Smsmith/*
16840843Smsmith** Revision History:
16951786Sdcs**
17051786Sdcs** 15 Apr 1999 (sadler) Merged FreeBSD changes for exception wordset and
17151786Sdcs** counted strings in ficlExec.
17243078Smsmith** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an
17343078Smsmith** "end" field, and all words respect this. ficlExec is passed a "size"
17443078Smsmith** of TIB, as well as vmPushTib. This size is used to calculate the "end"
17543078Smsmith** of the string, ie, base+size. If the size is not known, pass -1.
17643078Smsmith**
17743078Smsmith** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing
17843078Smsmith** words has been modified to conform to EXCEPTION EXT word set.
17943078Smsmith**
18040843Smsmith** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT,
18140843Smsmith**  SEARCH / SEARCH EXT, TOOLS / TOOLS EXT.
18240843Smsmith**  Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD,
18340843Smsmith**  EMPTY to clear stack.
18440843Smsmith**
18540843Smsmith** 29 jun 1998 (sadler) added variable sized hash table support
18640843Smsmith**  and ANS Forth optional SEARCH & SEARCH EXT word set.
18740843Smsmith** 26 May 1998 (sadler)
18840843Smsmith**  FICL_PROMPT macro
18940843Smsmith** 14 April 1998 (sadler) V1.04
19040843Smsmith**  Ficlwin: Windows version, Skip Carter's Linux port
19140843Smsmith** 5 March 1998 (sadler) V1.03
19240843Smsmith**  Bug fixes -- passes John Ryan's ANS test suite "core.fr"
19340843Smsmith**
19440843Smsmith** 24 February 1998 (sadler) V1.02
19540843Smsmith** -Fixed bugs in <# # #>
19640843Smsmith** -Changed FICL_WORD so that storage for the name characters
19740843Smsmith**  can be allocated from the dictionary as needed rather than
19840843Smsmith**  reserving 32 bytes in each word whether needed or not -
19940843Smsmith**  this saved 50% of the dictionary storage requirement.
20040843Smsmith** -Added words in testmain for Win32 functions system,chdir,cwd,
20140843Smsmith**  also added a word that loads and evaluates a file.
20240843Smsmith**
20340843Smsmith** December 1997 (sadler)
20440843Smsmith** -Added VM_RESTART exception handling in ficlExec -- this lets words
20540843Smsmith**  that require additional text to succeed (like :, create, variable...)
20640843Smsmith**  recover gracefully from an empty input buffer rather than emitting
20740843Smsmith**  an error message. Definitions can span multiple input blocks with
20840843Smsmith**  no restrictions.
20940843Smsmith** -Changed #include order so that <assert.h> is included in sysdep.h,
21040843Smsmith**  and sysdep is included in all other files. This lets you define
21140843Smsmith**  NDEBUG in sysdep.h to disable assertions if you want to.
21240843Smsmith** -Make PC specific system dependent code conditional on _M_IX86
21340843Smsmith**  defined so that ports can coexist in sysdep.h/sysdep.c
21440843Smsmith*/
21540843Smsmith
21640843Smsmith#ifdef __cplusplus
21740843Smsmithextern "C" {
21840843Smsmith#endif
21940843Smsmith
22040843Smsmith#include "sysdep.h"
22140843Smsmith#include <limits.h> /* UCHAR_MAX */
22240843Smsmith
22340843Smsmith/*
22440843Smsmith** Forward declarations... read on.
22540843Smsmith*/
22640843Smsmithstruct ficl_word;
22794290Sdcstypedef struct ficl_word FICL_WORD;
22840843Smsmithstruct vm;
22994290Sdcstypedef struct vm FICL_VM;
23040843Smsmithstruct ficl_dict;
23194290Sdcstypedef struct ficl_dict FICL_DICT;
23276116Sdcsstruct ficl_system;
23376116Sdcstypedef struct ficl_system FICL_SYSTEM;
23494290Sdcsstruct ficl_system_info;
23594290Sdcstypedef struct ficl_system_info FICL_SYSTEM_INFO;
23640843Smsmith
23740843Smsmith/*
23840843Smsmith** the Good Stuff starts here...
23940843Smsmith*/
240167850Sjkim#define FICL_VER        "3.03"
24194290Sdcs#define FICL_VER_MAJOR  3
242167850Sjkim#define FICL_VER_MINOR  3
24351786Sdcs#if !defined (FICL_PROMPT)
24451786Sdcs#define FICL_PROMPT "ok> "
24540949Smsmith#endif
24640843Smsmith
24740843Smsmith/*
24840843Smsmith** ANS Forth requires false to be zero, and true to be the ones
24940843Smsmith** complement of false... that unifies logical and bitwise operations
25040843Smsmith** nicely.
25140843Smsmith*/
25276116Sdcs#define FICL_TRUE  ((unsigned long)~(0L))
25340843Smsmith#define FICL_FALSE (0)
25440843Smsmith#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE)
25540843Smsmith
25640843Smsmith
25740843Smsmith/*
25840843Smsmith** A CELL is the main storage type. It must be large enough
25951786Sdcs** to contain a pointer or a scalar. In order to accommodate
26094290Sdcs** 32 bit and 64 bit processors, use abstract types for int,
26194290Sdcs** unsigned, and float.
26240843Smsmith*/
26340843Smsmithtypedef union _cell
26440843Smsmith{
26576116Sdcs    FICL_INT i;
26651786Sdcs    FICL_UNS u;
26776116Sdcs#if (FICL_WANT_FLOAT)
26876116Sdcs    FICL_FLOAT f;
26976116Sdcs#endif
27076116Sdcs    void *p;
27176116Sdcs    void (*fn)(void);
27240843Smsmith} CELL;
27340843Smsmith
27440843Smsmith/*
27594290Sdcs** LVALUEtoCELL does a little pointer trickery to cast any CELL sized
27640843Smsmith** lvalue (informal definition: an expression whose result has an
27740843Smsmith** address) to CELL. Remember that constants and casts are NOT
27840843Smsmith** themselves lvalues!
27940843Smsmith*/
28040843Smsmith#define LVALUEtoCELL(v) (*(CELL *)&v)
28140843Smsmith
28240843Smsmith/*
28340843Smsmith** PTRtoCELL is a cast through void * intended to satisfy the
28440843Smsmith** most outrageously pedantic compiler... (I won't mention
28540843Smsmith** its name)
28640843Smsmith*/
28740843Smsmith#define PTRtoCELL (CELL *)(void *)
28840843Smsmith#define PTRtoSTRING (FICL_STRING *)(void *)
28940843Smsmith
29040843Smsmith/*
29140843Smsmith** Strings in FICL are stored in Pascal style - with a count
29240843Smsmith** preceding the text. We'll also NULL-terminate them so that
29340843Smsmith** they work with the usual C lib string functions. (Belt &
29440843Smsmith** suspenders? You decide.)
29540843Smsmith** STRINGINFO hides the implementation with a couple of
29640843Smsmith** macros for use in internal routines.
29740843Smsmith*/
29840843Smsmith
29940843Smsmithtypedef unsigned char FICL_COUNT;
30040843Smsmith#define FICL_STRING_MAX UCHAR_MAX
30140843Smsmithtypedef struct _ficl_string
30240843Smsmith{
30340843Smsmith    FICL_COUNT count;
30440843Smsmith    char text[1];
30540843Smsmith} FICL_STRING;
30640843Smsmith
30740843Smsmithtypedef struct
30840843Smsmith{
30961182Sdcs    FICL_UNS count;
31040843Smsmith    char *cp;
31140843Smsmith} STRINGINFO;
31240843Smsmith
31340843Smsmith#define SI_COUNT(si) (si.count)
31440843Smsmith#define SI_PTR(si)   (si.cp)
31561182Sdcs#define SI_SETLEN(si, len) (si.count = (FICL_UNS)(len))
31640843Smsmith#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr))
31740843Smsmith/*
31840843Smsmith** Init a STRINGINFO from a pointer to NULL-terminated string
31940843Smsmith*/
32040843Smsmith#define SI_PSZ(si, psz) \
32140843Smsmith            {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);}
32240843Smsmith/*
32340843Smsmith** Init a STRINGINFO from a pointer to FICL_STRING
32440843Smsmith*/
32540843Smsmith#define SI_PFS(si, pfs) \
32640843Smsmith            {si.cp = pfs->text; si.count = pfs->count;}
32740843Smsmith
32840843Smsmith/*
32976116Sdcs** Ficl uses this little structure to hold the address of
33040843Smsmith** the block of text it's working on and an index to the next
33140843Smsmith** unconsumed character in the string. Traditionally, this is
33240843Smsmith** done by a Text Input Buffer, so I've called this struct TIB.
33343078Smsmith**
33443078Smsmith** Since this structure also holds the size of the input buffer,
33543078Smsmith** and since evaluate requires that, let's put the size here.
33643078Smsmith** The size is stored as an end-pointer because that is what the
33743078Smsmith** null-terminated string aware functions find most easy to deal
33843078Smsmith** with.
33943078Smsmith** Notice, though, that nobody really uses this except evaluate,
34043078Smsmith** so it might just be moved to FICL_VM instead. (sobral)
34140843Smsmith*/
34240843Smsmithtypedef struct
34340843Smsmith{
34461149Sdcs    FICL_INT index;
34543078Smsmith    char *end;
34640843Smsmith    char *cp;
34740843Smsmith} TIB;
34840843Smsmith
34940843Smsmith
35040843Smsmith/*
35140843Smsmith** Stacks get heavy use in Ficl and Forth...
35240843Smsmith** Each virtual machine implements two of them:
35340843Smsmith** one holds parameters (data), and the other holds return
35440843Smsmith** addresses and control flow information for the virtual
35540843Smsmith** machine. (Note: C's automatic stack is implicitly used,
35640843Smsmith** but not modeled because it doesn't need to be...)
35740843Smsmith** Here's an abstract type for a stack
35840843Smsmith*/
35940843Smsmithtypedef struct _ficlStack
36040843Smsmith{
36151786Sdcs    FICL_UNS nCells;    /* size of the stack */
36240843Smsmith    CELL *pFrame;       /* link reg for stack frame */
36340843Smsmith    CELL *sp;           /* stack pointer */
36476116Sdcs    CELL base[1];       /* Top of stack */
36540843Smsmith} FICL_STACK;
36640843Smsmith
36740843Smsmith/*
36840843Smsmith** Stack methods... many map closely to required Forth words.
36940843Smsmith*/
37094290SdcsFICL_STACK *stackCreate   (unsigned nCells);
37194290Sdcsvoid        stackDelete   (FICL_STACK *pStack);
37294290Sdcsint         stackDepth    (FICL_STACK *pStack);
37394290Sdcsvoid        stackDrop     (FICL_STACK *pStack, int n);
37494290SdcsCELL        stackFetch    (FICL_STACK *pStack, int n);
37594290SdcsCELL        stackGetTop   (FICL_STACK *pStack);
37694290Sdcsvoid        stackLink     (FICL_STACK *pStack, int nCells);
37794290Sdcsvoid        stackPick     (FICL_STACK *pStack, int n);
37894290SdcsCELL        stackPop      (FICL_STACK *pStack);
37994290Sdcsvoid       *stackPopPtr   (FICL_STACK *pStack);
38094290SdcsFICL_UNS    stackPopUNS   (FICL_STACK *pStack);
38194290SdcsFICL_INT    stackPopINT   (FICL_STACK *pStack);
38294290Sdcsvoid        stackPush     (FICL_STACK *pStack, CELL c);
38340843Smsmithvoid        stackPushPtr  (FICL_STACK *pStack, void *ptr);
38494290Sdcsvoid        stackPushUNS  (FICL_STACK *pStack, FICL_UNS u);
38594290Sdcsvoid        stackPushINT  (FICL_STACK *pStack, FICL_INT i);
38694290Sdcsvoid        stackReset    (FICL_STACK *pStack);
38794290Sdcsvoid        stackRoll     (FICL_STACK *pStack, int n);
38894290Sdcsvoid        stackSetTop   (FICL_STACK *pStack, CELL c);
38994290Sdcsvoid        stackStore    (FICL_STACK *pStack, int n, CELL c);
39094290Sdcsvoid        stackUnlink   (FICL_STACK *pStack);
39140843Smsmith
39276116Sdcs#if (FICL_WANT_FLOAT)
39376116Sdcsfloat       stackPopFloat (FICL_STACK *pStack);
39494290Sdcsvoid        stackPushFloat(FICL_STACK *pStack, FICL_FLOAT f);
39576116Sdcs#endif
39676116Sdcs
39776116Sdcs/*
39876116Sdcs** Shortcuts (Guy Carver)
39976116Sdcs*/
40094290Sdcs#define PUSHPTR(p)   stackPushPtr(pVM->pStack,p)
40194290Sdcs#define PUSHUNS(u)   stackPushUNS(pVM->pStack,u)
40294290Sdcs#define PUSHINT(i)   stackPushINT(pVM->pStack,i)
40394290Sdcs#define PUSHFLOAT(f) stackPushFloat(pVM->fStack,f)
40494290Sdcs#define PUSH(c)      stackPush(pVM->pStack,c)
40594290Sdcs#define POPPTR()     stackPopPtr(pVM->pStack)
40694290Sdcs#define POPUNS()     stackPopUNS(pVM->pStack)
40794290Sdcs#define POPINT()     stackPopINT(pVM->pStack)
40894290Sdcs#define POPFLOAT()   stackPopFloat(pVM->fStack)
40994290Sdcs#define POP()        stackPop(pVM->pStack)
41094290Sdcs#define GETTOP()     stackGetTop(pVM->pStack)
41194290Sdcs#define SETTOP(c)    stackSetTop(pVM->pStack,LVALUEtoCELL(c))
41294290Sdcs#define GETTOPF()    stackGetTop(pVM->fStack)
41394290Sdcs#define SETTOPF(c)   stackSetTop(pVM->fStack,LVALUEtoCELL(c))
41494290Sdcs#define STORE(n,c)   stackStore(pVM->pStack,n,LVALUEtoCELL(c))
41594290Sdcs#define DEPTH()      stackDepth(pVM->pStack)
41694290Sdcs#define DROP(n)      stackDrop(pVM->pStack,n)
41794290Sdcs#define DROPF(n)     stackDrop(pVM->fStack,n)
41894290Sdcs#define FETCH(n)     stackFetch(pVM->pStack,n)
41994290Sdcs#define PICK(n)      stackPick(pVM->pStack,n)
42094290Sdcs#define PICKF(n)     stackPick(pVM->fStack,n)
42194290Sdcs#define ROLL(n)      stackRoll(pVM->pStack,n)
42294290Sdcs#define ROLLF(n)     stackRoll(pVM->fStack,n)
42376116Sdcs
42440843Smsmith/*
42540843Smsmith** The virtual machine (VM) contains the state for one interpreter.
42640843Smsmith** Defined operations include:
42740843Smsmith** Create & initialize
42840843Smsmith** Delete
42940843Smsmith** Execute a block of text
43040843Smsmith** Parse a word out of the input stream
43140843Smsmith** Call return, and branch
43240843Smsmith** Text output
43340843Smsmith** Throw an exception
43440843Smsmith*/
43540843Smsmith
43694290Sdcstypedef FICL_WORD ** IPTYPE; /* the VM's instruction pointer */
43740843Smsmith
43840843Smsmith/*
43940843Smsmith** Each VM has a placeholder for an output function -
44040843Smsmith** this makes it possible to have each VM do I/O
44140843Smsmith** through a different device. If you specify no
44240843Smsmith** OUTFUNC, it defaults to ficlTextOut.
44340843Smsmith*/
44494290Sdcstypedef void (*OUTFUNC)(FICL_VM *pVM, char *text, int fNewline);
44540843Smsmith
44640843Smsmith/*
44740843Smsmith** Each VM operates in one of two non-error states: interpreting
44840843Smsmith** or compiling. When interpreting, words are simply executed.
44940843Smsmith** When compiling, most words in the input stream have their
45040843Smsmith** addresses inserted into the word under construction. Some words
45140843Smsmith** (known as IMMEDIATE) are executed in the compile state, too.
45240843Smsmith*/
45340843Smsmith/* values of STATE */
45440843Smsmith#define INTERPRET 0
45540843Smsmith#define COMPILE   1
45640843Smsmith
45740843Smsmith/*
45840843Smsmith** The pad is a small scratch area for text manipulation. ANS Forth
45940843Smsmith** requires it to hold at least 84 characters.
46040843Smsmith*/
46140843Smsmith#if !defined nPAD
46240843Smsmith#define nPAD 256
46340843Smsmith#endif
46440843Smsmith
46540843Smsmith/*
46640843Smsmith** ANS Forth requires that a word's name contain {1..31} characters.
46740843Smsmith*/
46840843Smsmith#if !defined nFICLNAME
46976116Sdcs#define nFICLNAME       31
47040843Smsmith#endif
47140843Smsmith
47240843Smsmith/*
47340843Smsmith** OK - now we can really define the VM...
47440843Smsmith*/
47594290Sdcsstruct vm
47640843Smsmith{
47776116Sdcs    FICL_SYSTEM    *pSys;       /* Which system this VM belongs to  */
47894290Sdcs    FICL_VM        *link;       /* Ficl keeps a VM list for simple teardown */
47940843Smsmith    jmp_buf        *pState;     /* crude exception mechanism...     */
48040843Smsmith    OUTFUNC         textOut;    /* Output callback - see sysdep.c   */
48194290Sdcs    void *          pExtend;    /* vm extension pointer for app use - initialized from FICL_SYSTEM */
48240843Smsmith    short           fRestart;   /* Set TRUE to restart runningWord  */
48340843Smsmith    IPTYPE          ip;         /* instruction pointer              */
48494290Sdcs    FICL_WORD      *runningWord;/* address of currently running word (often just *(ip-1) ) */
48561182Sdcs    FICL_UNS        state;      /* compiling or interpreting        */
48661182Sdcs    FICL_UNS        base;       /* number conversion base           */
48740843Smsmith    FICL_STACK     *pStack;     /* param stack                      */
48840843Smsmith    FICL_STACK     *rStack;     /* return stack                     */
48976116Sdcs#if FICL_WANT_FLOAT
49076116Sdcs    FICL_STACK     *fStack;     /* float stack (optional)           */
49176116Sdcs#endif
49294290Sdcs    CELL            sourceID;   /* -1 if EVALUATE, 0 if normal input */
49340843Smsmith    TIB             tib;        /* address of incoming text string  */
49440843Smsmith#if FICL_WANT_USER
49540843Smsmith    CELL            user[FICL_USER_CELLS];
49640843Smsmith#endif
49740843Smsmith    char            pad[nPAD];  /* the scratch area (see above)     */
49894290Sdcs};
49940843Smsmith
50040843Smsmith/*
50140843Smsmith** A FICL_CODE points to a function that gets called to help execute
50240843Smsmith** a word in the dictionary. It always gets passed a pointer to the
50340843Smsmith** running virtual machine, and from there it can get the address
50440843Smsmith** of the parameter area of the word it's supposed to operate on.
50540843Smsmith** For precompiled words, the code is all there is. For user defined
50640843Smsmith** words, the code assumes that the word's parameter area is a list
50740843Smsmith** of pointers to the code fields of other words to execute, and
50840843Smsmith** may also contain inline data. The first parameter is always
50940843Smsmith** a pointer to a code field.
51040843Smsmith*/
51140843Smsmithtypedef void (*FICL_CODE)(FICL_VM *pVm);
51240843Smsmith
51351786Sdcs#if 0
51451786Sdcs#define VM_ASSERT(pVM) assert((*(pVM->ip - 1)) == pVM->runningWord)
51551786Sdcs#else
51651786Sdcs#define VM_ASSERT(pVM)
51751786Sdcs#endif
51851786Sdcs
51940843Smsmith/*
52040843Smsmith** Ficl models memory as a contiguous space divided into
52140843Smsmith** words in a linked list called the dictionary.
52240843Smsmith** A FICL_WORD starts each entry in the list.
52340843Smsmith** Version 1.02: space for the name characters is allotted from
52494290Sdcs** the dictionary ahead of the word struct, rather than using
52594290Sdcs** a fixed size array for each name.
52640843Smsmith*/
52794290Sdcsstruct ficl_word
52840843Smsmith{
52940843Smsmith    struct ficl_word *link;     /* Previous word in the dictionary      */
53040843Smsmith    UNS16 hash;
53140843Smsmith    UNS8 flags;                 /* Immediate, Smudge, Compile-only      */
53240843Smsmith    FICL_COUNT nName;           /* Number of chars in word name         */
53340843Smsmith    char *name;                 /* First nFICLNAME chars of word name   */
53440843Smsmith    FICL_CODE code;             /* Native code to execute the word      */
53540843Smsmith    CELL param[1];              /* First data cell of the word          */
53694290Sdcs};
53740843Smsmith
53840843Smsmith/*
53940843Smsmith** Worst-case size of a word header: nFICLNAME chars in name
54040843Smsmith*/
54140843Smsmith#define CELLS_PER_WORD  \
54240843Smsmith    ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \
54340843Smsmith                          / (sizeof (CELL)) )
54440843Smsmith
54540843Smsmithint wordIsImmediate(FICL_WORD *pFW);
54640843Smsmithint wordIsCompileOnly(FICL_WORD *pFW);
54740843Smsmith
54840843Smsmith/* flag values for word header */
54940843Smsmith#define FW_IMMEDIATE    1   /* execute me even if compiling */
55040843Smsmith#define FW_COMPILE      2   /* error if executed when not compiling */
55140843Smsmith#define FW_SMUDGE       4   /* definition in progress - hide me */
55294290Sdcs#define FW_ISOBJECT     8   /* word is an object or object member variable */
55340843Smsmith
55440843Smsmith#define FW_COMPIMMED    (FW_IMMEDIATE | FW_COMPILE)
55540843Smsmith#define FW_DEFAULT      0
55640843Smsmith
55740843Smsmith
55840843Smsmith/*
55940843Smsmith** Exit codes for vmThrow
56040843Smsmith*/
56151786Sdcs#define VM_INNEREXIT -256   /* tell ficlExecXT to exit inner loop */
56251786Sdcs#define VM_OUTOFTEXT -257   /* hungry - normal exit */
56351786Sdcs#define VM_RESTART   -258   /* word needs more text to succeed - re-run it */
56451786Sdcs#define VM_USEREXIT  -259   /* user wants to quit */
56551786Sdcs#define VM_ERREXIT   -260   /* interp found an error */
56676116Sdcs#define VM_BREAK     -261   /* debugger breakpoint */
56743078Smsmith#define VM_ABORT       -1   /* like errexit -- abort */
56843078Smsmith#define VM_ABORTQ      -2   /* like errexit -- abort" */
56943078Smsmith#define VM_QUIT       -56   /* like errexit, but leave pStack & base alone */
57040843Smsmith
57140843Smsmith
57240843Smsmithvoid        vmBranchRelative(FICL_VM *pVM, int offset);
57394290SdcsFICL_VM *   vmCreate       (FICL_VM *pVM, unsigned nPStack, unsigned nRStack);
57494290Sdcsvoid        vmDelete       (FICL_VM *pVM);
57594290Sdcsvoid        vmExecute      (FICL_VM *pVM, FICL_WORD *pWord);
57694290SdcsFICL_DICT  *vmGetDict      (FICL_VM *pVM);
57794290Sdcschar *      vmGetString    (FICL_VM *pVM, FICL_STRING *spDest, char delimiter);
57894290SdcsSTRINGINFO  vmGetWord      (FICL_VM *pVM);
57994290SdcsSTRINGINFO  vmGetWord0     (FICL_VM *pVM);
58094290Sdcsint         vmGetWordToPad (FICL_VM *pVM);
58194290SdcsSTRINGINFO  vmParseString  (FICL_VM *pVM, char delimiter);
58260959SdcsSTRINGINFO  vmParseStringEx(FICL_VM *pVM, char delimiter, char fSkipLeading);
58394290SdcsCELL        vmPop          (FICL_VM *pVM);
58494290Sdcsvoid        vmPush         (FICL_VM *pVM, CELL c);
58594290Sdcsvoid        vmPopIP        (FICL_VM *pVM);
58694290Sdcsvoid        vmPushIP       (FICL_VM *pVM, IPTYPE newIP);
58794290Sdcsvoid        vmQuit         (FICL_VM *pVM);
58894290Sdcsvoid        vmReset        (FICL_VM *pVM);
58994290Sdcsvoid        vmSetTextOut   (FICL_VM *pVM, OUTFUNC textOut);
59094290Sdcsvoid        vmTextOut      (FICL_VM *pVM, char *text, int fNewline);
59194290Sdcsvoid        vmTextOut      (FICL_VM *pVM, char *text, int fNewline);
59294290Sdcsvoid        vmThrow        (FICL_VM *pVM, int except);
59394290Sdcsvoid        vmThrowErr     (FICL_VM *pVM, char *fmt, ...);
59440843Smsmith
59551786Sdcs#define vmGetRunningWord(pVM) ((pVM)->runningWord)
59651786Sdcs
59751786Sdcs
59840843Smsmith/*
59951786Sdcs** The inner interpreter - coded as a macro (see note for
60051786Sdcs** INLINE_INNER_LOOP in sysdep.h for complaints about VC++ 5
60151786Sdcs*/
60260959Sdcs#define M_VM_STEP(pVM) \
60351786Sdcs        FICL_WORD *tempFW = *(pVM)->ip++; \
60451786Sdcs        (pVM)->runningWord = tempFW; \
60594290Sdcs        tempFW->code(pVM);
60651786Sdcs
60760959Sdcs#define M_INNER_LOOP(pVM) \
60860959Sdcs    for (;;)  { M_VM_STEP(pVM) }
60951786Sdcs
61060959Sdcs
61151786Sdcs#if INLINE_INNER_LOOP != 0
61251786Sdcs#define     vmInnerLoop(pVM) M_INNER_LOOP(pVM)
61351786Sdcs#else
61451786Sdcsvoid        vmInnerLoop(FICL_VM *pVM);
61551786Sdcs#endif
61651786Sdcs
61751786Sdcs/*
61840843Smsmith** vmCheckStack needs a vm pointer because it might have to say
61940843Smsmith** something if it finds a problem. Parms popCells and pushCells
62040843Smsmith** correspond to the number of parameters on the left and right of
62140843Smsmith** a word's stack effect comment.
62240843Smsmith*/
62340843Smsmithvoid        vmCheckStack(FICL_VM *pVM, int popCells, int pushCells);
62476116Sdcs#if FICL_WANT_FLOAT
62576116Sdcsvoid        vmCheckFStack(FICL_VM *pVM, int popCells, int pushCells);
62676116Sdcs#endif
62740843Smsmith
62840843Smsmith/*
62940843Smsmith** TIB access routines...
63040843Smsmith** ANS forth seems to require the input buffer to be represented
63140843Smsmith** as a pointer to the start of the buffer, and an index to the
63240843Smsmith** next character to read.
63340843Smsmith** PushTib points the VM to a new input string and optionally
63440843Smsmith**  returns a copy of the current state
63540843Smsmith** PopTib restores the TIB state given a saved TIB from PushTib
63640843Smsmith** GetInBuf returns a pointer to the next unused char of the TIB
63740843Smsmith*/
63894290Sdcsvoid        vmPushTib  (FICL_VM *pVM, char *text, FICL_INT nChars, TIB *pSaveTib);
63994290Sdcsvoid        vmPopTib   (FICL_VM *pVM, TIB *pTib);
64094290Sdcs#define     vmGetInBuf(pVM)      ((pVM)->tib.cp + (pVM)->tib.index)
64194290Sdcs#define     vmGetInBufLen(pVM)   ((pVM)->tib.end - (pVM)->tib.cp)
64294290Sdcs#define     vmGetInBufEnd(pVM)   ((pVM)->tib.end)
64376116Sdcs#define     vmGetTibIndex(pVM)    (pVM)->tib.index
64440843Smsmith#define     vmSetTibIndex(pVM, i) (pVM)->tib.index = i
64540843Smsmith#define     vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp
64640843Smsmith
64740843Smsmith/*
64840843Smsmith** Generally useful string manipulators omitted by ANSI C...
64940843Smsmith** ltoa complements strtol
65040843Smsmith*/
65140843Smsmith#if defined(_WIN32) && !FICL_MAIN
65240843Smsmith/* #SHEESH
65340843Smsmith** Why do Microsoft Meatballs insist on contaminating
65440843Smsmith** my namespace with their string functions???
65540843Smsmith*/
65640843Smsmith#pragma warning(disable: 4273)
65740843Smsmith#endif
65840843Smsmith
65951786Sdcsint        isPowerOfTwo(FICL_UNS u);
66051786Sdcs
66151786Sdcschar       *ltoa( FICL_INT value, char *string, int radix );
66251786Sdcschar       *ultoa(FICL_UNS value, char *string, int radix );
66340843Smsmithchar        digit_to_char(int value);
66440843Smsmithchar       *strrev( char *string );
66551786Sdcschar       *skipSpace(char *cp, char *end);
66640843Smsmithchar       *caseFold(char *cp);
66776116Sdcsint         strincmp(char *cp1, char *cp2, FICL_UNS count);
66840843Smsmith
66940843Smsmith#if defined(_WIN32) && !FICL_MAIN
67040843Smsmith#pragma warning(default: 4273)
67140843Smsmith#endif
67240843Smsmith
67340843Smsmith/*
67440843Smsmith** Ficl hash table - variable size.
67540843Smsmith** assert(size > 0)
67640843Smsmith** If size is 1, the table degenerates into a linked list.
67740843Smsmith** A WORDLIST (see the search order word set in DPANS) is
67840843Smsmith** just a pointer to a FICL_HASH in this implementation.
67940843Smsmith*/
68051786Sdcs#if !defined HASHSIZE /* Default size of hash table. For most uniform */
68176116Sdcs#define HASHSIZE 241  /*   performance, use a prime number!   */
68240843Smsmith#endif
68340843Smsmith
68440843Smsmithtypedef struct ficl_hash
68540843Smsmith{
68676116Sdcs    struct ficl_hash *link;  /* link to parent class wordlist for OO */
68776116Sdcs    char      *name;         /* optional pointer to \0 terminated wordlist name */
68876116Sdcs    unsigned   size;         /* number of buckets in the hash */
68940843Smsmith    FICL_WORD *table[1];
69040843Smsmith} FICL_HASH;
69140843Smsmith
69294290Sdcsvoid        hashForget    (FICL_HASH *pHash, void *where);
69394290SdcsUNS16       hashHashCode  (STRINGINFO si);
69440843Smsmithvoid        hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW);
69594290SdcsFICL_WORD  *hashLookup    (FICL_HASH *pHash, STRINGINFO si, UNS16 hashCode);
69694290Sdcsvoid        hashReset     (FICL_HASH *pHash);
69740843Smsmith
69840843Smsmith/*
69940843Smsmith** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's
70040843Smsmith** memory model. Description of fields:
70140843Smsmith**
70240843Smsmith** here -- points to the next free byte in the dictionary. This
70340843Smsmith**      pointer is forced to be CELL-aligned before a definition is added.
70440843Smsmith**      Do not assume any specific alignment otherwise - Use dictAlign().
70540843Smsmith**
70640843Smsmith** smudge -- pointer to word currently being defined (or last defined word)
70740843Smsmith**      If the definition completes successfully, the word will be
70840843Smsmith**      linked into the hash table. If unsuccessful, dictUnsmudge
70940843Smsmith**      uses this pointer to restore the previous state of the dictionary.
71040843Smsmith**      Smudge prevents unintentional recursion as a side-effect: the
71140843Smsmith**      dictionary search algo examines only completed definitions, so a
71240843Smsmith**      word cannot invoke itself by name. See the ficl word "recurse".
71340843Smsmith**      NOTE: smudge always points to the last word defined. IMMEDIATE
71440843Smsmith**      makes use of this fact. Smudge is initially NULL.
71540843Smsmith**
71640843Smsmith** pForthWords -- pointer to the default wordlist (FICL_HASH).
71740843Smsmith**      This is the initial compilation list, and contains all
71840843Smsmith**      ficl's precompiled words.
71940843Smsmith**
72040843Smsmith** pCompile -- compilation wordlist - initially equal to pForthWords
72140843Smsmith** pSearch  -- array of pointers to wordlists. Managed as a stack.
72240843Smsmith**      Highest index is the first list in the search order.
72340843Smsmith** nLists   -- number of lists in pSearch. nLists-1 is the highest
72440843Smsmith**      filled slot in pSearch, and points to the first wordlist
72540843Smsmith**      in the search order
72640843Smsmith** size -- number of cells in the dictionary (total)
72740843Smsmith** dict -- start of data area. Must be at the end of the struct.
72840843Smsmith*/
72994290Sdcsstruct ficl_dict
73040843Smsmith{
73140843Smsmith    CELL *here;
73240843Smsmith    FICL_WORD *smudge;
73340843Smsmith    FICL_HASH *pForthWords;
73440843Smsmith    FICL_HASH *pCompile;
73540843Smsmith    FICL_HASH *pSearch[FICL_DEFAULT_VOCS];
73640843Smsmith    int        nLists;
73740843Smsmith    unsigned   size;    /* Number of cells in dict (total)*/
73860014Sdcs    CELL       *dict;   /* Base of dictionary memory      */
73994290Sdcs};
74040843Smsmith
74140843Smsmithvoid       *alignPtr(void *ptr);
74240843Smsmithvoid        dictAbortDefinition(FICL_DICT *pDict);
74394290Sdcsvoid        dictAlign      (FICL_DICT *pDict);
74494290Sdcsint         dictAllot      (FICL_DICT *pDict, int n);
74594290Sdcsint         dictAllotCells (FICL_DICT *pDict, int nCells);
74694290Sdcsvoid        dictAppendCell (FICL_DICT *pDict, CELL c);
74794290Sdcsvoid        dictAppendChar (FICL_DICT *pDict, char c);
74894290SdcsFICL_WORD  *dictAppendWord (FICL_DICT *pDict,
74940843Smsmith                           char *name,
75040843Smsmith                           FICL_CODE pCode,
75140843Smsmith                           UNS8 flags);
75240843SmsmithFICL_WORD  *dictAppendWord2(FICL_DICT *pDict,
75340843Smsmith                           STRINGINFO si,
75440843Smsmith                           FICL_CODE pCode,
75540843Smsmith                           UNS8 flags);
75694290Sdcsvoid        dictAppendUNS  (FICL_DICT *pDict, FICL_UNS u);
75794290Sdcsint         dictCellsAvail (FICL_DICT *pDict);
75894290Sdcsint         dictCellsUsed  (FICL_DICT *pDict);
75994290Sdcsvoid        dictCheck      (FICL_DICT *pDict, FICL_VM *pVM, int n);
760209361Sbrianvoid        dictCheckThreshold(FICL_DICT* dp);
76140843SmsmithFICL_DICT  *dictCreate(unsigned nCELLS);
76240843SmsmithFICL_DICT  *dictCreateHashed(unsigned nCells, unsigned nHash);
76376116SdcsFICL_HASH  *dictCreateWordlist(FICL_DICT *dp, int nBuckets);
76494290Sdcsvoid        dictDelete     (FICL_DICT *pDict);
76594290Sdcsvoid        dictEmpty      (FICL_DICT *pDict, unsigned nHash);
76694290Sdcs#if FICL_WANT_FLOAT
76794290Sdcsvoid        dictHashSummary(FICL_VM *pVM);
76894290Sdcs#endif
76994290Sdcsint         dictIncludes   (FICL_DICT *pDict, void *p);
77094290SdcsFICL_WORD  *dictLookup     (FICL_DICT *pDict, STRINGINFO si);
77140843Smsmith#if FICL_WANT_LOCALS
77294290SdcsFICL_WORD  *ficlLookupLoc  (FICL_SYSTEM *pSys, STRINGINFO si);
77340843Smsmith#endif
77440843Smsmithvoid        dictResetSearchOrder(FICL_DICT *pDict);
77594290Sdcsvoid        dictSetFlags   (FICL_DICT *pDict, UNS8 set, UNS8 clr);
77640843Smsmithvoid        dictSetImmediate(FICL_DICT *pDict);
77794290Sdcsvoid        dictUnsmudge   (FICL_DICT *pDict);
77894290SdcsCELL       *dictWhere      (FICL_DICT *pDict);
77940843Smsmith
78040843Smsmith
78176116Sdcs/*
78276116Sdcs** P A R S E   S T E P
78376116Sdcs** (New for 2.05)
78476116Sdcs** See words.c: interpWord
78576116Sdcs** By default, ficl goes through two attempts to parse each token from its input
78676116Sdcs** stream: it first attempts to match it with a word in the dictionary, and
78776116Sdcs** if that fails, it attempts to convert it into a number. This mechanism is now
78876116Sdcs** extensible by additional steps. This allows extensions like floating point and
78976116Sdcs** double number support to be factored cleanly.
79076116Sdcs**
79176116Sdcs** Each parse step is a function that receives the next input token as a STRINGINFO.
79276116Sdcs** If the parse step matches the token, it must apply semantics to the token appropriate
79376116Sdcs** to the present value of VM.state (compiling or interpreting), and return FICL_TRUE.
79476116Sdcs** Otherwise it returns FICL_FALSE. See words.c: isNumber for an example
79576116Sdcs**
79676116Sdcs** Note: for the sake of efficiency, it's a good idea both to limit the number
79776116Sdcs** of parse steps and to code each parse step so that it rejects tokens that
79876116Sdcs** do not match as quickly as possible.
79976116Sdcs*/
80076116Sdcs
80176116Sdcstypedef int (*FICL_PARSE_STEP)(FICL_VM *pVM, STRINGINFO si);
80276116Sdcs
80340843Smsmith/*
80476116Sdcs** Appends a parse step function to the end of the parse list (see
80576116Sdcs** FICL_PARSE_STEP notes in ficl.h for details). Returns 0 if successful,
80676116Sdcs** nonzero if there's no more room in the list. Each parse step is a word in
80776116Sdcs** the dictionary. Precompiled parse steps can use (PARSE-STEP) as their
80876116Sdcs** CFA - see parenParseStep in words.c.
80976116Sdcs*/
81076116Sdcsint  ficlAddParseStep(FICL_SYSTEM *pSys, FICL_WORD *pFW); /* ficl.c */
81176116Sdcsvoid ficlAddPrecompiledParseStep(FICL_SYSTEM *pSys, char *name, FICL_PARSE_STEP pStep);
81276116Sdcsvoid ficlListParseSteps(FICL_VM *pVM);
81376116Sdcs
81476116Sdcs/*
81594290Sdcs** FICL_BREAKPOINT record.
81694290Sdcs** origXT - if NULL, this breakpoint is unused. Otherwise it stores the xt
81794290Sdcs** that the breakpoint overwrote. This is restored to the dictionary when the
81894290Sdcs** BP executes or gets cleared
81994290Sdcs** address - the location of the breakpoint (address of the instruction that
82094290Sdcs**           has been replaced with the breakpoint trap
82194290Sdcs** origXT  - The original contents of the location with the breakpoint
82294290Sdcs** Note: address is NULL when this breakpoint is empty
82394290Sdcs*/
82494290Sdcstypedef struct FICL_BREAKPOINT
82594290Sdcs{
82694290Sdcs    void      *address;
82794290Sdcs    FICL_WORD *origXT;
82894290Sdcs} FICL_BREAKPOINT;
82994290Sdcs
83094290Sdcs
83194290Sdcs/*
83276116Sdcs** F I C L _ S Y S T E M
83376116Sdcs** The top level data structure of the system - ficl_system ties a list of
83476116Sdcs** virtual machines with their corresponding dictionaries. Ficl 3.0 will
83576116Sdcs** support multiple Ficl systems, allowing multiple concurrent sessions
83676116Sdcs** to separate dictionaries with some constraints.
83776116Sdcs** The present model allows multiple sessions to one dictionary provided
83876116Sdcs** you implement ficlLockDictionary() as specified in sysdep.h
83994290Sdcs** Note: the pExtend pointer is there to provide context for applications. It is copied
84094290Sdcs** to each VM's pExtend field as that VM is created.
84176116Sdcs*/
84276116Sdcsstruct ficl_system
84376116Sdcs{
84476116Sdcs    FICL_SYSTEM *link;
84594290Sdcs    void *pExtend;      /* Initializes VM's pExtend pointer (for application use) */
84676116Sdcs    FICL_VM *vmList;
84776116Sdcs    FICL_DICT *dp;
84876116Sdcs    FICL_DICT *envp;
84976116Sdcs#ifdef FICL_WANT_LOCALS
85076116Sdcs    FICL_DICT *localp;
85176116Sdcs#endif
85276116Sdcs    FICL_WORD *pInterp[3];
85394290Sdcs    FICL_WORD *parseList[FICL_MAX_PARSE_STEPS];
85494290Sdcs	OUTFUNC    textOut;
85594290Sdcs
85694290Sdcs	FICL_WORD *pBranchParen;
85794290Sdcs	FICL_WORD *pDoParen;
85894290Sdcs	FICL_WORD *pDoesParen;
85994290Sdcs	FICL_WORD *pExitInner;
86094290Sdcs	FICL_WORD *pExitParen;
861167850Sjkim	FICL_WORD *pBranch0;
86294290Sdcs	FICL_WORD *pInterpret;
86394290Sdcs	FICL_WORD *pLitParen;
86494290Sdcs	FICL_WORD *pTwoLitParen;
86594290Sdcs	FICL_WORD *pLoopParen;
86694290Sdcs	FICL_WORD *pPLoopParen;
86794290Sdcs	FICL_WORD *pQDoParen;
86894290Sdcs	FICL_WORD *pSemiParen;
869167850Sjkim	FICL_WORD *pOfParen;
87094290Sdcs	FICL_WORD *pStore;
871167850Sjkim	FICL_WORD *pDrop;
87294290Sdcs	FICL_WORD *pCStringLit;
87394290Sdcs	FICL_WORD *pStringLit;
87494290Sdcs
87594290Sdcs#if FICL_WANT_LOCALS
87694290Sdcs	FICL_WORD *pGetLocalParen;
87794290Sdcs	FICL_WORD *pGet2LocalParen;
87894290Sdcs	FICL_WORD *pGetLocal0;
87994290Sdcs	FICL_WORD *pGetLocal1;
88094290Sdcs	FICL_WORD *pToLocalParen;
88194290Sdcs	FICL_WORD *pTo2LocalParen;
88294290Sdcs	FICL_WORD *pToLocal0;
88394290Sdcs	FICL_WORD *pToLocal1;
88494290Sdcs	FICL_WORD *pLinkParen;
88594290Sdcs	FICL_WORD *pUnLinkParen;
88694290Sdcs	FICL_INT   nLocals;
88794290Sdcs	CELL *pMarkLocals;
88894290Sdcs#endif
88994290Sdcs
89094290Sdcs	FICL_BREAKPOINT bpStep;
89176116Sdcs};
89276116Sdcs
89394290Sdcsstruct ficl_system_info
89494290Sdcs{
89594290Sdcs	int size;           /* structure size tag for versioning */
89694290Sdcs	int nDictCells;     /* Size of system's Dictionary */
89794290Sdcs	OUTFUNC textOut;    /* default textOut function */
89894290Sdcs	void *pExtend;      /* Initializes VM's pExtend pointer - for application use */
89994290Sdcs    int nEnvCells;      /* Size of Environment dictionary */
90094290Sdcs};
90194290Sdcs
90294290Sdcs
90394290Sdcs#define ficlInitInfo(x) { memset((x), 0, sizeof(FICL_SYSTEM_INFO)); \
90494290Sdcs         (x)->size = sizeof(FICL_SYSTEM_INFO); }
90594290Sdcs
90676116Sdcs/*
90740843Smsmith** External interface to FICL...
90840843Smsmith*/
90940843Smsmith/*
91040843Smsmith** f i c l I n i t S y s t e m
91140843Smsmith** Binds a global dictionary to the interpreter system and initializes
91240843Smsmith** the dict to contain the ANSI CORE wordset.
91394290Sdcs** You can specify the address and size of the allocated area.
91494290Sdcs** Using ficlInitSystemEx you can also specify the text output function.
91540843Smsmith** After that, ficl manages it.
91640843Smsmith** First step is to set up the static pointers to the area.
91740843Smsmith** Then write the "precompiled" portion of the dictionary in.
91840843Smsmith** The dictionary needs to be at least large enough to hold the
91940843Smsmith** precompiled part. Try 1K cells minimum. Use "words" to find
92040843Smsmith** out how much of the dictionary is used at any time.
92140843Smsmith*/
92294290SdcsFICL_SYSTEM *ficlInitSystemEx(FICL_SYSTEM_INFO *fsi);
92340843Smsmith
92494290Sdcs/* Deprecated call */
92594290SdcsFICL_SYSTEM *ficlInitSystem(int nDictCells);
92694290Sdcs
92740843Smsmith/*
92840843Smsmith** f i c l T e r m S y s t e m
92940843Smsmith** Deletes the system dictionary and all virtual machines that
93040843Smsmith** were created with ficlNewVM (see below). Call this function to
93140843Smsmith** reclaim all memory used by the dictionary and VMs.
93240843Smsmith*/
93394290Sdcsvoid       ficlTermSystem(FICL_SYSTEM *pSys);
93440843Smsmith
93540843Smsmith/*
93694290Sdcs** f i c l E v a l u a t e
93794290Sdcs** Evaluates a block of input text in the context of the
93894290Sdcs** specified interpreter. Also sets SOURCE-ID properly.
93994290Sdcs**
94094290Sdcs** PLEASE USE THIS FUNCTION when throwing a hard-coded
94194290Sdcs** string to the FICL interpreter.
94294290Sdcs*/
94394290Sdcsint        ficlEvaluate(FICL_VM *pVM, char *pText);
94494290Sdcs
94594290Sdcs/*
94640843Smsmith** f i c l E x e c
94740843Smsmith** Evaluates a block of input text in the context of the
94840843Smsmith** specified interpreter. Emits any requested output to the
94951786Sdcs** interpreter's output function. If the input string is NULL
95051786Sdcs** terminated, you can pass -1 as nChars rather than count it.
95140843Smsmith** Execution returns when the text block has been executed,
95240843Smsmith** or an error occurs.
95340843Smsmith** Returns one of the VM_XXXX codes defined in ficl.h:
95440843Smsmith** VM_OUTOFTEXT is the normal exit condition
95540843Smsmith** VM_ERREXIT means that the interp encountered a syntax error
95640843Smsmith**      and the vm has been reset to recover (some or all
95740843Smsmith**      of the text block got ignored
95840843Smsmith** VM_USEREXIT means that the user executed the "bye" command
95940843Smsmith**      to shut down the interpreter. This would be a good
96040843Smsmith**      time to delete the vm, etc -- or you can ignore this
96140843Smsmith**      signal.
96243078Smsmith** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"'
96343078Smsmith**      commands.
96440843Smsmith** Preconditions: successful execution of ficlInitSystem,
96540843Smsmith**      Successful creation and init of the VM by ficlNewVM (or equiv)
96694290Sdcs**
96794290Sdcs** If you call ficlExec() or one of its brothers, you MUST
96894290Sdcs** ensure pVM->sourceID was set to a sensible value.
96994290Sdcs** ficlExec() explicitly DOES NOT manage SOURCE-ID for you.
97040843Smsmith*/
97151786Sdcsint        ficlExec (FICL_VM *pVM, char *pText);
97261182Sdcsint        ficlExecC(FICL_VM *pVM, char *pText, FICL_INT nChars);
97351786Sdcsint        ficlExecXT(FICL_VM *pVM, FICL_WORD *pWord);
97440843Smsmith
97540843Smsmith/*
97640989Sjkh** ficlExecFD(FICL_VM *pVM, int fd);
97740989Sjkh * Evaluates text from file passed in via fd.
97840989Sjkh * Execution returns when all of file has been executed or an
97940989Sjkh * error occurs.
98040989Sjkh */
98140989Sjkhint        ficlExecFD(FICL_VM *pVM, int fd);
98240989Sjkh
98340989Sjkh/*
98440843Smsmith** Create a new VM from the heap, and link it into the system VM list.
98540843Smsmith** Initializes the VM and binds default sized stacks to it. Returns the
98640843Smsmith** address of the VM, or NULL if an error occurs.
98740843Smsmith** Precondition: successful execution of ficlInitSystem
98840843Smsmith*/
98994290SdcsFICL_VM   *ficlNewVM(FICL_SYSTEM *pSys);
99040843Smsmith
99140843Smsmith/*
99260959Sdcs** Force deletion of a VM. You do not need to do this
99360959Sdcs** unless you're creating and discarding a lot of VMs.
99460959Sdcs** For systems that use a constant pool of VMs for the life
99560959Sdcs** of the system, ficltermSystem takes care of VM cleanup
99660959Sdcs** automatically.
99760959Sdcs*/
99860959Sdcsvoid ficlFreeVM(FICL_VM *pVM);
99960959Sdcs
100060959Sdcs
100160959Sdcs/*
100251786Sdcs** Set the stack sizes (return and parameter) to be used for all
100351786Sdcs** subsequently created VMs. Returns actual stack size to be used.
100451786Sdcs*/
100551786Sdcsint ficlSetStackSize(int nStackCells);
100651786Sdcs
100751786Sdcs/*
100840843Smsmith** Returns the address of the most recently defined word in the system
100940843Smsmith** dictionary with the given name, or NULL if no match.
101040843Smsmith** Precondition: successful execution of ficlInitSystem
101140843Smsmith*/
101294290SdcsFICL_WORD *ficlLookup(FICL_SYSTEM *pSys, char *name);
101340843Smsmith
101440843Smsmith/*
101540843Smsmith** f i c l G e t D i c t
101640843Smsmith** Utility function - returns the address of the system dictionary.
101740843Smsmith** Precondition: successful execution of ficlInitSystem
101840843Smsmith*/
101994290SdcsFICL_DICT *ficlGetDict(FICL_SYSTEM *pSys);
102094290SdcsFICL_DICT *ficlGetEnv (FICL_SYSTEM *pSys);
102194290Sdcsvoid       ficlSetEnv (FICL_SYSTEM *pSys, char *name, FICL_UNS value);
102294290Sdcsvoid       ficlSetEnvD(FICL_SYSTEM *pSys, char *name, FICL_UNS hi, FICL_UNS lo);
102340843Smsmith#if FICL_WANT_LOCALS
102494290SdcsFICL_DICT *ficlGetLoc (FICL_SYSTEM *pSys);
102540843Smsmith#endif
102640843Smsmith/*
102740843Smsmith** f i c l B u i l d
102840843Smsmith** Builds a word into the system default dictionary in a thread-safe way.
102940843Smsmith** Preconditions: system must be initialized, and there must
103040843Smsmith** be enough space for the new word's header! Operation is
103140843Smsmith** controlled by ficlLockDictionary, so any initialization
103240843Smsmith** required by your version of the function (if you "overrode"
103340843Smsmith** it) must be complete at this point.
103440843Smsmith** Parameters:
103540843Smsmith** name  -- the name of the word to be built
103640843Smsmith** code  -- code to execute when the word is invoked - must take a single param
103740843Smsmith**          pointer to a FICL_VM
103840843Smsmith** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR!
103940843Smsmith**          Most words can use FW_DEFAULT.
104040843Smsmith** nAllot - number of extra cells to allocate in the parameter area (usually zero)
104140843Smsmith*/
104294290Sdcsint        ficlBuild(FICL_SYSTEM *pSys, char *name, FICL_CODE code, char flags);
104340843Smsmith
104440843Smsmith/*
104540843Smsmith** f i c l C o m p i l e C o r e
104640843Smsmith** Builds the ANS CORE wordset into the dictionary - called by
104740843Smsmith** ficlInitSystem - no need to waste dict space by doing it again.
104840843Smsmith*/
104976116Sdcsvoid       ficlCompileCore(FICL_SYSTEM *pSys);
105076116Sdcsvoid       ficlCompilePrefix(FICL_SYSTEM *pSys);
105176116Sdcsvoid       ficlCompileSearch(FICL_SYSTEM *pSys);
105276116Sdcsvoid       ficlCompileSoftCore(FICL_SYSTEM *pSys);
105376116Sdcsvoid       ficlCompileTools(FICL_SYSTEM *pSys);
105494290Sdcsvoid       ficlCompileFile(FICL_SYSTEM *pSys);
105576116Sdcs#if FICL_WANT_FLOAT
105676116Sdcsvoid       ficlCompileFloat(FICL_SYSTEM *pSys);
105794290Sdcsint        ficlParseFloatNumber( FICL_VM *pVM, STRINGINFO si ); /* float.c */
105876116Sdcs#endif
105976116Sdcs#if FICL_PLATFORM_EXTEND
106076116Sdcsvoid       ficlCompilePlatform(FICL_SYSTEM *pSys);
106176116Sdcs#endif
106294290Sdcsint        ficlParsePrefix(FICL_VM *pVM, STRINGINFO si);
106340843Smsmith
106440843Smsmith/*
106540843Smsmith** from words.c...
106640843Smsmith*/
106740843Smsmithvoid       constantParen(FICL_VM *pVM);
106840843Smsmithvoid       twoConstParen(FICL_VM *pVM);
106976116Sdcsint        ficlParseNumber(FICL_VM *pVM, STRINGINFO si);
107076116Sdcsvoid       ficlTick(FICL_VM *pVM);
107176116Sdcsvoid       parseStepParen(FICL_VM *pVM);
107240843Smsmith
107343139Smsmith/*
107476116Sdcs** From tools.c
107576116Sdcs*/
107694290Sdcsint        isAFiclWord(FICL_DICT *pd, FICL_WORD *pFW);
107776116Sdcs
107876116Sdcs/*
107976116Sdcs** The following supports SEE and the debugger.
108076116Sdcs*/
108176116Sdcstypedef enum
108276116Sdcs{
108376116Sdcs    BRANCH,
108476116Sdcs    COLON,
108576116Sdcs    CONSTANT,
108676116Sdcs    CREATE,
108776116Sdcs    DO,
108876116Sdcs    DOES,
108976116Sdcs    IF,
109076116Sdcs    LITERAL,
109176116Sdcs    LOOP,
1092167850Sjkim    OF,
109376116Sdcs    PLOOP,
109476116Sdcs    PRIMITIVE,
109576116Sdcs    QDO,
109676116Sdcs    STRINGLIT,
109794290Sdcs    CSTRINGLIT,
109894290Sdcs#if FICL_WANT_USER
109976116Sdcs    USER,
110094290Sdcs#endif
110176116Sdcs    VARIABLE,
110276116Sdcs} WORDKIND;
110394290Sdcs
110476116SdcsWORDKIND   ficlWordClassify(FICL_WORD *pFW);
110576116Sdcs
110676116Sdcs/*
110760014Sdcs** Dictionary on-demand resizing
110860014Sdcs*/
110977443Sdcsextern CELL dictThreshold;
111077443Sdcsextern CELL dictIncrease;
111160014Sdcs
111260014Sdcs/*
111361374Sdcs** Various FreeBSD goodies
111461374Sdcs*/
111561374Sdcs
111642679Sabial#if defined(__i386__) && !defined(TESTMAIN)
111742679Sabialextern void ficlOutb(FICL_VM *pVM);
111842679Sabialextern void ficlInb(FICL_VM *pVM);
111942634Sabial#endif
112042634Sabial
112161374Sdcsextern void ficlSetenv(FICL_VM *pVM);
112261374Sdcsextern void ficlSetenvq(FICL_VM *pVM);
112361374Sdcsextern void ficlGetenv(FICL_VM *pVM);
112461374Sdcsextern void ficlUnsetenv(FICL_VM *pVM);
112561374Sdcsextern void ficlCopyin(FICL_VM *pVM);
112661374Sdcsextern void ficlCopyout(FICL_VM *pVM);
112765617Sdcsextern void ficlFindfile(FICL_VM *pVM);
1128138223Sscottlextern void ficlCcall(FICL_VM *pVM);
1129138223Sscottl#if !defined(TESTMAIN)
113065617Sdcsextern void ficlPnpdevices(FICL_VM *pVM);
113165617Sdcsextern void ficlPnphandlers(FICL_VM *pVM);
113261374Sdcs#endif
113361374Sdcs
113494290Sdcs/*
113594290Sdcs** Used with File-Access wordset.
113694290Sdcs*/
113794290Sdcs#define FICL_FAM_READ	1
113894290Sdcs#define FICL_FAM_WRITE	2
113994290Sdcs#define FICL_FAM_APPEND	4
114094290Sdcs#define FICL_FAM_BINARY	8
114194290Sdcs
114294290Sdcs#define FICL_FAM_OPEN_MODE(fam)	((fam) & (FICL_FAM_READ | FICL_FAM_WRITE | FICL_FAM_APPEND))
114394290Sdcs
114494290Sdcs
114594290Sdcs#if (FICL_WANT_FILE)
114694290Sdcstypedef struct ficlFILE
114794290Sdcs{
114894290Sdcs	FILE *f;
114994290Sdcs	char filename[256];
115094290Sdcs} ficlFILE;
115194290Sdcs#endif
115294290Sdcs
115340843Smsmith#ifdef __cplusplus
115440843Smsmith}
115540843Smsmith#endif
115640843Smsmith
115740843Smsmith#endif /* __FICL_H__ */
1158