ficl.h revision 42634
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 640843Smsmith** 740843Smsmith*******************************************************************/ 840843Smsmith/* 940843Smsmith** N O T I C E -- DISCLAIMER OF WARRANTY 1040843Smsmith** 1140843Smsmith** Ficl is freeware. Use it in any way that you like, with 1240843Smsmith** the understanding that the code is supported on a "best effort" 1340843Smsmith** basis only. 1440843Smsmith** 1540843Smsmith** Any third party may reproduce, distribute, or modify the ficl 1640843Smsmith** software code or any derivative works thereof without any 1740843Smsmith** compensation or license, provided that the author information 1840843Smsmith** and this disclaimer text are retained in the source code files. 1940843Smsmith** The ficl software code is provided on an "as is" basis without 2040843Smsmith** warranty of any kind, including, without limitation, the implied 2140843Smsmith** warranties of merchantability and fitness for a particular purpose 2240843Smsmith** and their equivalents under the laws of any jurisdiction. 2340843Smsmith** 2440843Smsmith** I am interested in hearing from anyone who uses ficl. If you have 2540843Smsmith** a problem, a success story, a defect, an enhancement request, or 2640843Smsmith** if you would like to contribute to the ficl release (yay!), please 2740843Smsmith** send me email at the address above. 2840843Smsmith*/ 2940843Smsmith 3040843Smsmith#if !defined (__FICL_H__) 3140843Smsmith#define __FICL_H__ 3240843Smsmith/* 3340843Smsmith** Ficl (Forth-inspired command language) is an ANS Forth 3440843Smsmith** interpreter written in C. Unlike traditional Forths, this 3540843Smsmith** interpreter is designed to be embedded into other systems 3640843Smsmith** as a command/macro/development prototype language. 3740843Smsmith** 3840843Smsmith** Where Forths usually view themselves as the center of the system 3940843Smsmith** and expect the rest of the system to be coded in Forth, Ficl 4040843Smsmith** acts as a component of the system. It is easy to export 4140843Smsmith** code written in C or ASM to Ficl in the style of TCL, or to invoke 4240843Smsmith** Ficl code from a compiled module. This allows you to do incremental 4340843Smsmith** development in a way that combines the best features of threaded 4440843Smsmith** languages (rapid development, quick code/test/debug cycle, 4540843Smsmith** reasonably fast) with the best features of C (everyone knows it, 4640843Smsmith** easier to support large blocks of code, efficient, type checking). 4740843Smsmith** 4840843Smsmith** Ficl provides facilities for interoperating 4940843Smsmith** with programs written in C: C functions can be exported to Ficl, 5040843Smsmith** and Ficl commands can be executed via a C calling interface. The 5140843Smsmith** interpreter is re-entrant, so it can be used in multiple instances 5240843Smsmith** in a multitasking system. Unlike Forth, Ficl's outer interpreter 5340843Smsmith** expects a text block as input, and returns to the caller after each 5440843Smsmith** text block, so the "data pump" is somewhere in external code. This 5540843Smsmith** is more like TCL than Forth, which usually expcets to be at the center 5640843Smsmith** of the system, requesting input at its convenience. Each Ficl virtual 5740843Smsmith** machine can be bound to a different I/O channel, and is independent 5840843Smsmith** of all others in in the same address space except that all virtual 5940843Smsmith** machines share a common dictionary (a sort or open symbol table that 6040843Smsmith** defines all of the elements of the language). 6140843Smsmith** 6240843Smsmith** Code is written in ANSI C for portability. 6340843Smsmith** 6440843Smsmith** Summary of Ficl features and constraints: 6540843Smsmith** - Standard: Implements the ANSI Forth CORE word set and part 6640843Smsmith** of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and 6740843Smsmith** TOOLS EXT, LOCAL and LOCAL ext and various extras. 6840843Smsmith** - Extensible: you can export code written in Forth, C, 6940843Smsmith** or asm in a straightforward way. Ficl provides open 7040843Smsmith** facilities for extending the language in an application 7140843Smsmith** specific way. You can even add new control structures! 7240843Smsmith** - Ficl and C can interact in two ways: Ficl can encapsulate 7340843Smsmith** C code, or C code can invoke Ficl code. 7440843Smsmith** - Thread-safe, re-entrant: The shared system dictionary 7540843Smsmith** uses a locking mechanism that you can either supply 7640843Smsmith** or stub out to provide exclusive access. Each Ficl 7740843Smsmith** virtual machine has an otherwise complete state, and 7840843Smsmith** each can be bound to a separate I/O channel (or none at all). 7940843Smsmith** - Simple encapsulation into existing systems: a basic implementation 8040843Smsmith** requires three function calls (see the example program in testmain.c). 8140843Smsmith** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data 8240843Smsmith** environments. It does require somewhat more memory than a pure 8340843Smsmith** ROM implementation because it builds its system dictionary in 8440843Smsmith** RAM at startup time. 8540843Smsmith** - Written an ANSI C to be as simple as I can make it to understand, 8640843Smsmith** support, debug, and port. Compiles without complaint at /Az /W4 8740843Smsmith** (require ANSI C, max warnings) under Microsoft VC++ 5. 8840843Smsmith** - Does full 32 bit math (but you need to implement 8940843Smsmith** two mixed precision math primitives (see sysdep.c)) 9040843Smsmith** - Indirect threaded interpreter is not the fastest kind of 9140843Smsmith** Forth there is (see pForth 68K for a really fast subroutine 9240843Smsmith** threaded interpreter), but it's the cleanest match to a 9340843Smsmith** pure C implementation. 9440843Smsmith** 9540843Smsmith** P O R T I N G F i c l 9640843Smsmith** 9740843Smsmith** To install Ficl on your target system, you need an ANSI C compiler 9840843Smsmith** and its runtime library. Inspect the system dependent macros and 9940843Smsmith** functions in sysdep.h and sysdep.c and edit them to suit your 10040843Smsmith** system. For example, INT16 is a short on some compilers and an 10140843Smsmith** int on others. Check the default CELL alignment controlled by 10240843Smsmith** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree, 10340843Smsmith** ficlLockDictionary, and ficlTextOut to work with your operating system. 10440843Smsmith** Finally, use testmain.c as a guide to installing the Ficl system and 10540843Smsmith** one or more virtual machines into your code. You do not need to include 10640843Smsmith** testmain.c in your build. 10740843Smsmith** 10840843Smsmith** T o D o L i s t 10940843Smsmith** 11040843Smsmith** 1. Unimplemented system dependent CORE word: key 11140843Smsmith** 2. Kludged CORE word: ACCEPT 11240843Smsmith** 3. Dictionary locking is full of holes - only one vm at a time 11340843Smsmith** can alter the dict. 11440843Smsmith** 4. Ficl uses the pad in CORE words - this violates the standard, 11540843Smsmith** but it's cleaner for a multithreaded system. I'll have to make a 11640843Smsmith** second pad for reference by the word PAD to fix this. 11740843Smsmith** 11840843Smsmith** F o r M o r e I n f o r m a t i o n 11940843Smsmith** 12040843Smsmith** Web home of ficl 12140843Smsmith** http://www.taygeta.com/forth/compilers 12240843Smsmith** Check this website for Forth literature (including the ANSI standard) 12340843Smsmith** http://www.taygeta.com/forthlit.html 12440843Smsmith** and here for software and more links 12540843Smsmith** http://www.taygeta.com/forth.html 12640843Smsmith** 12740843Smsmith** Obvious Performance enhancement opportunities 12840843Smsmith** Compile speed 12940843Smsmith** - work on interpret speed 13040843Smsmith** - turn off locals (FICL_WANT_LOCALS) 13140843Smsmith** Interpret speed 13240843Smsmith** - Change inner interpreter (and everything else) 13340843Smsmith** so that a definition is a list of pointers to functions 13440843Smsmith** and inline data rather than pointers to words. This gets 13540843Smsmith** rid of vm->runningWord and a level of indirection in the 13640843Smsmith** inner loop. I'll look at it for ficl 3.0 13740843Smsmith** - Make the main hash table a bigger prime (HASHSIZE) 13840843Smsmith** - FORGET about twiddling the hash function - my experience is 13940843Smsmith** that that is a waste of time. 14040843Smsmith** - eliminate the need to pass the pVM parameter on the stack 14140843Smsmith** by dedicating a register to it. Most words need access to the 14240843Smsmith** vm, but the parameter passing overhead can be reduced. One way 14340843Smsmith** requires that the host OS have a task switch callout. Create 14440843Smsmith** a global variable for the running VM and refer to it in words 14540843Smsmith** that need VM access. Alternative: use thread local storage. 14640843Smsmith** For single threaded implementations, you can just use a global. 14740843Smsmith** The first two solutions create portability problems, so I 14840843Smsmith** haven't considered doing them. Another possibility is to 14940843Smsmith** declare the pVm parameter to be "register", and hope the compiler 15040843Smsmith** pays attention. 15140843Smsmith** 15240843Smsmith*/ 15340843Smsmith 15440843Smsmith/* 15540843Smsmith** Revision History: 15640843Smsmith** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT, 15740843Smsmith** SEARCH / SEARCH EXT, TOOLS / TOOLS EXT. 15840843Smsmith** Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD, 15940843Smsmith** EMPTY to clear stack. 16040843Smsmith** 16140843Smsmith** 29 jun 1998 (sadler) added variable sized hash table support 16240843Smsmith** and ANS Forth optional SEARCH & SEARCH EXT word set. 16340843Smsmith** 26 May 1998 (sadler) 16440843Smsmith** FICL_PROMPT macro 16540843Smsmith** 14 April 1998 (sadler) V1.04 16640843Smsmith** Ficlwin: Windows version, Skip Carter's Linux port 16740843Smsmith** 5 March 1998 (sadler) V1.03 16840843Smsmith** Bug fixes -- passes John Ryan's ANS test suite "core.fr" 16940843Smsmith** 17040843Smsmith** 24 February 1998 (sadler) V1.02 17140843Smsmith** -Fixed bugs in <# # #> 17240843Smsmith** -Changed FICL_WORD so that storage for the name characters 17340843Smsmith** can be allocated from the dictionary as needed rather than 17440843Smsmith** reserving 32 bytes in each word whether needed or not - 17540843Smsmith** this saved 50% of the dictionary storage requirement. 17640843Smsmith** -Added words in testmain for Win32 functions system,chdir,cwd, 17740843Smsmith** also added a word that loads and evaluates a file. 17840843Smsmith** 17940843Smsmith** December 1997 (sadler) 18040843Smsmith** -Added VM_RESTART exception handling in ficlExec -- this lets words 18140843Smsmith** that require additional text to succeed (like :, create, variable...) 18240843Smsmith** recover gracefully from an empty input buffer rather than emitting 18340843Smsmith** an error message. Definitions can span multiple input blocks with 18440843Smsmith** no restrictions. 18540843Smsmith** -Changed #include order so that <assert.h> is included in sysdep.h, 18640843Smsmith** and sysdep is included in all other files. This lets you define 18740843Smsmith** NDEBUG in sysdep.h to disable assertions if you want to. 18840843Smsmith** -Make PC specific system dependent code conditional on _M_IX86 18940843Smsmith** defined so that ports can coexist in sysdep.h/sysdep.c 19040843Smsmith*/ 19140843Smsmith 19240843Smsmith#ifdef __cplusplus 19340843Smsmithextern "C" { 19440843Smsmith#endif 19540843Smsmith 19640843Smsmith#include "sysdep.h" 19740843Smsmith#include <limits.h> /* UCHAR_MAX */ 19840843Smsmith 19940843Smsmith/* 20040843Smsmith** Forward declarations... read on. 20140843Smsmith*/ 20240843Smsmithstruct ficl_word; 20340843Smsmithstruct vm; 20440843Smsmithstruct ficl_dict; 20540843Smsmith 20640843Smsmith/* 20740843Smsmith** the Good Stuff starts here... 20840843Smsmith*/ 20940949Smsmith#define FICL_VER "2.02" 21040977Sjkh#ifndef FICL_PROMPT 21140949Smsmith# define FICL_PROMPT "ok> " 21240949Smsmith#endif 21340843Smsmith 21440843Smsmith/* 21540843Smsmith** ANS Forth requires false to be zero, and true to be the ones 21640843Smsmith** complement of false... that unifies logical and bitwise operations 21740843Smsmith** nicely. 21840843Smsmith*/ 21940843Smsmith#define FICL_TRUE (0xffffffffL) 22040843Smsmith#define FICL_FALSE (0) 22140843Smsmith#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE) 22240843Smsmith 22340843Smsmith 22440843Smsmith/* 22540843Smsmith** A CELL is the main storage type. It must be large enough 22640843Smsmith** to contain a pointer or a scalar. Let's be picky and make 22740843Smsmith** a 32 bit cell explicitly... 22840843Smsmith*/ 22940843Smsmithtypedef union _cell 23040843Smsmith{ 23140843Smsmith INT32 i; 23240843Smsmith UNS32 u; 23340843Smsmith void *p; 23440843Smsmith} CELL; 23540843Smsmith 23640843Smsmith/* 23740843Smsmith** LVALUEtoCELL does a little pointer trickery to cast any 32 bit 23840843Smsmith** lvalue (informal definition: an expression whose result has an 23940843Smsmith** address) to CELL. Remember that constants and casts are NOT 24040843Smsmith** themselves lvalues! 24140843Smsmith*/ 24240843Smsmith#define LVALUEtoCELL(v) (*(CELL *)&v) 24340843Smsmith 24440843Smsmith/* 24540843Smsmith** PTRtoCELL is a cast through void * intended to satisfy the 24640843Smsmith** most outrageously pedantic compiler... (I won't mention 24740843Smsmith** its name) 24840843Smsmith*/ 24940843Smsmith#define PTRtoCELL (CELL *)(void *) 25040843Smsmith#define PTRtoSTRING (FICL_STRING *)(void *) 25140843Smsmith 25240843Smsmith/* 25340843Smsmith** Strings in FICL are stored in Pascal style - with a count 25440843Smsmith** preceding the text. We'll also NULL-terminate them so that 25540843Smsmith** they work with the usual C lib string functions. (Belt & 25640843Smsmith** suspenders? You decide.) 25740843Smsmith** STRINGINFO hides the implementation with a couple of 25840843Smsmith** macros for use in internal routines. 25940843Smsmith*/ 26040843Smsmith 26140843Smsmithtypedef unsigned char FICL_COUNT; 26240843Smsmith#define FICL_STRING_MAX UCHAR_MAX 26340843Smsmithtypedef struct _ficl_string 26440843Smsmith{ 26540843Smsmith FICL_COUNT count; 26640843Smsmith char text[1]; 26740843Smsmith} FICL_STRING; 26840843Smsmith 26940843Smsmithtypedef struct 27040843Smsmith{ 27140843Smsmith UNS32 count; 27240843Smsmith char *cp; 27340843Smsmith} STRINGINFO; 27440843Smsmith 27540843Smsmith#define SI_COUNT(si) (si.count) 27640843Smsmith#define SI_PTR(si) (si.cp) 27740843Smsmith#define SI_SETLEN(si, len) (si.count = (UNS32)(len)) 27840843Smsmith#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr)) 27940843Smsmith/* 28040843Smsmith** Init a STRINGINFO from a pointer to NULL-terminated string 28140843Smsmith*/ 28240843Smsmith#define SI_PSZ(si, psz) \ 28340843Smsmith {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);} 28440843Smsmith/* 28540843Smsmith** Init a STRINGINFO from a pointer to FICL_STRING 28640843Smsmith*/ 28740843Smsmith#define SI_PFS(si, pfs) \ 28840843Smsmith {si.cp = pfs->text; si.count = pfs->count;} 28940843Smsmith 29040843Smsmith/* 29140843Smsmith** Ficl uses a this little structure to hold the address of 29240843Smsmith** the block of text it's working on and an index to the next 29340843Smsmith** unconsumed character in the string. Traditionally, this is 29440843Smsmith** done by a Text Input Buffer, so I've called this struct TIB. 29540843Smsmith*/ 29640843Smsmithtypedef struct 29740843Smsmith{ 29840843Smsmith INT32 index; 29940843Smsmith char *cp; 30040843Smsmith} TIB; 30140843Smsmith 30240843Smsmith 30340843Smsmith/* 30440843Smsmith** Stacks get heavy use in Ficl and Forth... 30540843Smsmith** Each virtual machine implements two of them: 30640843Smsmith** one holds parameters (data), and the other holds return 30740843Smsmith** addresses and control flow information for the virtual 30840843Smsmith** machine. (Note: C's automatic stack is implicitly used, 30940843Smsmith** but not modeled because it doesn't need to be...) 31040843Smsmith** Here's an abstract type for a stack 31140843Smsmith*/ 31240843Smsmithtypedef struct _ficlStack 31340843Smsmith{ 31440843Smsmith UNS32 nCells; /* size of the stack */ 31540843Smsmith CELL *pFrame; /* link reg for stack frame */ 31640843Smsmith CELL *sp; /* stack pointer */ 31740843Smsmith CELL base[1]; /* Bottom of the stack */ 31840843Smsmith} FICL_STACK; 31940843Smsmith 32040843Smsmith/* 32140843Smsmith** Stack methods... many map closely to required Forth words. 32240843Smsmith*/ 32340843SmsmithFICL_STACK *stackCreate(unsigned nCells); 32440843Smsmithvoid stackDelete(FICL_STACK *pStack); 32540843Smsmithint stackDepth (FICL_STACK *pStack); 32640843Smsmithvoid stackDrop (FICL_STACK *pStack, int n); 32740843SmsmithCELL stackFetch (FICL_STACK *pStack, int n); 32840843SmsmithCELL stackGetTop(FICL_STACK *pStack); 32940843Smsmithvoid stackLink (FICL_STACK *pStack, int nCells); 33040843Smsmithvoid stackPick (FICL_STACK *pStack, int n); 33140843SmsmithCELL stackPop (FICL_STACK *pStack); 33240843Smsmithvoid *stackPopPtr (FICL_STACK *pStack); 33340843SmsmithUNS32 stackPopUNS32 (FICL_STACK *pStack); 33440843SmsmithINT32 stackPopINT32 (FICL_STACK *pStack); 33540843Smsmithvoid stackPush (FICL_STACK *pStack, CELL c); 33640843Smsmithvoid stackPushPtr (FICL_STACK *pStack, void *ptr); 33740843Smsmithvoid stackPushUNS32(FICL_STACK *pStack, UNS32 u); 33840843Smsmithvoid stackPushINT32(FICL_STACK *pStack, INT32 i); 33940843Smsmithvoid stackReset (FICL_STACK *pStack); 34040843Smsmithvoid stackRoll (FICL_STACK *pStack, int n); 34140843Smsmithvoid stackSetTop(FICL_STACK *pStack, CELL c); 34240843Smsmithvoid stackStore (FICL_STACK *pStack, int n, CELL c); 34340843Smsmithvoid stackUnlink(FICL_STACK *pStack); 34440843Smsmith 34540843Smsmith/* 34640843Smsmith** The virtual machine (VM) contains the state for one interpreter. 34740843Smsmith** Defined operations include: 34840843Smsmith** Create & initialize 34940843Smsmith** Delete 35040843Smsmith** Execute a block of text 35140843Smsmith** Parse a word out of the input stream 35240843Smsmith** Call return, and branch 35340843Smsmith** Text output 35440843Smsmith** Throw an exception 35540843Smsmith*/ 35640843Smsmith 35740843Smsmithtypedef struct ficl_word ** IPTYPE; /* the VM's instruction pointer */ 35840843Smsmith 35940843Smsmith/* 36040843Smsmith** Each VM has a placeholder for an output function - 36140843Smsmith** this makes it possible to have each VM do I/O 36240843Smsmith** through a different device. If you specify no 36340843Smsmith** OUTFUNC, it defaults to ficlTextOut. 36440843Smsmith*/ 36540843Smsmithtypedef void (*OUTFUNC)(struct vm *pVM, char *text, int fNewline); 36640843Smsmith 36740843Smsmith/* 36840843Smsmith** Each VM operates in one of two non-error states: interpreting 36940843Smsmith** or compiling. When interpreting, words are simply executed. 37040843Smsmith** When compiling, most words in the input stream have their 37140843Smsmith** addresses inserted into the word under construction. Some words 37240843Smsmith** (known as IMMEDIATE) are executed in the compile state, too. 37340843Smsmith*/ 37440843Smsmith/* values of STATE */ 37540843Smsmith#define INTERPRET 0 37640843Smsmith#define COMPILE 1 37740843Smsmith 37840843Smsmith/* 37940843Smsmith** The pad is a small scratch area for text manipulation. ANS Forth 38040843Smsmith** requires it to hold at least 84 characters. 38140843Smsmith*/ 38240843Smsmith#if !defined nPAD 38340843Smsmith#define nPAD 256 38440843Smsmith#endif 38540843Smsmith 38640843Smsmith/* 38740843Smsmith** ANS Forth requires that a word's name contain {1..31} characters. 38840843Smsmith*/ 38940843Smsmith#if !defined nFICLNAME 39040843Smsmith#define nFICLNAME 31 39140843Smsmith#endif 39240843Smsmith 39340843Smsmith/* 39440843Smsmith** OK - now we can really define the VM... 39540843Smsmith*/ 39640843Smsmithtypedef struct vm 39740843Smsmith{ 39840843Smsmith struct vm *link; /* Ficl keeps a VM list for simple teardown */ 39940843Smsmith jmp_buf *pState; /* crude exception mechanism... */ 40040843Smsmith OUTFUNC textOut; /* Output callback - see sysdep.c */ 40140843Smsmith void * pExtend; /* vm extension pointer */ 40240843Smsmith short fRestart; /* Set TRUE to restart runningWord */ 40340843Smsmith IPTYPE ip; /* instruction pointer */ 40440843Smsmith struct ficl_word 40540843Smsmith *runningWord;/* address of currently running word (often just *(ip-1) ) */ 40640843Smsmith UNS32 state; /* compiling or interpreting */ 40740843Smsmith UNS32 base; /* number conversion base */ 40840843Smsmith FICL_STACK *pStack; /* param stack */ 40940843Smsmith FICL_STACK *rStack; /* return stack */ 41040843Smsmith CELL sourceID; /* -1 if string, 0 if normal input */ 41140843Smsmith TIB tib; /* address of incoming text string */ 41240843Smsmith#if FICL_WANT_USER 41340843Smsmith CELL user[FICL_USER_CELLS]; 41440843Smsmith#endif 41540843Smsmith char pad[nPAD]; /* the scratch area (see above) */ 41640843Smsmith} FICL_VM; 41740843Smsmith 41840843Smsmith/* 41940843Smsmith** A FICL_CODE points to a function that gets called to help execute 42040843Smsmith** a word in the dictionary. It always gets passed a pointer to the 42140843Smsmith** running virtual machine, and from there it can get the address 42240843Smsmith** of the parameter area of the word it's supposed to operate on. 42340843Smsmith** For precompiled words, the code is all there is. For user defined 42440843Smsmith** words, the code assumes that the word's parameter area is a list 42540843Smsmith** of pointers to the code fields of other words to execute, and 42640843Smsmith** may also contain inline data. The first parameter is always 42740843Smsmith** a pointer to a code field. 42840843Smsmith*/ 42940843Smsmithtypedef void (*FICL_CODE)(FICL_VM *pVm); 43040843Smsmith 43140843Smsmith/* 43240843Smsmith** Ficl models memory as a contiguous space divided into 43340843Smsmith** words in a linked list called the dictionary. 43440843Smsmith** A FICL_WORD starts each entry in the list. 43540843Smsmith** Version 1.02: space for the name characters is allotted from 43640843Smsmith** the dictionary ahead of the word struct - this saves about half 43740843Smsmith** the storage on average with very little runtime cost. 43840843Smsmith*/ 43940843Smsmithtypedef struct ficl_word 44040843Smsmith{ 44140843Smsmith struct ficl_word *link; /* Previous word in the dictionary */ 44240843Smsmith UNS16 hash; 44340843Smsmith UNS8 flags; /* Immediate, Smudge, Compile-only */ 44440843Smsmith FICL_COUNT nName; /* Number of chars in word name */ 44540843Smsmith char *name; /* First nFICLNAME chars of word name */ 44640843Smsmith FICL_CODE code; /* Native code to execute the word */ 44740843Smsmith CELL param[1]; /* First data cell of the word */ 44840843Smsmith} FICL_WORD; 44940843Smsmith 45040843Smsmith/* 45140843Smsmith** Worst-case size of a word header: nFICLNAME chars in name 45240843Smsmith*/ 45340843Smsmith#define CELLS_PER_WORD \ 45440843Smsmith ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \ 45540843Smsmith / (sizeof (CELL)) ) 45640843Smsmith 45740843Smsmithint wordIsImmediate(FICL_WORD *pFW); 45840843Smsmithint wordIsCompileOnly(FICL_WORD *pFW); 45940843Smsmith 46040843Smsmith/* flag values for word header */ 46140843Smsmith#define FW_IMMEDIATE 1 /* execute me even if compiling */ 46240843Smsmith#define FW_COMPILE 2 /* error if executed when not compiling */ 46340843Smsmith#define FW_SMUDGE 4 /* definition in progress - hide me */ 46440843Smsmith#define FW_CLASS 8 /* Word defines a class */ 46540843Smsmith 46640843Smsmith#define FW_COMPIMMED (FW_IMMEDIATE | FW_COMPILE) 46740843Smsmith#define FW_DEFAULT 0 46840843Smsmith 46940843Smsmith 47040843Smsmith/* 47140843Smsmith** Exit codes for vmThrow 47240843Smsmith*/ 47340843Smsmith#define VM_OUTOFTEXT 1 /* hungry - normal exit */ 47440843Smsmith#define VM_RESTART 2 /* word needs more text to suxcceed - re-run it */ 47540843Smsmith#define VM_USEREXIT 3 /* user wants to quit */ 47640843Smsmith#define VM_ERREXIT 4 /* interp found an error */ 47740843Smsmith#define VM_QUIT 5 /* like errexit, but leave pStack & base alone */ 47840843Smsmith 47940843Smsmith 48040843Smsmithvoid vmBranchRelative(FICL_VM *pVM, int offset); 48140843SmsmithFICL_VM * vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack); 48240843Smsmithvoid vmDelete (FICL_VM *pVM); 48340843Smsmithvoid vmExecute(FICL_VM *pVM, FICL_WORD *pWord); 48440843Smsmithchar * vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter); 48540843SmsmithSTRINGINFO vmGetWord(FICL_VM *pVM); 48640843SmsmithSTRINGINFO vmGetWord0(FICL_VM *pVM); 48740843Smsmithint vmGetWordToPad(FICL_VM *pVM); 48840843SmsmithSTRINGINFO vmParseString(FICL_VM *pVM, char delimiter); 48940843Smsmithvoid vmPopIP (FICL_VM *pVM); 49040843Smsmithvoid vmPushIP (FICL_VM *pVM, IPTYPE newIP); 49140843Smsmithvoid vmQuit (FICL_VM *pVM); 49240843Smsmithvoid vmReset (FICL_VM *pVM); 49340843Smsmithvoid vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut); 49440843Smsmithvoid vmTextOut(FICL_VM *pVM, char *text, int fNewline); 49540843Smsmithvoid vmThrow (FICL_VM *pVM, int except); 49640843Smsmithvoid vmThrowErr(FICL_VM *pVM, char *fmt, ...); 49740843Smsmith 49840843Smsmith/* 49940843Smsmith** vmCheckStack needs a vm pointer because it might have to say 50040843Smsmith** something if it finds a problem. Parms popCells and pushCells 50140843Smsmith** correspond to the number of parameters on the left and right of 50240843Smsmith** a word's stack effect comment. 50340843Smsmith*/ 50440843Smsmithvoid vmCheckStack(FICL_VM *pVM, int popCells, int pushCells); 50540843Smsmith 50640843Smsmith/* 50740843Smsmith** TIB access routines... 50840843Smsmith** ANS forth seems to require the input buffer to be represented 50940843Smsmith** as a pointer to the start of the buffer, and an index to the 51040843Smsmith** next character to read. 51140843Smsmith** PushTib points the VM to a new input string and optionally 51240843Smsmith** returns a copy of the current state 51340843Smsmith** PopTib restores the TIB state given a saved TIB from PushTib 51440843Smsmith** GetInBuf returns a pointer to the next unused char of the TIB 51540843Smsmith*/ 51640843Smsmithvoid vmPushTib(FICL_VM *pVM, char *text, TIB *pSaveTib); 51740843Smsmithvoid vmPopTib(FICL_VM *pVM, TIB *pTib); 51840843Smsmith#define vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index) 51940843Smsmith#define vmSetTibIndex(pVM, i) (pVM)->tib.index = i 52040843Smsmith#define vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp 52140843Smsmith 52240843Smsmith/* 52340843Smsmith** Generally useful string manipulators omitted by ANSI C... 52440843Smsmith** ltoa complements strtol 52540843Smsmith*/ 52640843Smsmith#if defined(_WIN32) && !FICL_MAIN 52740843Smsmith/* #SHEESH 52840843Smsmith** Why do Microsoft Meatballs insist on contaminating 52940843Smsmith** my namespace with their string functions??? 53040843Smsmith*/ 53140843Smsmith#pragma warning(disable: 4273) 53240843Smsmith#endif 53340843Smsmith 53440843Smsmithchar *ltoa( INT32 value, char *string, int radix ); 53540843Smsmithchar *ultoa(UNS32 value, char *string, int radix ); 53640843Smsmithchar digit_to_char(int value); 53740843Smsmithchar *strrev( char *string ); 53840843Smsmithchar *skipSpace(char *cp); 53940843Smsmithchar *caseFold(char *cp); 54040843Smsmithint strincmp(char *cp1, char *cp2, FICL_COUNT count); 54140843Smsmith 54240843Smsmith#if defined(_WIN32) && !FICL_MAIN 54340843Smsmith#pragma warning(default: 4273) 54440843Smsmith#endif 54540843Smsmith 54640843Smsmith/* 54740843Smsmith** Ficl hash table - variable size. 54840843Smsmith** assert(size > 0) 54940843Smsmith** If size is 1, the table degenerates into a linked list. 55040843Smsmith** A WORDLIST (see the search order word set in DPANS) is 55140843Smsmith** just a pointer to a FICL_HASH in this implementation. 55240843Smsmith*/ 55340843Smsmith#if !defined HASHSIZE /* Default size of hash table. For best */ 55440843Smsmith#define HASHSIZE 127 /* performance, use a prime number! */ 55540843Smsmith#endif 55640843Smsmith 55740843Smsmithtypedef struct ficl_hash 55840843Smsmith{ 55940843Smsmith struct ficl_hash *link; /* eventual inheritance support */ 56040843Smsmith unsigned size; 56140843Smsmith FICL_WORD *table[1]; 56240843Smsmith} FICL_HASH; 56340843Smsmith 56440843Smsmithvoid hashForget(FICL_HASH *pHash, void *where); 56540843SmsmithUNS16 hashHashCode(STRINGINFO si); 56640843Smsmithvoid hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW); 56740843SmsmithFICL_WORD *hashLookup(struct ficl_hash *pHash, 56840843Smsmith STRINGINFO si, 56940843Smsmith UNS16 hashCode); 57040843Smsmithvoid hashReset(FICL_HASH *pHash); 57140843Smsmith 57240843Smsmith/* 57340843Smsmith** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's 57440843Smsmith** memory model. Description of fields: 57540843Smsmith** 57640843Smsmith** here -- points to the next free byte in the dictionary. This 57740843Smsmith** pointer is forced to be CELL-aligned before a definition is added. 57840843Smsmith** Do not assume any specific alignment otherwise - Use dictAlign(). 57940843Smsmith** 58040843Smsmith** smudge -- pointer to word currently being defined (or last defined word) 58140843Smsmith** If the definition completes successfully, the word will be 58240843Smsmith** linked into the hash table. If unsuccessful, dictUnsmudge 58340843Smsmith** uses this pointer to restore the previous state of the dictionary. 58440843Smsmith** Smudge prevents unintentional recursion as a side-effect: the 58540843Smsmith** dictionary search algo examines only completed definitions, so a 58640843Smsmith** word cannot invoke itself by name. See the ficl word "recurse". 58740843Smsmith** NOTE: smudge always points to the last word defined. IMMEDIATE 58840843Smsmith** makes use of this fact. Smudge is initially NULL. 58940843Smsmith** 59040843Smsmith** pForthWords -- pointer to the default wordlist (FICL_HASH). 59140843Smsmith** This is the initial compilation list, and contains all 59240843Smsmith** ficl's precompiled words. 59340843Smsmith** 59440843Smsmith** pCompile -- compilation wordlist - initially equal to pForthWords 59540843Smsmith** pSearch -- array of pointers to wordlists. Managed as a stack. 59640843Smsmith** Highest index is the first list in the search order. 59740843Smsmith** nLists -- number of lists in pSearch. nLists-1 is the highest 59840843Smsmith** filled slot in pSearch, and points to the first wordlist 59940843Smsmith** in the search order 60040843Smsmith** size -- number of cells in the dictionary (total) 60140843Smsmith** dict -- start of data area. Must be at the end of the struct. 60240843Smsmith*/ 60340843Smsmithtypedef struct ficl_dict 60440843Smsmith{ 60540843Smsmith CELL *here; 60640843Smsmith FICL_WORD *smudge; 60740843Smsmith FICL_HASH *pForthWords; 60840843Smsmith FICL_HASH *pCompile; 60940843Smsmith FICL_HASH *pSearch[FICL_DEFAULT_VOCS]; 61040843Smsmith int nLists; 61140843Smsmith unsigned size; /* Number of cells in dict (total)*/ 61240843Smsmith CELL dict[1]; /* Base of dictionary memory */ 61340843Smsmith} FICL_DICT; 61440843Smsmith 61540843Smsmithvoid *alignPtr(void *ptr); 61640843Smsmithvoid dictAbortDefinition(FICL_DICT *pDict); 61740843Smsmithvoid dictAlign(FICL_DICT *pDict); 61840843Smsmithint dictAllot(FICL_DICT *pDict, int n); 61940843Smsmithint dictAllotCells(FICL_DICT *pDict, int nCells); 62040843Smsmithvoid dictAppendCell(FICL_DICT *pDict, CELL c); 62140843Smsmithvoid dictAppendChar(FICL_DICT *pDict, char c); 62240843SmsmithFICL_WORD *dictAppendWord(FICL_DICT *pDict, 62340843Smsmith char *name, 62440843Smsmith FICL_CODE pCode, 62540843Smsmith UNS8 flags); 62640843SmsmithFICL_WORD *dictAppendWord2(FICL_DICT *pDict, 62740843Smsmith STRINGINFO si, 62840843Smsmith FICL_CODE pCode, 62940843Smsmith UNS8 flags); 63040843Smsmithvoid dictAppendUNS32(FICL_DICT *pDict, UNS32 u); 63140843Smsmithint dictCellsAvail(FICL_DICT *pDict); 63240843Smsmithint dictCellsUsed (FICL_DICT *pDict); 63340843Smsmithvoid dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells); 63440843SmsmithFICL_DICT *dictCreate(unsigned nCELLS); 63540843SmsmithFICL_DICT *dictCreateHashed(unsigned nCells, unsigned nHash); 63640843Smsmithvoid dictDelete(FICL_DICT *pDict); 63740843Smsmithvoid dictEmpty(FICL_DICT *pDict, unsigned nHash); 63840843Smsmithvoid dictHashSummary(FICL_VM *pVM); 63940843Smsmithint dictIncludes(FICL_DICT *pDict, void *p); 64040843SmsmithFICL_WORD *dictLookup(FICL_DICT *pDict, STRINGINFO si); 64140843Smsmith#if FICL_WANT_LOCALS 64240843SmsmithFICL_WORD *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si); 64340843Smsmith#endif 64440843Smsmithvoid dictResetSearchOrder(FICL_DICT *pDict); 64540843Smsmithvoid dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr); 64640843Smsmithvoid dictSetImmediate(FICL_DICT *pDict); 64740843Smsmithvoid dictUnsmudge(FICL_DICT *pDict); 64840843SmsmithCELL *dictWhere(FICL_DICT *pDict); 64940843Smsmith 65040843Smsmith 65140843Smsmith/* 65240843Smsmith** External interface to FICL... 65340843Smsmith*/ 65440843Smsmith/* 65540843Smsmith** f i c l I n i t S y s t e m 65640843Smsmith** Binds a global dictionary to the interpreter system and initializes 65740843Smsmith** the dict to contain the ANSI CORE wordset. 65840843Smsmith** You specify the address and size of the allocated area. 65940843Smsmith** After that, ficl manages it. 66040843Smsmith** First step is to set up the static pointers to the area. 66140843Smsmith** Then write the "precompiled" portion of the dictionary in. 66240843Smsmith** The dictionary needs to be at least large enough to hold the 66340843Smsmith** precompiled part. Try 1K cells minimum. Use "words" to find 66440843Smsmith** out how much of the dictionary is used at any time. 66540843Smsmith*/ 66640843Smsmithvoid ficlInitSystem(int nDictCells); 66740843Smsmith 66840843Smsmith/* 66940843Smsmith** f i c l T e r m S y s t e m 67040843Smsmith** Deletes the system dictionary and all virtual machines that 67140843Smsmith** were created with ficlNewVM (see below). Call this function to 67240843Smsmith** reclaim all memory used by the dictionary and VMs. 67340843Smsmith*/ 67440843Smsmithvoid ficlTermSystem(void); 67540843Smsmith 67640843Smsmith/* 67740843Smsmith** f i c l E x e c 67840843Smsmith** Evaluates a block of input text in the context of the 67940843Smsmith** specified interpreter. Emits any requested output to the 68040843Smsmith** interpreter's output function 68140843Smsmith** Execution returns when the text block has been executed, 68240843Smsmith** or an error occurs. 68340843Smsmith** Returns one of the VM_XXXX codes defined in ficl.h: 68440843Smsmith** VM_OUTOFTEXT is the normal exit condition 68540843Smsmith** VM_ERREXIT means that the interp encountered a syntax error 68640843Smsmith** and the vm has been reset to recover (some or all 68740843Smsmith** of the text block got ignored 68840843Smsmith** VM_USEREXIT means that the user executed the "bye" command 68940843Smsmith** to shut down the interpreter. This would be a good 69040843Smsmith** time to delete the vm, etc -- or you can ignore this 69140843Smsmith** signal. 69240843Smsmith** Preconditions: successful execution of ficlInitSystem, 69340843Smsmith** Successful creation and init of the VM by ficlNewVM (or equiv) 69440843Smsmith*/ 69540843Smsmithint ficlExec(FICL_VM *pVM, char *pText); 69640843Smsmith 69740843Smsmith/* 69840989Sjkh** ficlExecFD(FICL_VM *pVM, int fd); 69940989Sjkh * Evaluates text from file passed in via fd. 70040989Sjkh * Execution returns when all of file has been executed or an 70140989Sjkh * error occurs. 70240989Sjkh */ 70340989Sjkhint ficlExecFD(FICL_VM *pVM, int fd); 70440989Sjkh 70540989Sjkh/* 70640843Smsmith** Create a new VM from the heap, and link it into the system VM list. 70740843Smsmith** Initializes the VM and binds default sized stacks to it. Returns the 70840843Smsmith** address of the VM, or NULL if an error occurs. 70940843Smsmith** Precondition: successful execution of ficlInitSystem 71040843Smsmith*/ 71140843SmsmithFICL_VM *ficlNewVM(void); 71240843Smsmith 71340843Smsmith/* 71440843Smsmith** Returns the address of the most recently defined word in the system 71540843Smsmith** dictionary with the given name, or NULL if no match. 71640843Smsmith** Precondition: successful execution of ficlInitSystem 71740843Smsmith*/ 71840843SmsmithFICL_WORD *ficlLookup(char *name); 71940843Smsmith 72040843Smsmith/* 72140843Smsmith** f i c l G e t D i c t 72240843Smsmith** Utility function - returns the address of the system dictionary. 72340843Smsmith** Precondition: successful execution of ficlInitSystem 72440843Smsmith*/ 72540843SmsmithFICL_DICT *ficlGetDict(void); 72640843SmsmithFICL_DICT *ficlGetEnv(void); 72740843Smsmithvoid ficlSetEnv(char *name, UNS32 value); 72840843Smsmithvoid ficlSetEnvD(char *name, UNS32 hi, UNS32 lo); 72940843Smsmith#if FICL_WANT_LOCALS 73040843SmsmithFICL_DICT *ficlGetLoc(void); 73140843Smsmith#endif 73240843Smsmith/* 73340843Smsmith** f i c l B u i l d 73440843Smsmith** Builds a word into the system default dictionary in a thread-safe way. 73540843Smsmith** Preconditions: system must be initialized, and there must 73640843Smsmith** be enough space for the new word's header! Operation is 73740843Smsmith** controlled by ficlLockDictionary, so any initialization 73840843Smsmith** required by your version of the function (if you "overrode" 73940843Smsmith** it) must be complete at this point. 74040843Smsmith** Parameters: 74140843Smsmith** name -- the name of the word to be built 74240843Smsmith** code -- code to execute when the word is invoked - must take a single param 74340843Smsmith** pointer to a FICL_VM 74440843Smsmith** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR! 74540843Smsmith** Most words can use FW_DEFAULT. 74640843Smsmith** nAllot - number of extra cells to allocate in the parameter area (usually zero) 74740843Smsmith*/ 74840843Smsmithint ficlBuild(char *name, FICL_CODE code, char flags); 74940843Smsmith 75040843Smsmith/* 75140843Smsmith** f i c l C o m p i l e C o r e 75240843Smsmith** Builds the ANS CORE wordset into the dictionary - called by 75340843Smsmith** ficlInitSystem - no need to waste dict space by doing it again. 75440843Smsmith*/ 75540843Smsmithvoid ficlCompileCore(FICL_DICT *dp); 75640843Smsmithvoid ficlCompileSoftCore(FICL_VM *pVM); 75740843Smsmith 75840843Smsmith/* 75940843Smsmith** from words.c... 76040843Smsmith*/ 76140843Smsmithvoid constantParen(FICL_VM *pVM); 76240843Smsmithvoid twoConstParen(FICL_VM *pVM); 76340843Smsmith 76442634Sabial#ifdef __i386__ 76542634Sabialextern void pc_fetch(FICL_VM *pVM); 76642634Sabialextern void pc_store(FICL_VM *pVM); 76742634Sabial#endif 76842634Sabial 76940843Smsmith#ifdef __cplusplus 77040843Smsmith} 77140843Smsmith#endif 77240843Smsmith 77340843Smsmith#endif /* __FICL_H__ */ 774