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