ficl.h revision 61149
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 3051786Sdcs/* $FreeBSD: head/sys/boot/ficl/ficl.h 61149 2000-06-01 18:10:44Z dcs $ */ 3151786Sdcs 3240843Smsmith#if !defined (__FICL_H__) 3340843Smsmith#define __FICL_H__ 3440843Smsmith/* 3540843Smsmith** Ficl (Forth-inspired command language) is an ANS Forth 3640843Smsmith** interpreter written in C. Unlike traditional Forths, this 3740843Smsmith** interpreter is designed to be embedded into other systems 3840843Smsmith** as a command/macro/development prototype language. 3940843Smsmith** 4040843Smsmith** Where Forths usually view themselves as the center of the system 4140843Smsmith** and expect the rest of the system to be coded in Forth, Ficl 4240843Smsmith** acts as a component of the system. It is easy to export 4340843Smsmith** code written in C or ASM to Ficl in the style of TCL, or to invoke 4440843Smsmith** Ficl code from a compiled module. This allows you to do incremental 4540843Smsmith** development in a way that combines the best features of threaded 4640843Smsmith** languages (rapid development, quick code/test/debug cycle, 4740843Smsmith** reasonably fast) with the best features of C (everyone knows it, 4840843Smsmith** easier to support large blocks of code, efficient, type checking). 4940843Smsmith** 5040843Smsmith** Ficl provides facilities for interoperating 5140843Smsmith** with programs written in C: C functions can be exported to Ficl, 5240843Smsmith** and Ficl commands can be executed via a C calling interface. The 5340843Smsmith** interpreter is re-entrant, so it can be used in multiple instances 5440843Smsmith** in a multitasking system. Unlike Forth, Ficl's outer interpreter 5540843Smsmith** expects a text block as input, and returns to the caller after each 5640843Smsmith** text block, so the "data pump" is somewhere in external code. This 5740843Smsmith** is more like TCL than Forth, which usually expcets to be at the center 5840843Smsmith** of the system, requesting input at its convenience. Each Ficl virtual 5940843Smsmith** machine can be bound to a different I/O channel, and is independent 6040843Smsmith** of all others in in the same address space except that all virtual 6140843Smsmith** machines share a common dictionary (a sort or open symbol table that 6240843Smsmith** defines all of the elements of the language). 6340843Smsmith** 6440843Smsmith** Code is written in ANSI C for portability. 6540843Smsmith** 6640843Smsmith** Summary of Ficl features and constraints: 6740843Smsmith** - Standard: Implements the ANSI Forth CORE word set and part 6840843Smsmith** of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and 6940843Smsmith** TOOLS EXT, LOCAL and LOCAL ext and various extras. 7040843Smsmith** - Extensible: you can export code written in Forth, C, 7140843Smsmith** or asm in a straightforward way. Ficl provides open 7240843Smsmith** facilities for extending the language in an application 7340843Smsmith** specific way. You can even add new control structures! 7440843Smsmith** - Ficl and C can interact in two ways: Ficl can encapsulate 7540843Smsmith** C code, or C code can invoke Ficl code. 7640843Smsmith** - Thread-safe, re-entrant: The shared system dictionary 7740843Smsmith** uses a locking mechanism that you can either supply 7840843Smsmith** or stub out to provide exclusive access. Each Ficl 7940843Smsmith** virtual machine has an otherwise complete state, and 8040843Smsmith** each can be bound to a separate I/O channel (or none at all). 8140843Smsmith** - Simple encapsulation into existing systems: a basic implementation 8240843Smsmith** requires three function calls (see the example program in testmain.c). 8340843Smsmith** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data 8440843Smsmith** environments. It does require somewhat more memory than a pure 8540843Smsmith** ROM implementation because it builds its system dictionary in 8640843Smsmith** RAM at startup time. 8740843Smsmith** - Written an ANSI C to be as simple as I can make it to understand, 8840843Smsmith** support, debug, and port. Compiles without complaint at /Az /W4 8940843Smsmith** (require ANSI C, max warnings) under Microsoft VC++ 5. 9040843Smsmith** - Does full 32 bit math (but you need to implement 9140843Smsmith** two mixed precision math primitives (see sysdep.c)) 9240843Smsmith** - Indirect threaded interpreter is not the fastest kind of 9340843Smsmith** Forth there is (see pForth 68K for a really fast subroutine 9440843Smsmith** threaded interpreter), but it's the cleanest match to a 9540843Smsmith** pure C implementation. 9640843Smsmith** 9740843Smsmith** P O R T I N G F i c l 9840843Smsmith** 9940843Smsmith** To install Ficl on your target system, you need an ANSI C compiler 10040843Smsmith** and its runtime library. Inspect the system dependent macros and 10140843Smsmith** functions in sysdep.h and sysdep.c and edit them to suit your 10240843Smsmith** system. For example, INT16 is a short on some compilers and an 10340843Smsmith** int on others. Check the default CELL alignment controlled by 10440843Smsmith** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree, 10540843Smsmith** ficlLockDictionary, and ficlTextOut to work with your operating system. 10640843Smsmith** Finally, use testmain.c as a guide to installing the Ficl system and 10740843Smsmith** one or more virtual machines into your code. You do not need to include 10840843Smsmith** testmain.c in your build. 10940843Smsmith** 11040843Smsmith** T o D o L i s t 11140843Smsmith** 11240843Smsmith** 1. Unimplemented system dependent CORE word: key 11340843Smsmith** 2. Kludged CORE word: ACCEPT 11440843Smsmith** 3. Dictionary locking is full of holes - only one vm at a time 11540843Smsmith** can alter the dict. 11640843Smsmith** 4. Ficl uses the pad in CORE words - this violates the standard, 11740843Smsmith** but it's cleaner for a multithreaded system. I'll have to make a 11840843Smsmith** second pad for reference by the word PAD to fix this. 11940843Smsmith** 12040843Smsmith** F o r M o r e I n f o r m a t i o n 12140843Smsmith** 12240843Smsmith** Web home of ficl 12340843Smsmith** http://www.taygeta.com/forth/compilers 12440843Smsmith** Check this website for Forth literature (including the ANSI standard) 12540843Smsmith** http://www.taygeta.com/forthlit.html 12640843Smsmith** and here for software and more links 12740843Smsmith** http://www.taygeta.com/forth.html 12840843Smsmith** 12940843Smsmith** Obvious Performance enhancement opportunities 13040843Smsmith** Compile speed 13140843Smsmith** - work on interpret speed 13240843Smsmith** - turn off locals (FICL_WANT_LOCALS) 13340843Smsmith** Interpret speed 13440843Smsmith** - Change inner interpreter (and everything else) 13540843Smsmith** so that a definition is a list of pointers to functions 13640843Smsmith** and inline data rather than pointers to words. This gets 13740843Smsmith** rid of vm->runningWord and a level of indirection in the 13840843Smsmith** inner loop. I'll look at it for ficl 3.0 13940843Smsmith** - Make the main hash table a bigger prime (HASHSIZE) 14040843Smsmith** - FORGET about twiddling the hash function - my experience is 14140843Smsmith** that that is a waste of time. 14240843Smsmith** - eliminate the need to pass the pVM parameter on the stack 14340843Smsmith** by dedicating a register to it. Most words need access to the 14440843Smsmith** vm, but the parameter passing overhead can be reduced. One way 14540843Smsmith** requires that the host OS have a task switch callout. Create 14640843Smsmith** a global variable for the running VM and refer to it in words 14740843Smsmith** that need VM access. Alternative: use thread local storage. 14840843Smsmith** For single threaded implementations, you can just use a global. 14940843Smsmith** The first two solutions create portability problems, so I 15040843Smsmith** haven't considered doing them. Another possibility is to 15140843Smsmith** declare the pVm parameter to be "register", and hope the compiler 15240843Smsmith** pays attention. 15340843Smsmith** 15440843Smsmith*/ 15540843Smsmith 15640843Smsmith/* 15740843Smsmith** Revision History: 15851786Sdcs** 15951786Sdcs** 15 Apr 1999 (sadler) Merged FreeBSD changes for exception wordset and 16051786Sdcs** counted strings in ficlExec. 16143078Smsmith** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an 16243078Smsmith** "end" field, and all words respect this. ficlExec is passed a "size" 16343078Smsmith** of TIB, as well as vmPushTib. This size is used to calculate the "end" 16443078Smsmith** of the string, ie, base+size. If the size is not known, pass -1. 16543078Smsmith** 16643078Smsmith** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing 16743078Smsmith** words has been modified to conform to EXCEPTION EXT word set. 16843078Smsmith** 16940843Smsmith** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT, 17040843Smsmith** SEARCH / SEARCH EXT, TOOLS / TOOLS EXT. 17140843Smsmith** Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD, 17240843Smsmith** EMPTY to clear stack. 17340843Smsmith** 17440843Smsmith** 29 jun 1998 (sadler) added variable sized hash table support 17540843Smsmith** and ANS Forth optional SEARCH & SEARCH EXT word set. 17640843Smsmith** 26 May 1998 (sadler) 17740843Smsmith** FICL_PROMPT macro 17840843Smsmith** 14 April 1998 (sadler) V1.04 17940843Smsmith** Ficlwin: Windows version, Skip Carter's Linux port 18040843Smsmith** 5 March 1998 (sadler) V1.03 18140843Smsmith** Bug fixes -- passes John Ryan's ANS test suite "core.fr" 18240843Smsmith** 18340843Smsmith** 24 February 1998 (sadler) V1.02 18440843Smsmith** -Fixed bugs in <# # #> 18540843Smsmith** -Changed FICL_WORD so that storage for the name characters 18640843Smsmith** can be allocated from the dictionary as needed rather than 18740843Smsmith** reserving 32 bytes in each word whether needed or not - 18840843Smsmith** this saved 50% of the dictionary storage requirement. 18940843Smsmith** -Added words in testmain for Win32 functions system,chdir,cwd, 19040843Smsmith** also added a word that loads and evaluates a file. 19140843Smsmith** 19240843Smsmith** December 1997 (sadler) 19340843Smsmith** -Added VM_RESTART exception handling in ficlExec -- this lets words 19440843Smsmith** that require additional text to succeed (like :, create, variable...) 19540843Smsmith** recover gracefully from an empty input buffer rather than emitting 19640843Smsmith** an error message. Definitions can span multiple input blocks with 19740843Smsmith** no restrictions. 19840843Smsmith** -Changed #include order so that <assert.h> is included in sysdep.h, 19940843Smsmith** and sysdep is included in all other files. This lets you define 20040843Smsmith** NDEBUG in sysdep.h to disable assertions if you want to. 20140843Smsmith** -Make PC specific system dependent code conditional on _M_IX86 20240843Smsmith** defined so that ports can coexist in sysdep.h/sysdep.c 20340843Smsmith*/ 20440843Smsmith 20540843Smsmith#ifdef __cplusplus 20640843Smsmithextern "C" { 20740843Smsmith#endif 20840843Smsmith 20940843Smsmith#include "sysdep.h" 21040843Smsmith#include <limits.h> /* UCHAR_MAX */ 21140843Smsmith 21240843Smsmith/* 21340843Smsmith** Forward declarations... read on. 21440843Smsmith*/ 21540843Smsmithstruct ficl_word; 21640843Smsmithstruct vm; 21740843Smsmithstruct ficl_dict; 21840843Smsmith 21940843Smsmith/* 22040843Smsmith** the Good Stuff starts here... 22140843Smsmith*/ 22251786Sdcs#define FICL_VER "2.03" 22351786Sdcs#if !defined (FICL_PROMPT) 22451786Sdcs#define FICL_PROMPT "ok> " 22540949Smsmith#endif 22640843Smsmith 22740843Smsmith/* 22840843Smsmith** ANS Forth requires false to be zero, and true to be the ones 22940843Smsmith** complement of false... that unifies logical and bitwise operations 23040843Smsmith** nicely. 23140843Smsmith*/ 23256719Sdcs#define FICL_TRUE (~(0L)) 23340843Smsmith#define FICL_FALSE (0) 23440843Smsmith#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE) 23540843Smsmith 23640843Smsmith 23740843Smsmith/* 23840843Smsmith** A CELL is the main storage type. It must be large enough 23951786Sdcs** to contain a pointer or a scalar. In order to accommodate 24051786Sdcs** 32 bit and 64 bit processors, use abstract types for i and u. 24140843Smsmith*/ 24240843Smsmithtypedef union _cell 24340843Smsmith{ 24451786Sdcs FICL_INT i; 24551786Sdcs FICL_UNS u; 24640843Smsmith void *p; 24740843Smsmith} CELL; 24840843Smsmith 24940843Smsmith/* 25040843Smsmith** LVALUEtoCELL does a little pointer trickery to cast any 32 bit 25140843Smsmith** lvalue (informal definition: an expression whose result has an 25240843Smsmith** address) to CELL. Remember that constants and casts are NOT 25340843Smsmith** themselves lvalues! 25440843Smsmith*/ 25540843Smsmith#define LVALUEtoCELL(v) (*(CELL *)&v) 25640843Smsmith 25740843Smsmith/* 25840843Smsmith** PTRtoCELL is a cast through void * intended to satisfy the 25940843Smsmith** most outrageously pedantic compiler... (I won't mention 26040843Smsmith** its name) 26140843Smsmith*/ 26240843Smsmith#define PTRtoCELL (CELL *)(void *) 26340843Smsmith#define PTRtoSTRING (FICL_STRING *)(void *) 26440843Smsmith 26540843Smsmith/* 26640843Smsmith** Strings in FICL are stored in Pascal style - with a count 26740843Smsmith** preceding the text. We'll also NULL-terminate them so that 26840843Smsmith** they work with the usual C lib string functions. (Belt & 26940843Smsmith** suspenders? You decide.) 27040843Smsmith** STRINGINFO hides the implementation with a couple of 27140843Smsmith** macros for use in internal routines. 27240843Smsmith*/ 27340843Smsmith 27440843Smsmithtypedef unsigned char FICL_COUNT; 27540843Smsmith#define FICL_STRING_MAX UCHAR_MAX 27640843Smsmithtypedef struct _ficl_string 27740843Smsmith{ 27840843Smsmith FICL_COUNT count; 27940843Smsmith char text[1]; 28040843Smsmith} FICL_STRING; 28140843Smsmith 28240843Smsmithtypedef struct 28340843Smsmith{ 28440843Smsmith UNS32 count; 28540843Smsmith char *cp; 28640843Smsmith} STRINGINFO; 28740843Smsmith 28840843Smsmith#define SI_COUNT(si) (si.count) 28940843Smsmith#define SI_PTR(si) (si.cp) 29040843Smsmith#define SI_SETLEN(si, len) (si.count = (UNS32)(len)) 29140843Smsmith#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr)) 29240843Smsmith/* 29340843Smsmith** Init a STRINGINFO from a pointer to NULL-terminated string 29440843Smsmith*/ 29540843Smsmith#define SI_PSZ(si, psz) \ 29640843Smsmith {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);} 29740843Smsmith/* 29840843Smsmith** Init a STRINGINFO from a pointer to FICL_STRING 29940843Smsmith*/ 30040843Smsmith#define SI_PFS(si, pfs) \ 30140843Smsmith {si.cp = pfs->text; si.count = pfs->count;} 30240843Smsmith 30340843Smsmith/* 30440843Smsmith** Ficl uses a this little structure to hold the address of 30540843Smsmith** the block of text it's working on and an index to the next 30640843Smsmith** unconsumed character in the string. Traditionally, this is 30740843Smsmith** done by a Text Input Buffer, so I've called this struct TIB. 30843078Smsmith** 30943078Smsmith** Since this structure also holds the size of the input buffer, 31043078Smsmith** and since evaluate requires that, let's put the size here. 31143078Smsmith** The size is stored as an end-pointer because that is what the 31243078Smsmith** null-terminated string aware functions find most easy to deal 31343078Smsmith** with. 31443078Smsmith** Notice, though, that nobody really uses this except evaluate, 31543078Smsmith** so it might just be moved to FICL_VM instead. (sobral) 31640843Smsmith*/ 31740843Smsmithtypedef struct 31840843Smsmith{ 31961149Sdcs FICL_INT index; 32043078Smsmith char *end; 32140843Smsmith char *cp; 32240843Smsmith} TIB; 32340843Smsmith 32440843Smsmith 32540843Smsmith/* 32640843Smsmith** Stacks get heavy use in Ficl and Forth... 32740843Smsmith** Each virtual machine implements two of them: 32840843Smsmith** one holds parameters (data), and the other holds return 32940843Smsmith** addresses and control flow information for the virtual 33040843Smsmith** machine. (Note: C's automatic stack is implicitly used, 33140843Smsmith** but not modeled because it doesn't need to be...) 33240843Smsmith** Here's an abstract type for a stack 33340843Smsmith*/ 33440843Smsmithtypedef struct _ficlStack 33540843Smsmith{ 33651786Sdcs FICL_UNS nCells; /* size of the stack */ 33740843Smsmith CELL *pFrame; /* link reg for stack frame */ 33840843Smsmith CELL *sp; /* stack pointer */ 33940843Smsmith CELL base[1]; /* Bottom of the stack */ 34040843Smsmith} FICL_STACK; 34140843Smsmith 34240843Smsmith/* 34340843Smsmith** Stack methods... many map closely to required Forth words. 34440843Smsmith*/ 34540843SmsmithFICL_STACK *stackCreate(unsigned nCells); 34640843Smsmithvoid stackDelete(FICL_STACK *pStack); 34740843Smsmithint stackDepth (FICL_STACK *pStack); 34840843Smsmithvoid stackDrop (FICL_STACK *pStack, int n); 34940843SmsmithCELL stackFetch (FICL_STACK *pStack, int n); 35040843SmsmithCELL stackGetTop(FICL_STACK *pStack); 35140843Smsmithvoid stackLink (FICL_STACK *pStack, int nCells); 35240843Smsmithvoid stackPick (FICL_STACK *pStack, int n); 35340843SmsmithCELL stackPop (FICL_STACK *pStack); 35440843Smsmithvoid *stackPopPtr (FICL_STACK *pStack); 35551786SdcsFICL_UNS stackPopUNS(FICL_STACK *pStack); 35651786SdcsFICL_INT stackPopINT(FICL_STACK *pStack); 35740843Smsmithvoid stackPush (FICL_STACK *pStack, CELL c); 35840843Smsmithvoid stackPushPtr (FICL_STACK *pStack, void *ptr); 35951786Sdcsvoid stackPushUNS(FICL_STACK *pStack, FICL_UNS u); 36051786Sdcsvoid stackPushINT(FICL_STACK *pStack, FICL_INT i); 36140843Smsmithvoid stackReset (FICL_STACK *pStack); 36240843Smsmithvoid stackRoll (FICL_STACK *pStack, int n); 36340843Smsmithvoid stackSetTop(FICL_STACK *pStack, CELL c); 36440843Smsmithvoid stackStore (FICL_STACK *pStack, int n, CELL c); 36540843Smsmithvoid stackUnlink(FICL_STACK *pStack); 36640843Smsmith 36740843Smsmith/* 36840843Smsmith** The virtual machine (VM) contains the state for one interpreter. 36940843Smsmith** Defined operations include: 37040843Smsmith** Create & initialize 37140843Smsmith** Delete 37240843Smsmith** Execute a block of text 37340843Smsmith** Parse a word out of the input stream 37440843Smsmith** Call return, and branch 37540843Smsmith** Text output 37640843Smsmith** Throw an exception 37740843Smsmith*/ 37840843Smsmith 37940843Smsmithtypedef struct ficl_word ** IPTYPE; /* the VM's instruction pointer */ 38040843Smsmith 38140843Smsmith/* 38240843Smsmith** Each VM has a placeholder for an output function - 38340843Smsmith** this makes it possible to have each VM do I/O 38440843Smsmith** through a different device. If you specify no 38540843Smsmith** OUTFUNC, it defaults to ficlTextOut. 38640843Smsmith*/ 38740843Smsmithtypedef void (*OUTFUNC)(struct vm *pVM, char *text, int fNewline); 38840843Smsmith 38940843Smsmith/* 39040843Smsmith** Each VM operates in one of two non-error states: interpreting 39140843Smsmith** or compiling. When interpreting, words are simply executed. 39240843Smsmith** When compiling, most words in the input stream have their 39340843Smsmith** addresses inserted into the word under construction. Some words 39440843Smsmith** (known as IMMEDIATE) are executed in the compile state, too. 39540843Smsmith*/ 39640843Smsmith/* values of STATE */ 39740843Smsmith#define INTERPRET 0 39840843Smsmith#define COMPILE 1 39940843Smsmith 40040843Smsmith/* 40140843Smsmith** The pad is a small scratch area for text manipulation. ANS Forth 40240843Smsmith** requires it to hold at least 84 characters. 40340843Smsmith*/ 40440843Smsmith#if !defined nPAD 40540843Smsmith#define nPAD 256 40640843Smsmith#endif 40740843Smsmith 40840843Smsmith/* 40940843Smsmith** ANS Forth requires that a word's name contain {1..31} characters. 41040843Smsmith*/ 41140843Smsmith#if !defined nFICLNAME 41240843Smsmith#define nFICLNAME 31 41340843Smsmith#endif 41440843Smsmith 41540843Smsmith/* 41640843Smsmith** OK - now we can really define the VM... 41740843Smsmith*/ 41840843Smsmithtypedef struct vm 41940843Smsmith{ 42040843Smsmith struct vm *link; /* Ficl keeps a VM list for simple teardown */ 42140843Smsmith jmp_buf *pState; /* crude exception mechanism... */ 42240843Smsmith OUTFUNC textOut; /* Output callback - see sysdep.c */ 42340843Smsmith void * pExtend; /* vm extension pointer */ 42440843Smsmith short fRestart; /* Set TRUE to restart runningWord */ 42540843Smsmith IPTYPE ip; /* instruction pointer */ 42640843Smsmith struct ficl_word 42740843Smsmith *runningWord;/* address of currently running word (often just *(ip-1) ) */ 42840843Smsmith UNS32 state; /* compiling or interpreting */ 42940843Smsmith UNS32 base; /* number conversion base */ 43040843Smsmith FICL_STACK *pStack; /* param stack */ 43140843Smsmith FICL_STACK *rStack; /* return stack */ 43240843Smsmith CELL sourceID; /* -1 if string, 0 if normal input */ 43340843Smsmith TIB tib; /* address of incoming text string */ 43440843Smsmith#if FICL_WANT_USER 43540843Smsmith CELL user[FICL_USER_CELLS]; 43640843Smsmith#endif 43740843Smsmith char pad[nPAD]; /* the scratch area (see above) */ 43840843Smsmith} FICL_VM; 43940843Smsmith 44040843Smsmith/* 44140843Smsmith** A FICL_CODE points to a function that gets called to help execute 44240843Smsmith** a word in the dictionary. It always gets passed a pointer to the 44340843Smsmith** running virtual machine, and from there it can get the address 44440843Smsmith** of the parameter area of the word it's supposed to operate on. 44540843Smsmith** For precompiled words, the code is all there is. For user defined 44640843Smsmith** words, the code assumes that the word's parameter area is a list 44740843Smsmith** of pointers to the code fields of other words to execute, and 44840843Smsmith** may also contain inline data. The first parameter is always 44940843Smsmith** a pointer to a code field. 45040843Smsmith*/ 45140843Smsmithtypedef void (*FICL_CODE)(FICL_VM *pVm); 45240843Smsmith 45351786Sdcs#if 0 45451786Sdcs#define VM_ASSERT(pVM) assert((*(pVM->ip - 1)) == pVM->runningWord) 45551786Sdcs#else 45651786Sdcs#define VM_ASSERT(pVM) 45751786Sdcs#endif 45851786Sdcs 45940843Smsmith/* 46040843Smsmith** Ficl models memory as a contiguous space divided into 46140843Smsmith** words in a linked list called the dictionary. 46240843Smsmith** A FICL_WORD starts each entry in the list. 46340843Smsmith** Version 1.02: space for the name characters is allotted from 46440843Smsmith** the dictionary ahead of the word struct - this saves about half 46540843Smsmith** the storage on average with very little runtime cost. 46640843Smsmith*/ 46740843Smsmithtypedef struct ficl_word 46840843Smsmith{ 46940843Smsmith struct ficl_word *link; /* Previous word in the dictionary */ 47040843Smsmith UNS16 hash; 47140843Smsmith UNS8 flags; /* Immediate, Smudge, Compile-only */ 47240843Smsmith FICL_COUNT nName; /* Number of chars in word name */ 47340843Smsmith char *name; /* First nFICLNAME chars of word name */ 47440843Smsmith FICL_CODE code; /* Native code to execute the word */ 47540843Smsmith CELL param[1]; /* First data cell of the word */ 47640843Smsmith} FICL_WORD; 47740843Smsmith 47840843Smsmith/* 47940843Smsmith** Worst-case size of a word header: nFICLNAME chars in name 48040843Smsmith*/ 48140843Smsmith#define CELLS_PER_WORD \ 48240843Smsmith ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \ 48340843Smsmith / (sizeof (CELL)) ) 48440843Smsmith 48540843Smsmithint wordIsImmediate(FICL_WORD *pFW); 48640843Smsmithint wordIsCompileOnly(FICL_WORD *pFW); 48740843Smsmith 48840843Smsmith/* flag values for word header */ 48940843Smsmith#define FW_IMMEDIATE 1 /* execute me even if compiling */ 49040843Smsmith#define FW_COMPILE 2 /* error if executed when not compiling */ 49140843Smsmith#define FW_SMUDGE 4 /* definition in progress - hide me */ 49240843Smsmith#define FW_CLASS 8 /* Word defines a class */ 49340843Smsmith 49440843Smsmith#define FW_COMPIMMED (FW_IMMEDIATE | FW_COMPILE) 49540843Smsmith#define FW_DEFAULT 0 49640843Smsmith 49740843Smsmith 49840843Smsmith/* 49940843Smsmith** Exit codes for vmThrow 50040843Smsmith*/ 50151786Sdcs#define VM_INNEREXIT -256 /* tell ficlExecXT to exit inner loop */ 50251786Sdcs#define VM_OUTOFTEXT -257 /* hungry - normal exit */ 50351786Sdcs#define VM_RESTART -258 /* word needs more text to succeed - re-run it */ 50451786Sdcs#define VM_USEREXIT -259 /* user wants to quit */ 50551786Sdcs#define VM_ERREXIT -260 /* interp found an error */ 50643078Smsmith#define VM_ABORT -1 /* like errexit -- abort */ 50743078Smsmith#define VM_ABORTQ -2 /* like errexit -- abort" */ 50843078Smsmith#define VM_QUIT -56 /* like errexit, but leave pStack & base alone */ 50940843Smsmith 51040843Smsmith 51140843Smsmithvoid vmBranchRelative(FICL_VM *pVM, int offset); 51240843SmsmithFICL_VM * vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack); 51340843Smsmithvoid vmDelete (FICL_VM *pVM); 51440843Smsmithvoid vmExecute(FICL_VM *pVM, FICL_WORD *pWord); 51540843Smsmithchar * vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter); 51640843SmsmithSTRINGINFO vmGetWord(FICL_VM *pVM); 51740843SmsmithSTRINGINFO vmGetWord0(FICL_VM *pVM); 51840843Smsmithint vmGetWordToPad(FICL_VM *pVM); 51940843SmsmithSTRINGINFO vmParseString(FICL_VM *pVM, char delimiter); 52060959SdcsSTRINGINFO vmParseStringEx(FICL_VM *pVM, char delimiter, char fSkipLeading); 52160959SdcsCELL vmPop(FICL_VM *pVM); 52260959Sdcsvoid vmPush(FICL_VM *pVM, CELL c); 52340843Smsmithvoid vmPopIP (FICL_VM *pVM); 52440843Smsmithvoid vmPushIP (FICL_VM *pVM, IPTYPE newIP); 52540843Smsmithvoid vmQuit (FICL_VM *pVM); 52640843Smsmithvoid vmReset (FICL_VM *pVM); 52740843Smsmithvoid vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut); 52860959Sdcs#if FICL_WANT_DEBUGGER 52960959Sdcsvoid vmStep(FICL_VM *pVM); 53060959Sdcs#endif 53140843Smsmithvoid vmTextOut(FICL_VM *pVM, char *text, int fNewline); 53240843Smsmithvoid vmThrow (FICL_VM *pVM, int except); 53340843Smsmithvoid vmThrowErr(FICL_VM *pVM, char *fmt, ...); 53440843Smsmith 53551786Sdcs#define vmGetRunningWord(pVM) ((pVM)->runningWord) 53651786Sdcs 53751786Sdcs 53840843Smsmith/* 53951786Sdcs** The inner interpreter - coded as a macro (see note for 54051786Sdcs** INLINE_INNER_LOOP in sysdep.h for complaints about VC++ 5 54151786Sdcs*/ 54260959Sdcs#define M_VM_STEP(pVM) \ 54351786Sdcs FICL_WORD *tempFW = *(pVM)->ip++; \ 54451786Sdcs (pVM)->runningWord = tempFW; \ 54551786Sdcs tempFW->code(pVM); \ 54651786Sdcs 54760959Sdcs#define M_INNER_LOOP(pVM) \ 54860959Sdcs for (;;) { M_VM_STEP(pVM) } 54951786Sdcs 55060959Sdcs 55151786Sdcs#if INLINE_INNER_LOOP != 0 55251786Sdcs#define vmInnerLoop(pVM) M_INNER_LOOP(pVM) 55351786Sdcs#else 55451786Sdcsvoid vmInnerLoop(FICL_VM *pVM); 55551786Sdcs#endif 55651786Sdcs 55751786Sdcs/* 55840843Smsmith** vmCheckStack needs a vm pointer because it might have to say 55940843Smsmith** something if it finds a problem. Parms popCells and pushCells 56040843Smsmith** correspond to the number of parameters on the left and right of 56140843Smsmith** a word's stack effect comment. 56240843Smsmith*/ 56340843Smsmithvoid vmCheckStack(FICL_VM *pVM, int popCells, int pushCells); 56440843Smsmith 56540843Smsmith/* 56640843Smsmith** TIB access routines... 56740843Smsmith** ANS forth seems to require the input buffer to be represented 56840843Smsmith** as a pointer to the start of the buffer, and an index to the 56940843Smsmith** next character to read. 57040843Smsmith** PushTib points the VM to a new input string and optionally 57140843Smsmith** returns a copy of the current state 57240843Smsmith** PopTib restores the TIB state given a saved TIB from PushTib 57340843Smsmith** GetInBuf returns a pointer to the next unused char of the TIB 57440843Smsmith*/ 57551786Sdcsvoid vmPushTib(FICL_VM *pVM, char *text, INT32 nChars, TIB *pSaveTib); 57640843Smsmithvoid vmPopTib(FICL_VM *pVM, TIB *pTib); 57740843Smsmith#define vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index) 57851786Sdcs#define vmGetInBufLen(pVM) ((pVM)->tib.end - (pVM)->tib.cp) 57951786Sdcs#define vmGetInBufEnd(pVM) ((pVM)->tib.end) 58040843Smsmith#define vmSetTibIndex(pVM, i) (pVM)->tib.index = i 58140843Smsmith#define vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp 58240843Smsmith 58340843Smsmith/* 58440843Smsmith** Generally useful string manipulators omitted by ANSI C... 58540843Smsmith** ltoa complements strtol 58640843Smsmith*/ 58740843Smsmith#if defined(_WIN32) && !FICL_MAIN 58840843Smsmith/* #SHEESH 58940843Smsmith** Why do Microsoft Meatballs insist on contaminating 59040843Smsmith** my namespace with their string functions??? 59140843Smsmith*/ 59240843Smsmith#pragma warning(disable: 4273) 59340843Smsmith#endif 59440843Smsmith 59551786Sdcsint isPowerOfTwo(FICL_UNS u); 59651786Sdcs 59751786Sdcschar *ltoa( FICL_INT value, char *string, int radix ); 59851786Sdcschar *ultoa(FICL_UNS value, char *string, int radix ); 59940843Smsmithchar digit_to_char(int value); 60040843Smsmithchar *strrev( char *string ); 60151786Sdcschar *skipSpace(char *cp, char *end); 60240843Smsmithchar *caseFold(char *cp); 60340843Smsmithint strincmp(char *cp1, char *cp2, FICL_COUNT count); 60440843Smsmith 60540843Smsmith#if defined(_WIN32) && !FICL_MAIN 60640843Smsmith#pragma warning(default: 4273) 60740843Smsmith#endif 60840843Smsmith 60940843Smsmith/* 61040843Smsmith** Ficl hash table - variable size. 61140843Smsmith** assert(size > 0) 61240843Smsmith** If size is 1, the table degenerates into a linked list. 61340843Smsmith** A WORDLIST (see the search order word set in DPANS) is 61440843Smsmith** just a pointer to a FICL_HASH in this implementation. 61540843Smsmith*/ 61651786Sdcs#if !defined HASHSIZE /* Default size of hash table. For most uniform */ 61740843Smsmith#define HASHSIZE 127 /* performance, use a prime number! */ 61840843Smsmith#endif 61940843Smsmith 62040843Smsmithtypedef struct ficl_hash 62140843Smsmith{ 62240843Smsmith struct ficl_hash *link; /* eventual inheritance support */ 62340843Smsmith unsigned size; 62440843Smsmith FICL_WORD *table[1]; 62540843Smsmith} FICL_HASH; 62640843Smsmith 62740843Smsmithvoid hashForget(FICL_HASH *pHash, void *where); 62840843SmsmithUNS16 hashHashCode(STRINGINFO si); 62940843Smsmithvoid hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW); 63040843SmsmithFICL_WORD *hashLookup(struct ficl_hash *pHash, 63140843Smsmith STRINGINFO si, 63240843Smsmith UNS16 hashCode); 63340843Smsmithvoid hashReset(FICL_HASH *pHash); 63440843Smsmith 63540843Smsmith/* 63640843Smsmith** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's 63740843Smsmith** memory model. Description of fields: 63840843Smsmith** 63940843Smsmith** here -- points to the next free byte in the dictionary. This 64040843Smsmith** pointer is forced to be CELL-aligned before a definition is added. 64140843Smsmith** Do not assume any specific alignment otherwise - Use dictAlign(). 64240843Smsmith** 64340843Smsmith** smudge -- pointer to word currently being defined (or last defined word) 64440843Smsmith** If the definition completes successfully, the word will be 64540843Smsmith** linked into the hash table. If unsuccessful, dictUnsmudge 64640843Smsmith** uses this pointer to restore the previous state of the dictionary. 64740843Smsmith** Smudge prevents unintentional recursion as a side-effect: the 64840843Smsmith** dictionary search algo examines only completed definitions, so a 64940843Smsmith** word cannot invoke itself by name. See the ficl word "recurse". 65040843Smsmith** NOTE: smudge always points to the last word defined. IMMEDIATE 65140843Smsmith** makes use of this fact. Smudge is initially NULL. 65240843Smsmith** 65340843Smsmith** pForthWords -- pointer to the default wordlist (FICL_HASH). 65440843Smsmith** This is the initial compilation list, and contains all 65540843Smsmith** ficl's precompiled words. 65640843Smsmith** 65740843Smsmith** pCompile -- compilation wordlist - initially equal to pForthWords 65840843Smsmith** pSearch -- array of pointers to wordlists. Managed as a stack. 65940843Smsmith** Highest index is the first list in the search order. 66040843Smsmith** nLists -- number of lists in pSearch. nLists-1 is the highest 66140843Smsmith** filled slot in pSearch, and points to the first wordlist 66240843Smsmith** in the search order 66340843Smsmith** size -- number of cells in the dictionary (total) 66440843Smsmith** dict -- start of data area. Must be at the end of the struct. 66540843Smsmith*/ 66640843Smsmithtypedef struct ficl_dict 66740843Smsmith{ 66840843Smsmith CELL *here; 66940843Smsmith FICL_WORD *smudge; 67040843Smsmith FICL_HASH *pForthWords; 67140843Smsmith FICL_HASH *pCompile; 67240843Smsmith FICL_HASH *pSearch[FICL_DEFAULT_VOCS]; 67340843Smsmith int nLists; 67440843Smsmith unsigned size; /* Number of cells in dict (total)*/ 67560014Sdcs CELL *dict; /* Base of dictionary memory */ 67640843Smsmith} FICL_DICT; 67740843Smsmith 67840843Smsmithvoid *alignPtr(void *ptr); 67940843Smsmithvoid dictAbortDefinition(FICL_DICT *pDict); 68040843Smsmithvoid dictAlign(FICL_DICT *pDict); 68140843Smsmithint dictAllot(FICL_DICT *pDict, int n); 68240843Smsmithint dictAllotCells(FICL_DICT *pDict, int nCells); 68340843Smsmithvoid dictAppendCell(FICL_DICT *pDict, CELL c); 68440843Smsmithvoid dictAppendChar(FICL_DICT *pDict, char c); 68540843SmsmithFICL_WORD *dictAppendWord(FICL_DICT *pDict, 68640843Smsmith char *name, 68740843Smsmith FICL_CODE pCode, 68840843Smsmith UNS8 flags); 68940843SmsmithFICL_WORD *dictAppendWord2(FICL_DICT *pDict, 69040843Smsmith STRINGINFO si, 69140843Smsmith FICL_CODE pCode, 69240843Smsmith UNS8 flags); 69351786Sdcsvoid dictAppendUNS(FICL_DICT *pDict, FICL_UNS u); 69440843Smsmithint dictCellsAvail(FICL_DICT *pDict); 69540843Smsmithint dictCellsUsed (FICL_DICT *pDict); 69640843Smsmithvoid dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells); 69740843SmsmithFICL_DICT *dictCreate(unsigned nCELLS); 69840843SmsmithFICL_DICT *dictCreateHashed(unsigned nCells, unsigned nHash); 69940843Smsmithvoid dictDelete(FICL_DICT *pDict); 70040843Smsmithvoid dictEmpty(FICL_DICT *pDict, unsigned nHash); 70140843Smsmithint dictIncludes(FICL_DICT *pDict, void *p); 70240843SmsmithFICL_WORD *dictLookup(FICL_DICT *pDict, STRINGINFO si); 70340843Smsmith#if FICL_WANT_LOCALS 70440843SmsmithFICL_WORD *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si); 70540843Smsmith#endif 70640843Smsmithvoid dictResetSearchOrder(FICL_DICT *pDict); 70740843Smsmithvoid dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr); 70840843Smsmithvoid dictSetImmediate(FICL_DICT *pDict); 70940843Smsmithvoid dictUnsmudge(FICL_DICT *pDict); 71040843SmsmithCELL *dictWhere(FICL_DICT *pDict); 71140843Smsmith 71240843Smsmith 71340843Smsmith/* 71440843Smsmith** External interface to FICL... 71540843Smsmith*/ 71640843Smsmith/* 71740843Smsmith** f i c l I n i t S y s t e m 71840843Smsmith** Binds a global dictionary to the interpreter system and initializes 71940843Smsmith** the dict to contain the ANSI CORE wordset. 72040843Smsmith** You specify the address and size of the allocated area. 72140843Smsmith** After that, ficl manages it. 72240843Smsmith** First step is to set up the static pointers to the area. 72340843Smsmith** Then write the "precompiled" portion of the dictionary in. 72440843Smsmith** The dictionary needs to be at least large enough to hold the 72540843Smsmith** precompiled part. Try 1K cells minimum. Use "words" to find 72640843Smsmith** out how much of the dictionary is used at any time. 72740843Smsmith*/ 72840843Smsmithvoid ficlInitSystem(int nDictCells); 72940843Smsmith 73040843Smsmith/* 73140843Smsmith** f i c l T e r m S y s t e m 73240843Smsmith** Deletes the system dictionary and all virtual machines that 73340843Smsmith** were created with ficlNewVM (see below). Call this function to 73440843Smsmith** reclaim all memory used by the dictionary and VMs. 73540843Smsmith*/ 73640843Smsmithvoid ficlTermSystem(void); 73740843Smsmith 73840843Smsmith/* 73940843Smsmith** f i c l E x e c 74040843Smsmith** Evaluates a block of input text in the context of the 74140843Smsmith** specified interpreter. Emits any requested output to the 74251786Sdcs** interpreter's output function. If the input string is NULL 74351786Sdcs** terminated, you can pass -1 as nChars rather than count it. 74440843Smsmith** Execution returns when the text block has been executed, 74540843Smsmith** or an error occurs. 74640843Smsmith** Returns one of the VM_XXXX codes defined in ficl.h: 74740843Smsmith** VM_OUTOFTEXT is the normal exit condition 74840843Smsmith** VM_ERREXIT means that the interp encountered a syntax error 74940843Smsmith** and the vm has been reset to recover (some or all 75040843Smsmith** of the text block got ignored 75140843Smsmith** VM_USEREXIT means that the user executed the "bye" command 75240843Smsmith** to shut down the interpreter. This would be a good 75340843Smsmith** time to delete the vm, etc -- or you can ignore this 75440843Smsmith** signal. 75543078Smsmith** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"' 75643078Smsmith** commands. 75740843Smsmith** Preconditions: successful execution of ficlInitSystem, 75840843Smsmith** Successful creation and init of the VM by ficlNewVM (or equiv) 75940843Smsmith*/ 76051786Sdcsint ficlExec (FICL_VM *pVM, char *pText); 76151786Sdcsint ficlExecC(FICL_VM *pVM, char *pText, INT32 nChars); 76251786Sdcsint ficlExecXT(FICL_VM *pVM, FICL_WORD *pWord); 76340843Smsmith 76440843Smsmith/* 76540989Sjkh** ficlExecFD(FICL_VM *pVM, int fd); 76640989Sjkh * Evaluates text from file passed in via fd. 76740989Sjkh * Execution returns when all of file has been executed or an 76840989Sjkh * error occurs. 76940989Sjkh */ 77040989Sjkhint ficlExecFD(FICL_VM *pVM, int fd); 77140989Sjkh 77240989Sjkh/* 77340843Smsmith** Create a new VM from the heap, and link it into the system VM list. 77440843Smsmith** Initializes the VM and binds default sized stacks to it. Returns the 77540843Smsmith** address of the VM, or NULL if an error occurs. 77640843Smsmith** Precondition: successful execution of ficlInitSystem 77740843Smsmith*/ 77840843SmsmithFICL_VM *ficlNewVM(void); 77940843Smsmith 78040843Smsmith/* 78160959Sdcs** Force deletion of a VM. You do not need to do this 78260959Sdcs** unless you're creating and discarding a lot of VMs. 78360959Sdcs** For systems that use a constant pool of VMs for the life 78460959Sdcs** of the system, ficltermSystem takes care of VM cleanup 78560959Sdcs** automatically. 78660959Sdcs*/ 78760959Sdcsvoid ficlFreeVM(FICL_VM *pVM); 78860959Sdcs 78960959Sdcs 79060959Sdcs/* 79151786Sdcs** Set the stack sizes (return and parameter) to be used for all 79251786Sdcs** subsequently created VMs. Returns actual stack size to be used. 79351786Sdcs*/ 79451786Sdcsint ficlSetStackSize(int nStackCells); 79551786Sdcs 79651786Sdcs/* 79740843Smsmith** Returns the address of the most recently defined word in the system 79840843Smsmith** dictionary with the given name, or NULL if no match. 79940843Smsmith** Precondition: successful execution of ficlInitSystem 80040843Smsmith*/ 80140843SmsmithFICL_WORD *ficlLookup(char *name); 80240843Smsmith 80340843Smsmith/* 80440843Smsmith** f i c l G e t D i c t 80540843Smsmith** Utility function - returns the address of the system dictionary. 80640843Smsmith** Precondition: successful execution of ficlInitSystem 80740843Smsmith*/ 80840843SmsmithFICL_DICT *ficlGetDict(void); 80940843SmsmithFICL_DICT *ficlGetEnv(void); 81040843Smsmithvoid ficlSetEnv(char *name, UNS32 value); 81140843Smsmithvoid ficlSetEnvD(char *name, UNS32 hi, UNS32 lo); 81240843Smsmith#if FICL_WANT_LOCALS 81340843SmsmithFICL_DICT *ficlGetLoc(void); 81440843Smsmith#endif 81540843Smsmith/* 81640843Smsmith** f i c l B u i l d 81740843Smsmith** Builds a word into the system default dictionary in a thread-safe way. 81840843Smsmith** Preconditions: system must be initialized, and there must 81940843Smsmith** be enough space for the new word's header! Operation is 82040843Smsmith** controlled by ficlLockDictionary, so any initialization 82140843Smsmith** required by your version of the function (if you "overrode" 82240843Smsmith** it) must be complete at this point. 82340843Smsmith** Parameters: 82440843Smsmith** name -- the name of the word to be built 82540843Smsmith** code -- code to execute when the word is invoked - must take a single param 82640843Smsmith** pointer to a FICL_VM 82740843Smsmith** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR! 82840843Smsmith** Most words can use FW_DEFAULT. 82940843Smsmith** nAllot - number of extra cells to allocate in the parameter area (usually zero) 83040843Smsmith*/ 83140843Smsmithint ficlBuild(char *name, FICL_CODE code, char flags); 83240843Smsmith 83340843Smsmith/* 83440843Smsmith** f i c l C o m p i l e C o r e 83540843Smsmith** Builds the ANS CORE wordset into the dictionary - called by 83640843Smsmith** ficlInitSystem - no need to waste dict space by doing it again. 83740843Smsmith*/ 83840843Smsmithvoid ficlCompileCore(FICL_DICT *dp); 83940843Smsmithvoid ficlCompileSoftCore(FICL_VM *pVM); 84040843Smsmith 84140843Smsmith/* 84240843Smsmith** from words.c... 84340843Smsmith*/ 84440843Smsmithvoid constantParen(FICL_VM *pVM); 84540843Smsmithvoid twoConstParen(FICL_VM *pVM); 84640843Smsmith 84743139Smsmith/* 84860014Sdcs** Dictionary on-demand resizing 84960014Sdcs*/ 85060014Sdcsextern unsigned int dictThreshold; 85160014Sdcsextern unsigned int dictIncrease; 85260014Sdcs 85360014Sdcs/* 85443139Smsmith** So we can more easily debug... 85543139Smsmith*/ 85643139Smsmith#ifdef FICL_TRACE 85743139Smsmithextern int ficl_trace; 85843139Smsmith#endif 85943139Smsmith 86042679Sabial#if defined(__i386__) && !defined(TESTMAIN) 86142679Sabialextern void ficlOutb(FICL_VM *pVM); 86242679Sabialextern void ficlInb(FICL_VM *pVM); 86342634Sabial#endif 86442634Sabial 86540843Smsmith#ifdef __cplusplus 86640843Smsmith} 86740843Smsmith#endif 86840843Smsmith 86940843Smsmith#endif /* __FICL_H__ */ 870