ficl.h revision 138223
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: head/sys/boot/ficl/ficl.h 138223 2004-11-30 11:35:30Z scottl $ */
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*/
24094290Sdcs#define FICL_VER        "3.02"
24194290Sdcs#define FICL_VER_MAJOR  3
24294290Sdcs#define FICL_VER_MINOR  2
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);
76040843SmsmithFICL_DICT  *dictCreate(unsigned nCELLS);
76140843SmsmithFICL_DICT  *dictCreateHashed(unsigned nCells, unsigned nHash);
76276116SdcsFICL_HASH  *dictCreateWordlist(FICL_DICT *dp, int nBuckets);
76394290Sdcsvoid        dictDelete     (FICL_DICT *pDict);
76494290Sdcsvoid        dictEmpty      (FICL_DICT *pDict, unsigned nHash);
76594290Sdcs#if FICL_WANT_FLOAT
76694290Sdcsvoid        dictHashSummary(FICL_VM *pVM);
76794290Sdcs#endif
76894290Sdcsint         dictIncludes   (FICL_DICT *pDict, void *p);
76994290SdcsFICL_WORD  *dictLookup     (FICL_DICT *pDict, STRINGINFO si);
77040843Smsmith#if FICL_WANT_LOCALS
77194290SdcsFICL_WORD  *ficlLookupLoc  (FICL_SYSTEM *pSys, STRINGINFO si);
77240843Smsmith#endif
77340843Smsmithvoid        dictResetSearchOrder(FICL_DICT *pDict);
77494290Sdcsvoid        dictSetFlags   (FICL_DICT *pDict, UNS8 set, UNS8 clr);
77540843Smsmithvoid        dictSetImmediate(FICL_DICT *pDict);
77694290Sdcsvoid        dictUnsmudge   (FICL_DICT *pDict);
77794290SdcsCELL       *dictWhere      (FICL_DICT *pDict);
77840843Smsmith
77940843Smsmith
78076116Sdcs/*
78176116Sdcs** P A R S E   S T E P
78276116Sdcs** (New for 2.05)
78376116Sdcs** See words.c: interpWord
78476116Sdcs** By default, ficl goes through two attempts to parse each token from its input
78576116Sdcs** stream: it first attempts to match it with a word in the dictionary, and
78676116Sdcs** if that fails, it attempts to convert it into a number. This mechanism is now
78776116Sdcs** extensible by additional steps. This allows extensions like floating point and
78876116Sdcs** double number support to be factored cleanly.
78976116Sdcs**
79076116Sdcs** Each parse step is a function that receives the next input token as a STRINGINFO.
79176116Sdcs** If the parse step matches the token, it must apply semantics to the token appropriate
79276116Sdcs** to the present value of VM.state (compiling or interpreting), and return FICL_TRUE.
79376116Sdcs** Otherwise it returns FICL_FALSE. See words.c: isNumber for an example
79476116Sdcs**
79576116Sdcs** Note: for the sake of efficiency, it's a good idea both to limit the number
79676116Sdcs** of parse steps and to code each parse step so that it rejects tokens that
79776116Sdcs** do not match as quickly as possible.
79876116Sdcs*/
79976116Sdcs
80076116Sdcstypedef int (*FICL_PARSE_STEP)(FICL_VM *pVM, STRINGINFO si);
80176116Sdcs
80240843Smsmith/*
80376116Sdcs** Appends a parse step function to the end of the parse list (see
80476116Sdcs** FICL_PARSE_STEP notes in ficl.h for details). Returns 0 if successful,
80576116Sdcs** nonzero if there's no more room in the list. Each parse step is a word in
80676116Sdcs** the dictionary. Precompiled parse steps can use (PARSE-STEP) as their
80776116Sdcs** CFA - see parenParseStep in words.c.
80876116Sdcs*/
80976116Sdcsint  ficlAddParseStep(FICL_SYSTEM *pSys, FICL_WORD *pFW); /* ficl.c */
81076116Sdcsvoid ficlAddPrecompiledParseStep(FICL_SYSTEM *pSys, char *name, FICL_PARSE_STEP pStep);
81176116Sdcsvoid ficlListParseSteps(FICL_VM *pVM);
81276116Sdcs
81376116Sdcs/*
81494290Sdcs** FICL_BREAKPOINT record.
81594290Sdcs** origXT - if NULL, this breakpoint is unused. Otherwise it stores the xt
81694290Sdcs** that the breakpoint overwrote. This is restored to the dictionary when the
81794290Sdcs** BP executes or gets cleared
81894290Sdcs** address - the location of the breakpoint (address of the instruction that
81994290Sdcs**           has been replaced with the breakpoint trap
82094290Sdcs** origXT  - The original contents of the location with the breakpoint
82194290Sdcs** Note: address is NULL when this breakpoint is empty
82294290Sdcs*/
82394290Sdcstypedef struct FICL_BREAKPOINT
82494290Sdcs{
82594290Sdcs    void      *address;
82694290Sdcs    FICL_WORD *origXT;
82794290Sdcs} FICL_BREAKPOINT;
82894290Sdcs
82994290Sdcs
83094290Sdcs/*
83176116Sdcs** F I C L _ S Y S T E M
83276116Sdcs** The top level data structure of the system - ficl_system ties a list of
83376116Sdcs** virtual machines with their corresponding dictionaries. Ficl 3.0 will
83476116Sdcs** support multiple Ficl systems, allowing multiple concurrent sessions
83576116Sdcs** to separate dictionaries with some constraints.
83676116Sdcs** The present model allows multiple sessions to one dictionary provided
83776116Sdcs** you implement ficlLockDictionary() as specified in sysdep.h
83894290Sdcs** Note: the pExtend pointer is there to provide context for applications. It is copied
83994290Sdcs** to each VM's pExtend field as that VM is created.
84076116Sdcs*/
84176116Sdcsstruct ficl_system
84276116Sdcs{
84376116Sdcs    FICL_SYSTEM *link;
84494290Sdcs    void *pExtend;      /* Initializes VM's pExtend pointer (for application use) */
84576116Sdcs    FICL_VM *vmList;
84676116Sdcs    FICL_DICT *dp;
84776116Sdcs    FICL_DICT *envp;
84876116Sdcs#ifdef FICL_WANT_LOCALS
84976116Sdcs    FICL_DICT *localp;
85076116Sdcs#endif
85176116Sdcs    FICL_WORD *pInterp[3];
85294290Sdcs    FICL_WORD *parseList[FICL_MAX_PARSE_STEPS];
85394290Sdcs	OUTFUNC    textOut;
85494290Sdcs
85594290Sdcs	FICL_WORD *pBranchParen;
85694290Sdcs	FICL_WORD *pDoParen;
85794290Sdcs	FICL_WORD *pDoesParen;
85894290Sdcs	FICL_WORD *pExitInner;
85994290Sdcs	FICL_WORD *pExitParen;
86094290Sdcs	FICL_WORD *pIfParen;
86194290Sdcs	FICL_WORD *pInterpret;
86294290Sdcs	FICL_WORD *pLitParen;
86394290Sdcs	FICL_WORD *pTwoLitParen;
86494290Sdcs	FICL_WORD *pLoopParen;
86594290Sdcs	FICL_WORD *pPLoopParen;
86694290Sdcs	FICL_WORD *pQDoParen;
86794290Sdcs	FICL_WORD *pSemiParen;
86894290Sdcs	FICL_WORD *pStore;
86994290Sdcs	FICL_WORD *pCStringLit;
87094290Sdcs	FICL_WORD *pStringLit;
87194290Sdcs
87294290Sdcs#if FICL_WANT_LOCALS
87394290Sdcs	FICL_WORD *pGetLocalParen;
87494290Sdcs	FICL_WORD *pGet2LocalParen;
87594290Sdcs	FICL_WORD *pGetLocal0;
87694290Sdcs	FICL_WORD *pGetLocal1;
87794290Sdcs	FICL_WORD *pToLocalParen;
87894290Sdcs	FICL_WORD *pTo2LocalParen;
87994290Sdcs	FICL_WORD *pToLocal0;
88094290Sdcs	FICL_WORD *pToLocal1;
88194290Sdcs	FICL_WORD *pLinkParen;
88294290Sdcs	FICL_WORD *pUnLinkParen;
88394290Sdcs	FICL_INT   nLocals;
88494290Sdcs	CELL *pMarkLocals;
88594290Sdcs#endif
88694290Sdcs
88794290Sdcs	FICL_BREAKPOINT bpStep;
88876116Sdcs};
88976116Sdcs
89094290Sdcsstruct ficl_system_info
89194290Sdcs{
89294290Sdcs	int size;           /* structure size tag for versioning */
89394290Sdcs	int nDictCells;     /* Size of system's Dictionary */
89494290Sdcs	OUTFUNC textOut;    /* default textOut function */
89594290Sdcs	void *pExtend;      /* Initializes VM's pExtend pointer - for application use */
89694290Sdcs    int nEnvCells;      /* Size of Environment dictionary */
89794290Sdcs};
89894290Sdcs
89994290Sdcs
90094290Sdcs#define ficlInitInfo(x) { memset((x), 0, sizeof(FICL_SYSTEM_INFO)); \
90194290Sdcs         (x)->size = sizeof(FICL_SYSTEM_INFO); }
90294290Sdcs
90376116Sdcs/*
90440843Smsmith** External interface to FICL...
90540843Smsmith*/
90640843Smsmith/*
90740843Smsmith** f i c l I n i t S y s t e m
90840843Smsmith** Binds a global dictionary to the interpreter system and initializes
90940843Smsmith** the dict to contain the ANSI CORE wordset.
91094290Sdcs** You can specify the address and size of the allocated area.
91194290Sdcs** Using ficlInitSystemEx you can also specify the text output function.
91240843Smsmith** After that, ficl manages it.
91340843Smsmith** First step is to set up the static pointers to the area.
91440843Smsmith** Then write the "precompiled" portion of the dictionary in.
91540843Smsmith** The dictionary needs to be at least large enough to hold the
91640843Smsmith** precompiled part. Try 1K cells minimum. Use "words" to find
91740843Smsmith** out how much of the dictionary is used at any time.
91840843Smsmith*/
91994290SdcsFICL_SYSTEM *ficlInitSystemEx(FICL_SYSTEM_INFO *fsi);
92040843Smsmith
92194290Sdcs/* Deprecated call */
92294290SdcsFICL_SYSTEM *ficlInitSystem(int nDictCells);
92394290Sdcs
92440843Smsmith/*
92540843Smsmith** f i c l T e r m S y s t e m
92640843Smsmith** Deletes the system dictionary and all virtual machines that
92740843Smsmith** were created with ficlNewVM (see below). Call this function to
92840843Smsmith** reclaim all memory used by the dictionary and VMs.
92940843Smsmith*/
93094290Sdcsvoid       ficlTermSystem(FICL_SYSTEM *pSys);
93140843Smsmith
93240843Smsmith/*
93394290Sdcs** f i c l E v a l u a t e
93494290Sdcs** Evaluates a block of input text in the context of the
93594290Sdcs** specified interpreter. Also sets SOURCE-ID properly.
93694290Sdcs**
93794290Sdcs** PLEASE USE THIS FUNCTION when throwing a hard-coded
93894290Sdcs** string to the FICL interpreter.
93994290Sdcs*/
94094290Sdcsint        ficlEvaluate(FICL_VM *pVM, char *pText);
94194290Sdcs
94294290Sdcs/*
94340843Smsmith** f i c l E x e c
94440843Smsmith** Evaluates a block of input text in the context of the
94540843Smsmith** specified interpreter. Emits any requested output to the
94651786Sdcs** interpreter's output function. If the input string is NULL
94751786Sdcs** terminated, you can pass -1 as nChars rather than count it.
94840843Smsmith** Execution returns when the text block has been executed,
94940843Smsmith** or an error occurs.
95040843Smsmith** Returns one of the VM_XXXX codes defined in ficl.h:
95140843Smsmith** VM_OUTOFTEXT is the normal exit condition
95240843Smsmith** VM_ERREXIT means that the interp encountered a syntax error
95340843Smsmith**      and the vm has been reset to recover (some or all
95440843Smsmith**      of the text block got ignored
95540843Smsmith** VM_USEREXIT means that the user executed the "bye" command
95640843Smsmith**      to shut down the interpreter. This would be a good
95740843Smsmith**      time to delete the vm, etc -- or you can ignore this
95840843Smsmith**      signal.
95943078Smsmith** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"'
96043078Smsmith**      commands.
96140843Smsmith** Preconditions: successful execution of ficlInitSystem,
96240843Smsmith**      Successful creation and init of the VM by ficlNewVM (or equiv)
96394290Sdcs**
96494290Sdcs** If you call ficlExec() or one of its brothers, you MUST
96594290Sdcs** ensure pVM->sourceID was set to a sensible value.
96694290Sdcs** ficlExec() explicitly DOES NOT manage SOURCE-ID for you.
96740843Smsmith*/
96851786Sdcsint        ficlExec (FICL_VM *pVM, char *pText);
96961182Sdcsint        ficlExecC(FICL_VM *pVM, char *pText, FICL_INT nChars);
97051786Sdcsint        ficlExecXT(FICL_VM *pVM, FICL_WORD *pWord);
97140843Smsmith
97240843Smsmith/*
97340989Sjkh** ficlExecFD(FICL_VM *pVM, int fd);
97440989Sjkh * Evaluates text from file passed in via fd.
97540989Sjkh * Execution returns when all of file has been executed or an
97640989Sjkh * error occurs.
97740989Sjkh */
97840989Sjkhint        ficlExecFD(FICL_VM *pVM, int fd);
97940989Sjkh
98040989Sjkh/*
98140843Smsmith** Create a new VM from the heap, and link it into the system VM list.
98240843Smsmith** Initializes the VM and binds default sized stacks to it. Returns the
98340843Smsmith** address of the VM, or NULL if an error occurs.
98440843Smsmith** Precondition: successful execution of ficlInitSystem
98540843Smsmith*/
98694290SdcsFICL_VM   *ficlNewVM(FICL_SYSTEM *pSys);
98740843Smsmith
98840843Smsmith/*
98960959Sdcs** Force deletion of a VM. You do not need to do this
99060959Sdcs** unless you're creating and discarding a lot of VMs.
99160959Sdcs** For systems that use a constant pool of VMs for the life
99260959Sdcs** of the system, ficltermSystem takes care of VM cleanup
99360959Sdcs** automatically.
99460959Sdcs*/
99560959Sdcsvoid ficlFreeVM(FICL_VM *pVM);
99660959Sdcs
99760959Sdcs
99860959Sdcs/*
99951786Sdcs** Set the stack sizes (return and parameter) to be used for all
100051786Sdcs** subsequently created VMs. Returns actual stack size to be used.
100151786Sdcs*/
100251786Sdcsint ficlSetStackSize(int nStackCells);
100351786Sdcs
100451786Sdcs/*
100540843Smsmith** Returns the address of the most recently defined word in the system
100640843Smsmith** dictionary with the given name, or NULL if no match.
100740843Smsmith** Precondition: successful execution of ficlInitSystem
100840843Smsmith*/
100994290SdcsFICL_WORD *ficlLookup(FICL_SYSTEM *pSys, char *name);
101040843Smsmith
101140843Smsmith/*
101240843Smsmith** f i c l G e t D i c t
101340843Smsmith** Utility function - returns the address of the system dictionary.
101440843Smsmith** Precondition: successful execution of ficlInitSystem
101540843Smsmith*/
101694290SdcsFICL_DICT *ficlGetDict(FICL_SYSTEM *pSys);
101794290SdcsFICL_DICT *ficlGetEnv (FICL_SYSTEM *pSys);
101894290Sdcsvoid       ficlSetEnv (FICL_SYSTEM *pSys, char *name, FICL_UNS value);
101994290Sdcsvoid       ficlSetEnvD(FICL_SYSTEM *pSys, char *name, FICL_UNS hi, FICL_UNS lo);
102040843Smsmith#if FICL_WANT_LOCALS
102194290SdcsFICL_DICT *ficlGetLoc (FICL_SYSTEM *pSys);
102240843Smsmith#endif
102340843Smsmith/*
102440843Smsmith** f i c l B u i l d
102540843Smsmith** Builds a word into the system default dictionary in a thread-safe way.
102640843Smsmith** Preconditions: system must be initialized, and there must
102740843Smsmith** be enough space for the new word's header! Operation is
102840843Smsmith** controlled by ficlLockDictionary, so any initialization
102940843Smsmith** required by your version of the function (if you "overrode"
103040843Smsmith** it) must be complete at this point.
103140843Smsmith** Parameters:
103240843Smsmith** name  -- the name of the word to be built
103340843Smsmith** code  -- code to execute when the word is invoked - must take a single param
103440843Smsmith**          pointer to a FICL_VM
103540843Smsmith** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR!
103640843Smsmith**          Most words can use FW_DEFAULT.
103740843Smsmith** nAllot - number of extra cells to allocate in the parameter area (usually zero)
103840843Smsmith*/
103994290Sdcsint        ficlBuild(FICL_SYSTEM *pSys, char *name, FICL_CODE code, char flags);
104040843Smsmith
104140843Smsmith/*
104240843Smsmith** f i c l C o m p i l e C o r e
104340843Smsmith** Builds the ANS CORE wordset into the dictionary - called by
104440843Smsmith** ficlInitSystem - no need to waste dict space by doing it again.
104540843Smsmith*/
104676116Sdcsvoid       ficlCompileCore(FICL_SYSTEM *pSys);
104776116Sdcsvoid       ficlCompilePrefix(FICL_SYSTEM *pSys);
104876116Sdcsvoid       ficlCompileSearch(FICL_SYSTEM *pSys);
104976116Sdcsvoid       ficlCompileSoftCore(FICL_SYSTEM *pSys);
105076116Sdcsvoid       ficlCompileTools(FICL_SYSTEM *pSys);
105194290Sdcsvoid       ficlCompileFile(FICL_SYSTEM *pSys);
105276116Sdcs#if FICL_WANT_FLOAT
105376116Sdcsvoid       ficlCompileFloat(FICL_SYSTEM *pSys);
105494290Sdcsint        ficlParseFloatNumber( FICL_VM *pVM, STRINGINFO si ); /* float.c */
105576116Sdcs#endif
105676116Sdcs#if FICL_PLATFORM_EXTEND
105776116Sdcsvoid       ficlCompilePlatform(FICL_SYSTEM *pSys);
105876116Sdcs#endif
105994290Sdcsint        ficlParsePrefix(FICL_VM *pVM, STRINGINFO si);
106040843Smsmith
106140843Smsmith/*
106240843Smsmith** from words.c...
106340843Smsmith*/
106440843Smsmithvoid       constantParen(FICL_VM *pVM);
106540843Smsmithvoid       twoConstParen(FICL_VM *pVM);
106676116Sdcsint        ficlParseNumber(FICL_VM *pVM, STRINGINFO si);
106776116Sdcsvoid       ficlTick(FICL_VM *pVM);
106876116Sdcsvoid       parseStepParen(FICL_VM *pVM);
106940843Smsmith
107043139Smsmith/*
107176116Sdcs** From tools.c
107276116Sdcs*/
107394290Sdcsint        isAFiclWord(FICL_DICT *pd, FICL_WORD *pFW);
107476116Sdcs
107576116Sdcs/*
107676116Sdcs** The following supports SEE and the debugger.
107776116Sdcs*/
107876116Sdcstypedef enum
107976116Sdcs{
108076116Sdcs    BRANCH,
108176116Sdcs    COLON,
108276116Sdcs    CONSTANT,
108376116Sdcs    CREATE,
108476116Sdcs    DO,
108576116Sdcs    DOES,
108676116Sdcs    IF,
108776116Sdcs    LITERAL,
108876116Sdcs    LOOP,
108976116Sdcs    PLOOP,
109076116Sdcs    PRIMITIVE,
109176116Sdcs    QDO,
109276116Sdcs    STRINGLIT,
109394290Sdcs    CSTRINGLIT,
109494290Sdcs#if FICL_WANT_USER
109576116Sdcs    USER,
109694290Sdcs#endif
109776116Sdcs    VARIABLE,
109876116Sdcs} WORDKIND;
109994290Sdcs
110076116SdcsWORDKIND   ficlWordClassify(FICL_WORD *pFW);
110176116Sdcs
110276116Sdcs/*
110360014Sdcs** Dictionary on-demand resizing
110460014Sdcs*/
110577443Sdcsextern CELL dictThreshold;
110677443Sdcsextern CELL dictIncrease;
110760014Sdcs
110860014Sdcs/*
110961374Sdcs** Various FreeBSD goodies
111061374Sdcs*/
111161374Sdcs
111242679Sabial#if defined(__i386__) && !defined(TESTMAIN)
111342679Sabialextern void ficlOutb(FICL_VM *pVM);
111442679Sabialextern void ficlInb(FICL_VM *pVM);
111542634Sabial#endif
111642634Sabial
111761374Sdcsextern void ficlSetenv(FICL_VM *pVM);
111861374Sdcsextern void ficlSetenvq(FICL_VM *pVM);
111961374Sdcsextern void ficlGetenv(FICL_VM *pVM);
112061374Sdcsextern void ficlUnsetenv(FICL_VM *pVM);
112161374Sdcsextern void ficlCopyin(FICL_VM *pVM);
112261374Sdcsextern void ficlCopyout(FICL_VM *pVM);
112365617Sdcsextern void ficlFindfile(FICL_VM *pVM);
1124138223Sscottlextern void ficlCcall(FICL_VM *pVM);
1125138223Sscottl#if !defined(TESTMAIN)
112665617Sdcsextern void ficlPnpdevices(FICL_VM *pVM);
112765617Sdcsextern void ficlPnphandlers(FICL_VM *pVM);
112861374Sdcs#endif
112961374Sdcs
113094290Sdcs/*
113194290Sdcs** Used with File-Access wordset.
113294290Sdcs*/
113394290Sdcs#define FICL_FAM_READ	1
113494290Sdcs#define FICL_FAM_WRITE	2
113594290Sdcs#define FICL_FAM_APPEND	4
113694290Sdcs#define FICL_FAM_BINARY	8
113794290Sdcs
113894290Sdcs#define FICL_FAM_OPEN_MODE(fam)	((fam) & (FICL_FAM_READ | FICL_FAM_WRITE | FICL_FAM_APPEND))
113994290Sdcs
114094290Sdcs
114194290Sdcs#if (FICL_WANT_FILE)
114294290Sdcstypedef struct ficlFILE
114394290Sdcs{
114494290Sdcs	FILE *f;
114594290Sdcs	char filename[256];
114694290Sdcs} ficlFILE;
114794290Sdcs#endif
114894290Sdcs
114940843Smsmith#ifdef __cplusplus
115040843Smsmith}
115140843Smsmith#endif
115240843Smsmith
115340843Smsmith#endif /* __FICL_H__ */
1154