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