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