ficl.h revision 40977
11553Srgrimes/******************************************************************* 21553Srgrimes** f i c l . h 31553Srgrimes** Forth Inspired Command Language 41553Srgrimes** Author: John Sadler (john_sadler@alum.mit.edu) 51553Srgrimes** Created: 19 July 1997 61553Srgrimes** 71553Srgrimes*******************************************************************/ 81553Srgrimes/* 91553Srgrimes** N O T I C E -- DISCLAIMER OF WARRANTY 101553Srgrimes** 111553Srgrimes** Ficl is freeware. Use it in any way that you like, with 121553Srgrimes** the understanding that the code is supported on a "best effort" 131553Srgrimes** basis only. 141553Srgrimes** 151553Srgrimes** Any third party may reproduce, distribute, or modify the ficl 161553Srgrimes** software code or any derivative works thereof without any 171553Srgrimes** compensation or license, provided that the author information 181553Srgrimes** and this disclaimer text are retained in the source code files. 191553Srgrimes** The ficl software code is provided on an "as is" basis without 201553Srgrimes** warranty of any kind, including, without limitation, the implied 211553Srgrimes** warranties of merchantability and fitness for a particular purpose 221553Srgrimes** and their equivalents under the laws of any jurisdiction. 231553Srgrimes** 241553Srgrimes** I am interested in hearing from anyone who uses ficl. If you have 251553Srgrimes** a problem, a success story, a defect, an enhancement request, or 261553Srgrimes** if you would like to contribute to the ficl release (yay!), please 271553Srgrimes** send me email at the address above. 281553Srgrimes*/ 291553Srgrimes 30114601Sobrien#if !defined (__FICL_H__) 311553Srgrimes#define __FICL_H__ 3230643Scharnier/* 331553Srgrimes** Ficl (Forth-inspired command language) is an ANS Forth 341553Srgrimes** interpreter written in C. Unlike traditional Forths, this 351553Srgrimes** interpreter is designed to be embedded into other systems 361553Srgrimes** as a command/macro/development prototype language. 371553Srgrimes** 381553Srgrimes** Where Forths usually view themselves as the center of the system 39114601Sobrien** and expect the rest of the system to be coded in Forth, Ficl 4030643Scharnier** acts as a component of the system. It is easy to export 41114601Sobrien** code written in C or ASM to Ficl in the style of TCL, or to invoke 42114601Sobrien** Ficl code from a compiled module. This allows you to do incremental 431553Srgrimes** development in a way that combines the best features of threaded 441553Srgrimes** languages (rapid development, quick code/test/debug cycle, 4514544Sdg** reasonably fast) with the best features of C (everyone knows it, 461553Srgrimes** easier to support large blocks of code, efficient, type checking). 471553Srgrimes** 481553Srgrimes** Ficl provides facilities for interoperating 491553Srgrimes** with programs written in C: C functions can be exported to Ficl, 501553Srgrimes** and Ficl commands can be executed via a C calling interface. The 5120287Swollman** interpreter is re-entrant, so it can be used in multiple instances 521553Srgrimes** in a multitasking system. Unlike Forth, Ficl's outer interpreter 531553Srgrimes** expects a text block as input, and returns to the caller after each 541553Srgrimes** text block, so the "data pump" is somewhere in external code. This 551553Srgrimes** is more like TCL than Forth, which usually expcets to be at the center 561553Srgrimes** of the system, requesting input at its convenience. Each Ficl virtual 571553Srgrimes** machine can be bound to a different I/O channel, and is independent 581553Srgrimes** of all others in in the same address space except that all virtual 5955679Sshin** machines share a common dictionary (a sort or open symbol table that 6055679Sshin** defines all of the elements of the language). 6155679Sshin** 621553Srgrimes** Code is written in ANSI C for portability. 631553Srgrimes** 641553Srgrimes** Summary of Ficl features and constraints: 651553Srgrimes** - Standard: Implements the ANSI Forth CORE word set and part 661553Srgrimes** of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and 671553Srgrimes** TOOLS EXT, LOCAL and LOCAL ext and various extras. 681553Srgrimes** - Extensible: you can export code written in Forth, C, 691553Srgrimes** or asm in a straightforward way. Ficl provides open 701553Srgrimes** facilities for extending the language in an application 711553Srgrimes** specific way. You can even add new control structures! 721553Srgrimes** - Ficl and C can interact in two ways: Ficl can encapsulate 731553Srgrimes** C code, or C code can invoke Ficl code. 741553Srgrimes** - Thread-safe, re-entrant: The shared system dictionary 751553Srgrimes** uses a locking mechanism that you can either supply 7630643Scharnier** or stub out to provide exclusive access. Each Ficl 771553Srgrimes** virtual machine has an otherwise complete state, and 781553Srgrimes** each can be bound to a separate I/O channel (or none at all). 7930643Scharnier** - Simple encapsulation into existing systems: a basic implementation 8030643Scharnier** requires three function calls (see the example program in testmain.c). 81100114Salfred** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data 8230643Scharnier** environments. It does require somewhat more memory than a pure 831553Srgrimes** ROM implementation because it builds its system dictionary in 84100114Salfred** RAM at startup time. 851553Srgrimes** - Written an ANSI C to be as simple as I can make it to understand, 861553Srgrimes** support, debug, and port. Compiles without complaint at /Az /W4 871553Srgrimes** (require ANSI C, max warnings) under Microsoft VC++ 5. 881553Srgrimes** - Does full 32 bit math (but you need to implement 891553Srgrimes** two mixed precision math primitives (see sysdep.c)) 901553Srgrimes** - Indirect threaded interpreter is not the fastest kind of 911553Srgrimes** Forth there is (see pForth 68K for a really fast subroutine 92100114Salfred** threaded interpreter), but it's the cleanest match to a 93100114Salfred** pure C implementation. 94100114Salfred** 95100114Salfred** P O R T I N G F i c l 96100114Salfred** 9730643Scharnier** To install Ficl on your target system, you need an ANSI C compiler 9830643Scharnier** and its runtime library. Inspect the system dependent macros and 99100114Salfred** functions in sysdep.h and sysdep.c and edit them to suit your 1001553Srgrimes** system. For example, INT16 is a short on some compilers and an 10130643Scharnier** int on others. Check the default CELL alignment controlled by 102100114Salfred** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree, 1031553Srgrimes** ficlLockDictionary, and ficlTextOut to work with your operating system. 104100114Salfred** Finally, use testmain.c as a guide to installing the Ficl system and 105100114Salfred** one or more virtual machines into your code. You do not need to include 106100114Salfred** testmain.c in your build. 1071553Srgrimes** 10824428Simp** T o D o L i s t 1091553Srgrimes** 1101553Srgrimes** 1. Unimplemented system dependent CORE word: key 1111553Srgrimes** 2. Kludged CORE word: ACCEPT 1121553Srgrimes** 3. Dictionary locking is full of holes - only one vm at a time 1131553Srgrimes** can alter the dict. 1141553Srgrimes** 4. Ficl uses the pad in CORE words - this violates the standard, 1151553Srgrimes** but it's cleaner for a multithreaded system. I'll have to make a 1161553Srgrimes** second pad for reference by the word PAD to fix this. 1171553Srgrimes** 1181553Srgrimes** F o r M o r e I n f o r m a t i o n 1191553Srgrimes** 1201553Srgrimes** Web home of ficl 12130643Scharnier** http://www.taygeta.com/forth/compilers 12230643Scharnier** Check this website for Forth literature (including the ANSI standard) 1231553Srgrimes** http://www.taygeta.com/forthlit.html 1241553Srgrimes** and here for software and more links 1251553Srgrimes** http://www.taygeta.com/forth.html 1261553Srgrimes** 1271553Srgrimes** Obvious Performance enhancement opportunities 1281553Srgrimes** Compile speed 1291553Srgrimes** - work on interpret speed 1301553Srgrimes** - turn off locals (FICL_WANT_LOCALS) 1311553Srgrimes** Interpret speed 1321553Srgrimes** - Change inner interpreter (and everything else) 13330643Scharnier** so that a definition is a list of pointers to functions 1341553Srgrimes** and inline data rather than pointers to words. This gets 1351553Srgrimes** rid of vm->runningWord and a level of indirection in the 1361553Srgrimes** inner loop. I'll look at it for ficl 3.0 1371553Srgrimes** - Make the main hash table a bigger prime (HASHSIZE) 1381553Srgrimes** - FORGET about twiddling the hash function - my experience is 1391553Srgrimes** that that is a waste of time. 140100114Salfred** - eliminate the need to pass the pVM parameter on the stack 1411553Srgrimes** by dedicating a register to it. Most words need access to the 1421553Srgrimes** vm, but the parameter passing overhead can be reduced. One way 1431553Srgrimes** requires that the host OS have a task switch callout. Create 1441553Srgrimes** a global variable for the running VM and refer to it in words 1451553Srgrimes** that need VM access. Alternative: use thread local storage. 1461553Srgrimes** For single threaded implementations, you can just use a global. 1471553Srgrimes** The first two solutions create portability problems, so I 1481553Srgrimes** haven't considered doing them. Another possibility is to 1491553Srgrimes** declare the pVm parameter to be "register", and hope the compiler 1501553Srgrimes** pays attention. 1511553Srgrimes** 1521553Srgrimes*/ 1531553Srgrimes 154100114Salfred/* 1551553Srgrimes** Revision History: 156100114Salfred** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT, 157100114Salfred** SEARCH / SEARCH EXT, TOOLS / TOOLS EXT. 15830643Scharnier** Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD, 15930643Scharnier** EMPTY to clear stack. 16082664Sru** 16130643Scharnier** 29 jun 1998 (sadler) added variable sized hash table support 16230643Scharnier** and ANS Forth optional SEARCH & SEARCH EXT word set. 1631553Srgrimes** 26 May 1998 (sadler) 1641553Srgrimes** FICL_PROMPT macro 16530643Scharnier** 14 April 1998 (sadler) V1.04 16630643Scharnier** Ficlwin: Windows version, Skip Carter's Linux port 1671553Srgrimes** 5 March 1998 (sadler) V1.03 1681553Srgrimes** Bug fixes -- passes John Ryan's ANS test suite "core.fr" 16930643Scharnier** 17030643Scharnier** 24 February 1998 (sadler) V1.02 1711553Srgrimes** -Fixed bugs in <# # #> 1721553Srgrimes** -Changed FICL_WORD so that storage for the name characters 1731553Srgrimes** can be allocated from the dictionary as needed rather than 1741553Srgrimes** reserving 32 bytes in each word whether needed or not - 1751553Srgrimes** this saved 50% of the dictionary storage requirement. 1761553Srgrimes** -Added words in testmain for Win32 functions system,chdir,cwd, 1771553Srgrimes** also added a word that loads and evaluates a file. 1781553Srgrimes** 1791553Srgrimes** December 1997 (sadler) 1801553Srgrimes** -Added VM_RESTART exception handling in ficlExec -- this lets words 1811553Srgrimes** that require additional text to succeed (like :, create, variable...) 1821553Srgrimes** recover gracefully from an empty input buffer rather than emitting 1831553Srgrimes** an error message. Definitions can span multiple input blocks with 1841553Srgrimes** no restrictions. 1851553Srgrimes** -Changed #include order so that <assert.h> is included in sysdep.h, 1861553Srgrimes** and sysdep is included in all other files. This lets you define 1871553Srgrimes** NDEBUG in sysdep.h to disable assertions if you want to. 1881553Srgrimes** -Make PC specific system dependent code conditional on _M_IX86 1891553Srgrimes** defined so that ports can coexist in sysdep.h/sysdep.c 1901553Srgrimes*/ 1911553Srgrimes 1921553Srgrimes#ifdef __cplusplus 1931553Srgrimesextern "C" { 1941553Srgrimes#endif 1951553Srgrimes 196100114Salfred#include "sysdep.h" 1971553Srgrimes#include <limits.h> /* UCHAR_MAX */ 1981553Srgrimes 1991553Srgrimes/* 2001553Srgrimes** Forward declarations... read on. 2011553Srgrimes*/ 2021553Srgrimesstruct ficl_word; 2031553Srgrimesstruct vm; 204100165Sdesstruct ficl_dict; 2051553Srgrimes 2061553Srgrimes/* 2071553Srgrimes** the Good Stuff starts here... 2081553Srgrimes*/ 2091553Srgrimes#define FICL_VER "2.02" 21030643Scharnier#ifndef FICL_PROMPT 21130643Scharnier# define FICL_PROMPT "ok> " 21230643Scharnier#endif 21330643Scharnier 21430643Scharnier/* 21530643Scharnier** ANS Forth requires false to be zero, and true to be the ones 21630643Scharnier** complement of false... that unifies logical and bitwise operations 21730643Scharnier** nicely. 21830643Scharnier*/ 2191553Srgrimes#define FICL_TRUE (0xffffffffL) 2201553Srgrimes#define FICL_FALSE (0) 2211553Srgrimes#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE) 2221553Srgrimes 2231553Srgrimes 22456801Sshin/* 2251553Srgrimes** A CELL is the main storage type. It must be large enough 2261553Srgrimes** to contain a pointer or a scalar. Let's be picky and make 2271553Srgrimes** a 32 bit cell explicitly... 2281553Srgrimes*/ 2291553Srgrimestypedef union _cell 2301553Srgrimes{ 2311553Srgrimes INT32 i; 2321553Srgrimes UNS32 u; 23356801Sshin void *p; 23456801Sshin} CELL; 23556801Sshin 23656801Sshin/* 23756801Sshin** LVALUEtoCELL does a little pointer trickery to cast any 32 bit 23856801Sshin** lvalue (informal definition: an expression whose result has an 23956801Sshin** address) to CELL. Remember that constants and casts are NOT 24056801Sshin** themselves lvalues! 24156801Sshin*/ 24256801Sshin#define LVALUEtoCELL(v) (*(CELL *)&v) 24356801Sshin 24456801Sshin/* 24556801Sshin** PTRtoCELL is a cast through void * intended to satisfy the 24656801Sshin** most outrageously pedantic compiler... (I won't mention 24756801Sshin** its name) 24856801Sshin*/ 24956801Sshin#define PTRtoCELL (CELL *)(void *) 25056801Sshin#define PTRtoSTRING (FICL_STRING *)(void *) 25156801Sshin 2521553Srgrimes/* 2531553Srgrimes** Strings in FICL are stored in Pascal style - with a count 2541553Srgrimes** preceding the text. We'll also NULL-terminate them so that 2551553Srgrimes** they work with the usual C lib string functions. (Belt & 2561553Srgrimes** suspenders? You decide.) 2571553Srgrimes** STRINGINFO hides the implementation with a couple of 2581553Srgrimes** macros for use in internal routines. 2591553Srgrimes*/ 26056801Sshin 26156801Sshintypedef unsigned char FICL_COUNT; 26256801Sshin#define FICL_STRING_MAX UCHAR_MAX 26356801Sshintypedef struct _ficl_string 26456801Sshin{ 26556801Sshin FICL_COUNT count; 26656801Sshin char text[1]; 26756801Sshin} FICL_STRING; 26856801Sshin 26956801Sshintypedef struct 27056801Sshin{ 27156801Sshin UNS32 count; 27256801Sshin char *cp; 27356801Sshin} STRINGINFO; 27456801Sshin 27556801Sshin#define SI_COUNT(si) (si.count) 27656801Sshin#define SI_PTR(si) (si.cp) 27756801Sshin#define SI_SETLEN(si, len) (si.count = (UNS32)(len)) 27856801Sshin#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr)) 2791553Srgrimes/* 2801553Srgrimes** Init a STRINGINFO from a pointer to NULL-terminated string 2811553Srgrimes*/ 2821553Srgrimes#define SI_PSZ(si, psz) \ 2831553Srgrimes {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);} 2841553Srgrimes/* 2851553Srgrimes** Init a STRINGINFO from a pointer to FICL_STRING 2861553Srgrimes*/ 2871553Srgrimes#define SI_PFS(si, pfs) \ 28830643Scharnier {si.cp = pfs->text; si.count = pfs->count;} 28930643Scharnier 2901553Srgrimes/* 2911553Srgrimes** Ficl uses a this little structure to hold the address of 2921553Srgrimes** the block of text it's working on and an index to the next 29330643Scharnier** unconsumed character in the string. Traditionally, this is 29430643Scharnier** done by a Text Input Buffer, so I've called this struct TIB. 2951553Srgrimes*/ 2961553Srgrimestypedef struct 2971553Srgrimes{ 2981553Srgrimes INT32 index; 2991553Srgrimes char *cp; 3001553Srgrimes} TIB; 3011553Srgrimes 3021553Srgrimes 30330643Scharnier/* 304189090Sed** Stacks get heavy use in Ficl and Forth... 305189090Sed** Each virtual machine implements two of them: 3061553Srgrimes** one holds parameters (data), and the other holds return 3071553Srgrimes** addresses and control flow information for the virtual 3081553Srgrimes** machine. (Note: C's automatic stack is implicitly used, 30955679Sshin** but not modeled because it doesn't need to be...) 31055679Sshin** Here's an abstract type for a stack 31155679Sshin*/ 31255679Sshintypedef struct _ficlStack 31355679Sshin{ 31455679Sshin UNS32 nCells; /* size of the stack */ 3151553Srgrimes CELL *pFrame; /* link reg for stack frame */ 31655679Sshin CELL *sp; /* stack pointer */ 31756801Sshin CELL base[1]; /* Bottom of the stack */ 31856801Sshin} FICL_STACK; 31955679Sshin 32056801Sshin/* 32155679Sshin** Stack methods... many map closely to required Forth words. 32255679Sshin*/ 32356801SshinFICL_STACK *stackCreate(unsigned nCells); 32455679Sshinvoid stackDelete(FICL_STACK *pStack); 32555679Sshinint stackDepth (FICL_STACK *pStack); 32655679Sshinvoid stackDrop (FICL_STACK *pStack, int n); 32755679SshinCELL stackFetch (FICL_STACK *pStack, int n); 32855679SshinCELL stackGetTop(FICL_STACK *pStack); 32955679Sshinvoid stackLink (FICL_STACK *pStack, int nCells); 33055679Sshinvoid stackPick (FICL_STACK *pStack, int n); 33155679SshinCELL stackPop (FICL_STACK *pStack); 33255679Sshinvoid *stackPopPtr (FICL_STACK *pStack); 33355679SshinUNS32 stackPopUNS32 (FICL_STACK *pStack); 334100114SalfredINT32 stackPopINT32 (FICL_STACK *pStack); 3351553Srgrimesvoid stackPush (FICL_STACK *pStack, CELL c); 3361553Srgrimesvoid stackPushPtr (FICL_STACK *pStack, void *ptr); 3371553Srgrimesvoid stackPushUNS32(FICL_STACK *pStack, UNS32 u); 3381553Srgrimesvoid stackPushINT32(FICL_STACK *pStack, INT32 i); 3391553Srgrimesvoid stackReset (FICL_STACK *pStack); 34055679Sshinvoid stackRoll (FICL_STACK *pStack, int n); 34155679Sshinvoid stackSetTop(FICL_STACK *pStack, CELL c); 34255679Sshinvoid stackStore (FICL_STACK *pStack, int n, CELL c); 34355679Sshinvoid stackUnlink(FICL_STACK *pStack); 3441553Srgrimes 3451553Srgrimes/* 34655679Sshin** The virtual machine (VM) contains the state for one interpreter. 34755679Sshin** Defined operations include: 34855679Sshin** Create & initialize 34955679Sshin** Delete 35055679Sshin** Execute a block of text 35155679Sshin** Parse a word out of the input stream 35255679Sshin** Call return, and branch 35355679Sshin** Text output 3541553Srgrimes** Throw an exception 35555679Sshin*/ 35655679Sshin 35755679Sshintypedef struct ficl_word ** IPTYPE; /* the VM's instruction pointer */ 35855679Sshin 35955679Sshin/* 36055679Sshin** Each VM has a placeholder for an output function - 36155679Sshin** this makes it possible to have each VM do I/O 3621553Srgrimes** through a different device. If you specify no 36355679Sshin** OUTFUNC, it defaults to ficlTextOut. 36455679Sshin*/ 36555679Sshintypedef void (*OUTFUNC)(struct vm *pVM, char *text, int fNewline); 36655679Sshin 36755679Sshin/* 36855679Sshin** Each VM operates in one of two non-error states: interpreting 36955679Sshin** or compiling. When interpreting, words are simply executed. 37055679Sshin** When compiling, most words in the input stream have their 37155679Sshin** addresses inserted into the word under construction. Some words 3721553Srgrimes** (known as IMMEDIATE) are executed in the compile state, too. 3731553Srgrimes*/ 3741553Srgrimes/* values of STATE */ 3751553Srgrimes#define INTERPRET 0 3761553Srgrimes#define COMPILE 1 3771553Srgrimes 3781553Srgrimes/* 3791553Srgrimes** The pad is a small scratch area for text manipulation. ANS Forth 3801553Srgrimes** requires it to hold at least 84 characters. 381100114Salfred*/ 3821553Srgrimes#if !defined nPAD 383100114Salfred#define nPAD 256 384100114Salfred#endif 3851553Srgrimes 3861553Srgrimes/* 38755679Sshin** ANS Forth requires that a word's name contain {1..31} characters. 3881553Srgrimes*/ 389100114Salfred#if !defined nFICLNAME 3901553Srgrimes#define nFICLNAME 31 39155679Sshin#endif 3921553Srgrimes 3931553Srgrimes/* 3941553Srgrimes** OK - now we can really define the VM... 3951553Srgrimes*/ 3961553Srgrimestypedef struct vm 3971553Srgrimes{ 3981553Srgrimes struct vm *link; /* Ficl keeps a VM list for simple teardown */ 3991553Srgrimes jmp_buf *pState; /* crude exception mechanism... */ 4001553Srgrimes OUTFUNC textOut; /* Output callback - see sysdep.c */ 4011553Srgrimes void * pExtend; /* vm extension pointer */ 4021553Srgrimes short fRestart; /* Set TRUE to restart runningWord */ 4031553Srgrimes IPTYPE ip; /* instruction pointer */ 4041553Srgrimes struct ficl_word 4051553Srgrimes *runningWord;/* address of currently running word (often just *(ip-1) ) */ 4061553Srgrimes UNS32 state; /* compiling or interpreting */ 4071553Srgrimes UNS32 base; /* number conversion base */ 4081553Srgrimes FICL_STACK *pStack; /* param stack */ 4091553Srgrimes FICL_STACK *rStack; /* return stack */ 4101553Srgrimes CELL sourceID; /* -1 if string, 0 if normal input */ 4111553Srgrimes TIB tib; /* address of incoming text string */ 4121553Srgrimes#if FICL_WANT_USER 4131553Srgrimes CELL user[FICL_USER_CELLS]; 4141553Srgrimes#endif 4151553Srgrimes char pad[nPAD]; /* the scratch area (see above) */ 4161553Srgrimes} FICL_VM; 417100114Salfred 418100114Salfred/* 419100114Salfred** A FICL_CODE points to a function that gets called to help execute 420100114Salfred** a word in the dictionary. It always gets passed a pointer to the 421100114Salfred** running virtual machine, and from there it can get the address 422100114Salfred** of the parameter area of the word it's supposed to operate on. 423100114Salfred** For precompiled words, the code is all there is. For user defined 4241553Srgrimes** words, the code assumes that the word's parameter area is a list 4251553Srgrimes** of pointers to the code fields of other words to execute, and 42650680Sjlemon** may also contain inline data. The first parameter is always 42750680Sjlemon** a pointer to a code field. 42850680Sjlemon*/ 42950680Sjlemontypedef void (*FICL_CODE)(FICL_VM *pVm); 43050680Sjlemon 4311553Srgrimes/* 4321553Srgrimes** Ficl models memory as a contiguous space divided into 4331553Srgrimes** words in a linked list called the dictionary. 4341553Srgrimes** A FICL_WORD starts each entry in the list. 4351553Srgrimes** Version 1.02: space for the name characters is allotted from 4361553Srgrimes** the dictionary ahead of the word struct - this saves about half 4371553Srgrimes** the storage on average with very little runtime cost. 4381553Srgrimes*/ 4391553Srgrimestypedef struct ficl_word 4401553Srgrimes{ 4411553Srgrimes struct ficl_word *link; /* Previous word in the dictionary */ 4421553Srgrimes UNS16 hash; 4431553Srgrimes UNS8 flags; /* Immediate, Smudge, Compile-only */ 4441553Srgrimes FICL_COUNT nName; /* Number of chars in word name */ 4451553Srgrimes char *name; /* First nFICLNAME chars of word name */ 44650680Sjlemon FICL_CODE code; /* Native code to execute the word */ 4471553Srgrimes CELL param[1]; /* First data cell of the word */ 4481553Srgrimes} FICL_WORD; 44930643Scharnier 45073732Sdwmalone/* 45173732Sdwmalone** Worst-case size of a word header: nFICLNAME chars in name 4521553Srgrimes*/ 45373732Sdwmalone#define CELLS_PER_WORD \ 4541553Srgrimes ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \ 4551553Srgrimes / (sizeof (CELL)) ) 4561553Srgrimes 45730643Scharnierint wordIsImmediate(FICL_WORD *pFW); 4581553Srgrimesint wordIsCompileOnly(FICL_WORD *pFW); 4591553Srgrimes 4601553Srgrimes/* flag values for word header */ 4611553Srgrimes#define FW_IMMEDIATE 1 /* execute me even if compiling */ 4621553Srgrimes#define FW_COMPILE 2 /* error if executed when not compiling */ 4631553Srgrimes#define FW_SMUDGE 4 /* definition in progress - hide me */ 464#define FW_CLASS 8 /* Word defines a class */ 465 466#define FW_COMPIMMED (FW_IMMEDIATE | FW_COMPILE) 467#define FW_DEFAULT 0 468 469 470/* 471** Exit codes for vmThrow 472*/ 473#define VM_OUTOFTEXT 1 /* hungry - normal exit */ 474#define VM_RESTART 2 /* word needs more text to suxcceed - re-run it */ 475#define VM_USEREXIT 3 /* user wants to quit */ 476#define VM_ERREXIT 4 /* interp found an error */ 477#define VM_QUIT 5 /* like errexit, but leave pStack & base alone */ 478 479 480void vmBranchRelative(FICL_VM *pVM, int offset); 481FICL_VM * vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack); 482void vmDelete (FICL_VM *pVM); 483void vmExecute(FICL_VM *pVM, FICL_WORD *pWord); 484char * vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter); 485STRINGINFO vmGetWord(FICL_VM *pVM); 486STRINGINFO vmGetWord0(FICL_VM *pVM); 487int vmGetWordToPad(FICL_VM *pVM); 488STRINGINFO vmParseString(FICL_VM *pVM, char delimiter); 489void vmPopIP (FICL_VM *pVM); 490void vmPushIP (FICL_VM *pVM, IPTYPE newIP); 491void vmQuit (FICL_VM *pVM); 492void vmReset (FICL_VM *pVM); 493void vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut); 494void vmTextOut(FICL_VM *pVM, char *text, int fNewline); 495void vmThrow (FICL_VM *pVM, int except); 496void vmThrowErr(FICL_VM *pVM, char *fmt, ...); 497 498/* 499** vmCheckStack needs a vm pointer because it might have to say 500** something if it finds a problem. Parms popCells and pushCells 501** correspond to the number of parameters on the left and right of 502** a word's stack effect comment. 503*/ 504void vmCheckStack(FICL_VM *pVM, int popCells, int pushCells); 505 506/* 507** TIB access routines... 508** ANS forth seems to require the input buffer to be represented 509** as a pointer to the start of the buffer, and an index to the 510** next character to read. 511** PushTib points the VM to a new input string and optionally 512** returns a copy of the current state 513** PopTib restores the TIB state given a saved TIB from PushTib 514** GetInBuf returns a pointer to the next unused char of the TIB 515*/ 516void vmPushTib(FICL_VM *pVM, char *text, TIB *pSaveTib); 517void vmPopTib(FICL_VM *pVM, TIB *pTib); 518#define vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index) 519#define vmSetTibIndex(pVM, i) (pVM)->tib.index = i 520#define vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp 521 522/* 523** Generally useful string manipulators omitted by ANSI C... 524** ltoa complements strtol 525*/ 526#if defined(_WIN32) && !FICL_MAIN 527/* #SHEESH 528** Why do Microsoft Meatballs insist on contaminating 529** my namespace with their string functions??? 530*/ 531#pragma warning(disable: 4273) 532#endif 533 534char *ltoa( INT32 value, char *string, int radix ); 535char *ultoa(UNS32 value, char *string, int radix ); 536char digit_to_char(int value); 537char *strrev( char *string ); 538char *skipSpace(char *cp); 539char *caseFold(char *cp); 540int strincmp(char *cp1, char *cp2, FICL_COUNT count); 541 542#if defined(_WIN32) && !FICL_MAIN 543#pragma warning(default: 4273) 544#endif 545 546/* 547** Ficl hash table - variable size. 548** assert(size > 0) 549** If size is 1, the table degenerates into a linked list. 550** A WORDLIST (see the search order word set in DPANS) is 551** just a pointer to a FICL_HASH in this implementation. 552*/ 553#if !defined HASHSIZE /* Default size of hash table. For best */ 554#define HASHSIZE 127 /* performance, use a prime number! */ 555#endif 556 557typedef struct ficl_hash 558{ 559 struct ficl_hash *link; /* eventual inheritance support */ 560 unsigned size; 561 FICL_WORD *table[1]; 562} FICL_HASH; 563 564void hashForget(FICL_HASH *pHash, void *where); 565UNS16 hashHashCode(STRINGINFO si); 566void hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW); 567FICL_WORD *hashLookup(struct ficl_hash *pHash, 568 STRINGINFO si, 569 UNS16 hashCode); 570void hashReset(FICL_HASH *pHash); 571 572/* 573** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's 574** memory model. Description of fields: 575** 576** here -- points to the next free byte in the dictionary. This 577** pointer is forced to be CELL-aligned before a definition is added. 578** Do not assume any specific alignment otherwise - Use dictAlign(). 579** 580** smudge -- pointer to word currently being defined (or last defined word) 581** If the definition completes successfully, the word will be 582** linked into the hash table. If unsuccessful, dictUnsmudge 583** uses this pointer to restore the previous state of the dictionary. 584** Smudge prevents unintentional recursion as a side-effect: the 585** dictionary search algo examines only completed definitions, so a 586** word cannot invoke itself by name. See the ficl word "recurse". 587** NOTE: smudge always points to the last word defined. IMMEDIATE 588** makes use of this fact. Smudge is initially NULL. 589** 590** pForthWords -- pointer to the default wordlist (FICL_HASH). 591** This is the initial compilation list, and contains all 592** ficl's precompiled words. 593** 594** pCompile -- compilation wordlist - initially equal to pForthWords 595** pSearch -- array of pointers to wordlists. Managed as a stack. 596** Highest index is the first list in the search order. 597** nLists -- number of lists in pSearch. nLists-1 is the highest 598** filled slot in pSearch, and points to the first wordlist 599** in the search order 600** size -- number of cells in the dictionary (total) 601** dict -- start of data area. Must be at the end of the struct. 602*/ 603typedef struct ficl_dict 604{ 605 CELL *here; 606 FICL_WORD *smudge; 607 FICL_HASH *pForthWords; 608 FICL_HASH *pCompile; 609 FICL_HASH *pSearch[FICL_DEFAULT_VOCS]; 610 int nLists; 611 unsigned size; /* Number of cells in dict (total)*/ 612 CELL dict[1]; /* Base of dictionary memory */ 613} FICL_DICT; 614 615void *alignPtr(void *ptr); 616void dictAbortDefinition(FICL_DICT *pDict); 617void dictAlign(FICL_DICT *pDict); 618int dictAllot(FICL_DICT *pDict, int n); 619int dictAllotCells(FICL_DICT *pDict, int nCells); 620void dictAppendCell(FICL_DICT *pDict, CELL c); 621void dictAppendChar(FICL_DICT *pDict, char c); 622FICL_WORD *dictAppendWord(FICL_DICT *pDict, 623 char *name, 624 FICL_CODE pCode, 625 UNS8 flags); 626FICL_WORD *dictAppendWord2(FICL_DICT *pDict, 627 STRINGINFO si, 628 FICL_CODE pCode, 629 UNS8 flags); 630void dictAppendUNS32(FICL_DICT *pDict, UNS32 u); 631int dictCellsAvail(FICL_DICT *pDict); 632int dictCellsUsed (FICL_DICT *pDict); 633void dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells); 634FICL_DICT *dictCreate(unsigned nCELLS); 635FICL_DICT *dictCreateHashed(unsigned nCells, unsigned nHash); 636void dictDelete(FICL_DICT *pDict); 637void dictEmpty(FICL_DICT *pDict, unsigned nHash); 638void dictHashSummary(FICL_VM *pVM); 639int dictIncludes(FICL_DICT *pDict, void *p); 640FICL_WORD *dictLookup(FICL_DICT *pDict, STRINGINFO si); 641#if FICL_WANT_LOCALS 642FICL_WORD *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si); 643#endif 644void dictResetSearchOrder(FICL_DICT *pDict); 645void dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr); 646void dictSetImmediate(FICL_DICT *pDict); 647void dictUnsmudge(FICL_DICT *pDict); 648CELL *dictWhere(FICL_DICT *pDict); 649 650 651/* 652** External interface to FICL... 653*/ 654/* 655** f i c l I n i t S y s t e m 656** Binds a global dictionary to the interpreter system and initializes 657** the dict to contain the ANSI CORE wordset. 658** You specify the address and size of the allocated area. 659** After that, ficl manages it. 660** First step is to set up the static pointers to the area. 661** Then write the "precompiled" portion of the dictionary in. 662** The dictionary needs to be at least large enough to hold the 663** precompiled part. Try 1K cells minimum. Use "words" to find 664** out how much of the dictionary is used at any time. 665*/ 666void ficlInitSystem(int nDictCells); 667 668/* 669** f i c l T e r m S y s t e m 670** Deletes the system dictionary and all virtual machines that 671** were created with ficlNewVM (see below). Call this function to 672** reclaim all memory used by the dictionary and VMs. 673*/ 674void ficlTermSystem(void); 675 676/* 677** f i c l E x e c 678** Evaluates a block of input text in the context of the 679** specified interpreter. Emits any requested output to the 680** interpreter's output function 681** Execution returns when the text block has been executed, 682** or an error occurs. 683** Returns one of the VM_XXXX codes defined in ficl.h: 684** VM_OUTOFTEXT is the normal exit condition 685** VM_ERREXIT means that the interp encountered a syntax error 686** and the vm has been reset to recover (some or all 687** of the text block got ignored 688** VM_USEREXIT means that the user executed the "bye" command 689** to shut down the interpreter. This would be a good 690** time to delete the vm, etc -- or you can ignore this 691** signal. 692** Preconditions: successful execution of ficlInitSystem, 693** Successful creation and init of the VM by ficlNewVM (or equiv) 694*/ 695int ficlExec(FICL_VM *pVM, char *pText); 696 697/* 698** Create a new VM from the heap, and link it into the system VM list. 699** Initializes the VM and binds default sized stacks to it. Returns the 700** address of the VM, or NULL if an error occurs. 701** Precondition: successful execution of ficlInitSystem 702*/ 703FICL_VM *ficlNewVM(void); 704 705/* 706** Returns the address of the most recently defined word in the system 707** dictionary with the given name, or NULL if no match. 708** Precondition: successful execution of ficlInitSystem 709*/ 710FICL_WORD *ficlLookup(char *name); 711 712/* 713** f i c l G e t D i c t 714** Utility function - returns the address of the system dictionary. 715** Precondition: successful execution of ficlInitSystem 716*/ 717FICL_DICT *ficlGetDict(void); 718FICL_DICT *ficlGetEnv(void); 719void ficlSetEnv(char *name, UNS32 value); 720void ficlSetEnvD(char *name, UNS32 hi, UNS32 lo); 721#if FICL_WANT_LOCALS 722FICL_DICT *ficlGetLoc(void); 723#endif 724/* 725** f i c l B u i l d 726** Builds a word into the system default dictionary in a thread-safe way. 727** Preconditions: system must be initialized, and there must 728** be enough space for the new word's header! Operation is 729** controlled by ficlLockDictionary, so any initialization 730** required by your version of the function (if you "overrode" 731** it) must be complete at this point. 732** Parameters: 733** name -- the name of the word to be built 734** code -- code to execute when the word is invoked - must take a single param 735** pointer to a FICL_VM 736** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR! 737** Most words can use FW_DEFAULT. 738** nAllot - number of extra cells to allocate in the parameter area (usually zero) 739*/ 740int ficlBuild(char *name, FICL_CODE code, char flags); 741 742/* 743** f i c l C o m p i l e C o r e 744** Builds the ANS CORE wordset into the dictionary - called by 745** ficlInitSystem - no need to waste dict space by doing it again. 746*/ 747void ficlCompileCore(FICL_DICT *dp); 748void ficlCompileSoftCore(FICL_VM *pVM); 749 750/* 751** from words.c... 752*/ 753void constantParen(FICL_VM *pVM); 754void twoConstParen(FICL_VM *pVM); 755 756#ifdef __cplusplus 757} 758#endif 759 760#endif /* __FICL_H__ */ 761