ficl.h revision 51786
1/******************************************************************* 2** f i c l . h 3** Forth Inspired Command Language 4** Author: John Sadler (john_sadler@alum.mit.edu) 5** Created: 19 July 1997 6** 7*******************************************************************/ 8/* 9** N O T I C E -- DISCLAIMER OF WARRANTY 10** 11** Ficl is freeware. Use it in any way that you like, with 12** the understanding that the code is supported on a "best effort" 13** basis only. 14** 15** Any third party may reproduce, distribute, or modify the ficl 16** software code or any derivative works thereof without any 17** compensation or license, provided that the author information 18** and this disclaimer text are retained in the source code files. 19** The ficl software code is provided on an "as is" basis without 20** warranty of any kind, including, without limitation, the implied 21** warranties of merchantability and fitness for a particular purpose 22** and their equivalents under the laws of any jurisdiction. 23** 24** I am interested in hearing from anyone who uses ficl. If you have 25** a problem, a success story, a defect, an enhancement request, or 26** if you would like to contribute to the ficl release (yay!), please 27** send me email at the address above. 28*/ 29 30/* $FreeBSD: head/sys/boot/ficl/ficl.h 51786 1999-09-29 04:43:16Z dcs $ */ 31 32#if !defined (__FICL_H__) 33#define __FICL_H__ 34/* 35** Ficl (Forth-inspired command language) is an ANS Forth 36** interpreter written in C. Unlike traditional Forths, this 37** interpreter is designed to be embedded into other systems 38** as a command/macro/development prototype language. 39** 40** Where Forths usually view themselves as the center of the system 41** and expect the rest of the system to be coded in Forth, Ficl 42** acts as a component of the system. It is easy to export 43** code written in C or ASM to Ficl in the style of TCL, or to invoke 44** Ficl code from a compiled module. This allows you to do incremental 45** development in a way that combines the best features of threaded 46** languages (rapid development, quick code/test/debug cycle, 47** reasonably fast) with the best features of C (everyone knows it, 48** easier to support large blocks of code, efficient, type checking). 49** 50** Ficl provides facilities for interoperating 51** with programs written in C: C functions can be exported to Ficl, 52** and Ficl commands can be executed via a C calling interface. The 53** interpreter is re-entrant, so it can be used in multiple instances 54** in a multitasking system. Unlike Forth, Ficl's outer interpreter 55** expects a text block as input, and returns to the caller after each 56** text block, so the "data pump" is somewhere in external code. This 57** is more like TCL than Forth, which usually expcets to be at the center 58** of the system, requesting input at its convenience. Each Ficl virtual 59** machine can be bound to a different I/O channel, and is independent 60** of all others in in the same address space except that all virtual 61** machines share a common dictionary (a sort or open symbol table that 62** defines all of the elements of the language). 63** 64** Code is written in ANSI C for portability. 65** 66** Summary of Ficl features and constraints: 67** - Standard: Implements the ANSI Forth CORE word set and part 68** of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and 69** TOOLS EXT, LOCAL and LOCAL ext and various extras. 70** - Extensible: you can export code written in Forth, C, 71** or asm in a straightforward way. Ficl provides open 72** facilities for extending the language in an application 73** specific way. You can even add new control structures! 74** - Ficl and C can interact in two ways: Ficl can encapsulate 75** C code, or C code can invoke Ficl code. 76** - Thread-safe, re-entrant: The shared system dictionary 77** uses a locking mechanism that you can either supply 78** or stub out to provide exclusive access. Each Ficl 79** virtual machine has an otherwise complete state, and 80** each can be bound to a separate I/O channel (or none at all). 81** - Simple encapsulation into existing systems: a basic implementation 82** requires three function calls (see the example program in testmain.c). 83** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data 84** environments. It does require somewhat more memory than a pure 85** ROM implementation because it builds its system dictionary in 86** RAM at startup time. 87** - Written an ANSI C to be as simple as I can make it to understand, 88** support, debug, and port. Compiles without complaint at /Az /W4 89** (require ANSI C, max warnings) under Microsoft VC++ 5. 90** - Does full 32 bit math (but you need to implement 91** two mixed precision math primitives (see sysdep.c)) 92** - Indirect threaded interpreter is not the fastest kind of 93** Forth there is (see pForth 68K for a really fast subroutine 94** threaded interpreter), but it's the cleanest match to a 95** pure C implementation. 96** 97** P O R T I N G F i c l 98** 99** To install Ficl on your target system, you need an ANSI C compiler 100** and its runtime library. Inspect the system dependent macros and 101** functions in sysdep.h and sysdep.c and edit them to suit your 102** system. For example, INT16 is a short on some compilers and an 103** int on others. Check the default CELL alignment controlled by 104** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree, 105** ficlLockDictionary, and ficlTextOut to work with your operating system. 106** Finally, use testmain.c as a guide to installing the Ficl system and 107** one or more virtual machines into your code. You do not need to include 108** testmain.c in your build. 109** 110** T o D o L i s t 111** 112** 1. Unimplemented system dependent CORE word: key 113** 2. Kludged CORE word: ACCEPT 114** 3. Dictionary locking is full of holes - only one vm at a time 115** can alter the dict. 116** 4. Ficl uses the pad in CORE words - this violates the standard, 117** but it's cleaner for a multithreaded system. I'll have to make a 118** second pad for reference by the word PAD to fix this. 119** 120** F o r M o r e I n f o r m a t i o n 121** 122** Web home of ficl 123** http://www.taygeta.com/forth/compilers 124** Check this website for Forth literature (including the ANSI standard) 125** http://www.taygeta.com/forthlit.html 126** and here for software and more links 127** http://www.taygeta.com/forth.html 128** 129** Obvious Performance enhancement opportunities 130** Compile speed 131** - work on interpret speed 132** - turn off locals (FICL_WANT_LOCALS) 133** Interpret speed 134** - Change inner interpreter (and everything else) 135** so that a definition is a list of pointers to functions 136** and inline data rather than pointers to words. This gets 137** rid of vm->runningWord and a level of indirection in the 138** inner loop. I'll look at it for ficl 3.0 139** - Make the main hash table a bigger prime (HASHSIZE) 140** - FORGET about twiddling the hash function - my experience is 141** that that is a waste of time. 142** - eliminate the need to pass the pVM parameter on the stack 143** by dedicating a register to it. Most words need access to the 144** vm, but the parameter passing overhead can be reduced. One way 145** requires that the host OS have a task switch callout. Create 146** a global variable for the running VM and refer to it in words 147** that need VM access. Alternative: use thread local storage. 148** For single threaded implementations, you can just use a global. 149** The first two solutions create portability problems, so I 150** haven't considered doing them. Another possibility is to 151** declare the pVm parameter to be "register", and hope the compiler 152** pays attention. 153** 154*/ 155 156/* 157** Revision History: 158** 159** 15 Apr 1999 (sadler) Merged FreeBSD changes for exception wordset and 160** counted strings in ficlExec. 161** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an 162** "end" field, and all words respect this. ficlExec is passed a "size" 163** of TIB, as well as vmPushTib. This size is used to calculate the "end" 164** of the string, ie, base+size. If the size is not known, pass -1. 165** 166** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing 167** words has been modified to conform to EXCEPTION EXT word set. 168** 169** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT, 170** SEARCH / SEARCH EXT, TOOLS / TOOLS EXT. 171** Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD, 172** EMPTY to clear stack. 173** 174** 29 jun 1998 (sadler) added variable sized hash table support 175** and ANS Forth optional SEARCH & SEARCH EXT word set. 176** 26 May 1998 (sadler) 177** FICL_PROMPT macro 178** 14 April 1998 (sadler) V1.04 179** Ficlwin: Windows version, Skip Carter's Linux port 180** 5 March 1998 (sadler) V1.03 181** Bug fixes -- passes John Ryan's ANS test suite "core.fr" 182** 183** 24 February 1998 (sadler) V1.02 184** -Fixed bugs in <# # #> 185** -Changed FICL_WORD so that storage for the name characters 186** can be allocated from the dictionary as needed rather than 187** reserving 32 bytes in each word whether needed or not - 188** this saved 50% of the dictionary storage requirement. 189** -Added words in testmain for Win32 functions system,chdir,cwd, 190** also added a word that loads and evaluates a file. 191** 192** December 1997 (sadler) 193** -Added VM_RESTART exception handling in ficlExec -- this lets words 194** that require additional text to succeed (like :, create, variable...) 195** recover gracefully from an empty input buffer rather than emitting 196** an error message. Definitions can span multiple input blocks with 197** no restrictions. 198** -Changed #include order so that <assert.h> is included in sysdep.h, 199** and sysdep is included in all other files. This lets you define 200** NDEBUG in sysdep.h to disable assertions if you want to. 201** -Make PC specific system dependent code conditional on _M_IX86 202** defined so that ports can coexist in sysdep.h/sysdep.c 203*/ 204 205#ifdef __cplusplus 206extern "C" { 207#endif 208 209#include "sysdep.h" 210#include <limits.h> /* UCHAR_MAX */ 211 212/* 213** Forward declarations... read on. 214*/ 215struct ficl_word; 216struct vm; 217struct ficl_dict; 218 219/* 220** the Good Stuff starts here... 221*/ 222#define FICL_VER "2.03" 223#if !defined (FICL_PROMPT) 224#define FICL_PROMPT "ok> " 225#endif 226 227/* 228** ANS Forth requires false to be zero, and true to be the ones 229** complement of false... that unifies logical and bitwise operations 230** nicely. 231*/ 232#define FICL_TRUE (0xffffffffL) 233#define FICL_FALSE (0) 234#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE) 235 236 237/* 238** A CELL is the main storage type. It must be large enough 239** to contain a pointer or a scalar. In order to accommodate 240** 32 bit and 64 bit processors, use abstract types for i and u. 241*/ 242typedef union _cell 243{ 244 FICL_INT i; 245 FICL_UNS u; 246 void *p; 247} CELL; 248 249/* 250** LVALUEtoCELL does a little pointer trickery to cast any 32 bit 251** lvalue (informal definition: an expression whose result has an 252** address) to CELL. Remember that constants and casts are NOT 253** themselves lvalues! 254*/ 255#define LVALUEtoCELL(v) (*(CELL *)&v) 256 257/* 258** PTRtoCELL is a cast through void * intended to satisfy the 259** most outrageously pedantic compiler... (I won't mention 260** its name) 261*/ 262#define PTRtoCELL (CELL *)(void *) 263#define PTRtoSTRING (FICL_STRING *)(void *) 264 265/* 266** Strings in FICL are stored in Pascal style - with a count 267** preceding the text. We'll also NULL-terminate them so that 268** they work with the usual C lib string functions. (Belt & 269** suspenders? You decide.) 270** STRINGINFO hides the implementation with a couple of 271** macros for use in internal routines. 272*/ 273 274typedef unsigned char FICL_COUNT; 275#define FICL_STRING_MAX UCHAR_MAX 276typedef struct _ficl_string 277{ 278 FICL_COUNT count; 279 char text[1]; 280} FICL_STRING; 281 282typedef struct 283{ 284 UNS32 count; 285 char *cp; 286} STRINGINFO; 287 288#define SI_COUNT(si) (si.count) 289#define SI_PTR(si) (si.cp) 290#define SI_SETLEN(si, len) (si.count = (UNS32)(len)) 291#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr)) 292/* 293** Init a STRINGINFO from a pointer to NULL-terminated string 294*/ 295#define SI_PSZ(si, psz) \ 296 {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);} 297/* 298** Init a STRINGINFO from a pointer to FICL_STRING 299*/ 300#define SI_PFS(si, pfs) \ 301 {si.cp = pfs->text; si.count = pfs->count;} 302 303/* 304** Ficl uses a this little structure to hold the address of 305** the block of text it's working on and an index to the next 306** unconsumed character in the string. Traditionally, this is 307** done by a Text Input Buffer, so I've called this struct TIB. 308** 309** Since this structure also holds the size of the input buffer, 310** and since evaluate requires that, let's put the size here. 311** The size is stored as an end-pointer because that is what the 312** null-terminated string aware functions find most easy to deal 313** with. 314** Notice, though, that nobody really uses this except evaluate, 315** so it might just be moved to FICL_VM instead. (sobral) 316*/ 317typedef struct 318{ 319 INT32 index; 320 char *end; 321 char *cp; 322} TIB; 323 324 325/* 326** Stacks get heavy use in Ficl and Forth... 327** Each virtual machine implements two of them: 328** one holds parameters (data), and the other holds return 329** addresses and control flow information for the virtual 330** machine. (Note: C's automatic stack is implicitly used, 331** but not modeled because it doesn't need to be...) 332** Here's an abstract type for a stack 333*/ 334typedef struct _ficlStack 335{ 336 FICL_UNS nCells; /* size of the stack */ 337 CELL *pFrame; /* link reg for stack frame */ 338 CELL *sp; /* stack pointer */ 339 CELL base[1]; /* Bottom of the stack */ 340} FICL_STACK; 341 342/* 343** Stack methods... many map closely to required Forth words. 344*/ 345FICL_STACK *stackCreate(unsigned nCells); 346void stackDelete(FICL_STACK *pStack); 347int stackDepth (FICL_STACK *pStack); 348void stackDrop (FICL_STACK *pStack, int n); 349CELL stackFetch (FICL_STACK *pStack, int n); 350CELL stackGetTop(FICL_STACK *pStack); 351void stackLink (FICL_STACK *pStack, int nCells); 352void stackPick (FICL_STACK *pStack, int n); 353CELL stackPop (FICL_STACK *pStack); 354void *stackPopPtr (FICL_STACK *pStack); 355FICL_UNS stackPopUNS(FICL_STACK *pStack); 356FICL_INT stackPopINT(FICL_STACK *pStack); 357void stackPush (FICL_STACK *pStack, CELL c); 358void stackPushPtr (FICL_STACK *pStack, void *ptr); 359void stackPushUNS(FICL_STACK *pStack, FICL_UNS u); 360void stackPushINT(FICL_STACK *pStack, FICL_INT i); 361void stackReset (FICL_STACK *pStack); 362void stackRoll (FICL_STACK *pStack, int n); 363void stackSetTop(FICL_STACK *pStack, CELL c); 364void stackStore (FICL_STACK *pStack, int n, CELL c); 365void stackUnlink(FICL_STACK *pStack); 366 367/* 368** The virtual machine (VM) contains the state for one interpreter. 369** Defined operations include: 370** Create & initialize 371** Delete 372** Execute a block of text 373** Parse a word out of the input stream 374** Call return, and branch 375** Text output 376** Throw an exception 377*/ 378 379typedef struct ficl_word ** IPTYPE; /* the VM's instruction pointer */ 380 381/* 382** Each VM has a placeholder for an output function - 383** this makes it possible to have each VM do I/O 384** through a different device. If you specify no 385** OUTFUNC, it defaults to ficlTextOut. 386*/ 387typedef void (*OUTFUNC)(struct vm *pVM, char *text, int fNewline); 388 389/* 390** Each VM operates in one of two non-error states: interpreting 391** or compiling. When interpreting, words are simply executed. 392** When compiling, most words in the input stream have their 393** addresses inserted into the word under construction. Some words 394** (known as IMMEDIATE) are executed in the compile state, too. 395*/ 396/* values of STATE */ 397#define INTERPRET 0 398#define COMPILE 1 399 400/* 401** The pad is a small scratch area for text manipulation. ANS Forth 402** requires it to hold at least 84 characters. 403*/ 404#if !defined nPAD 405#define nPAD 256 406#endif 407 408/* 409** ANS Forth requires that a word's name contain {1..31} characters. 410*/ 411#if !defined nFICLNAME 412#define nFICLNAME 31 413#endif 414 415/* 416** OK - now we can really define the VM... 417*/ 418typedef struct vm 419{ 420 struct vm *link; /* Ficl keeps a VM list for simple teardown */ 421 jmp_buf *pState; /* crude exception mechanism... */ 422 OUTFUNC textOut; /* Output callback - see sysdep.c */ 423 void * pExtend; /* vm extension pointer */ 424 short fRestart; /* Set TRUE to restart runningWord */ 425 IPTYPE ip; /* instruction pointer */ 426 struct ficl_word 427 *runningWord;/* address of currently running word (often just *(ip-1) ) */ 428 UNS32 state; /* compiling or interpreting */ 429 UNS32 base; /* number conversion base */ 430 FICL_STACK *pStack; /* param stack */ 431 FICL_STACK *rStack; /* return stack */ 432 CELL sourceID; /* -1 if string, 0 if normal input */ 433 TIB tib; /* address of incoming text string */ 434#if FICL_WANT_USER 435 CELL user[FICL_USER_CELLS]; 436#endif 437 char pad[nPAD]; /* the scratch area (see above) */ 438} FICL_VM; 439 440/* 441** A FICL_CODE points to a function that gets called to help execute 442** a word in the dictionary. It always gets passed a pointer to the 443** running virtual machine, and from there it can get the address 444** of the parameter area of the word it's supposed to operate on. 445** For precompiled words, the code is all there is. For user defined 446** words, the code assumes that the word's parameter area is a list 447** of pointers to the code fields of other words to execute, and 448** may also contain inline data. The first parameter is always 449** a pointer to a code field. 450*/ 451typedef void (*FICL_CODE)(FICL_VM *pVm); 452 453#if 0 454#define VM_ASSERT(pVM) assert((*(pVM->ip - 1)) == pVM->runningWord) 455#else 456#define VM_ASSERT(pVM) 457#endif 458 459/* 460** Ficl models memory as a contiguous space divided into 461** words in a linked list called the dictionary. 462** A FICL_WORD starts each entry in the list. 463** Version 1.02: space for the name characters is allotted from 464** the dictionary ahead of the word struct - this saves about half 465** the storage on average with very little runtime cost. 466*/ 467typedef struct ficl_word 468{ 469 struct ficl_word *link; /* Previous word in the dictionary */ 470 UNS16 hash; 471 UNS8 flags; /* Immediate, Smudge, Compile-only */ 472 FICL_COUNT nName; /* Number of chars in word name */ 473 char *name; /* First nFICLNAME chars of word name */ 474 FICL_CODE code; /* Native code to execute the word */ 475 CELL param[1]; /* First data cell of the word */ 476} FICL_WORD; 477 478/* 479** Worst-case size of a word header: nFICLNAME chars in name 480*/ 481#define CELLS_PER_WORD \ 482 ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \ 483 / (sizeof (CELL)) ) 484 485int wordIsImmediate(FICL_WORD *pFW); 486int wordIsCompileOnly(FICL_WORD *pFW); 487 488/* flag values for word header */ 489#define FW_IMMEDIATE 1 /* execute me even if compiling */ 490#define FW_COMPILE 2 /* error if executed when not compiling */ 491#define FW_SMUDGE 4 /* definition in progress - hide me */ 492#define FW_CLASS 8 /* Word defines a class */ 493 494#define FW_COMPIMMED (FW_IMMEDIATE | FW_COMPILE) 495#define FW_DEFAULT 0 496 497 498/* 499** Exit codes for vmThrow 500*/ 501#define VM_INNEREXIT -256 /* tell ficlExecXT to exit inner loop */ 502#define VM_OUTOFTEXT -257 /* hungry - normal exit */ 503#define VM_RESTART -258 /* word needs more text to succeed - re-run it */ 504#define VM_USEREXIT -259 /* user wants to quit */ 505#define VM_ERREXIT -260 /* interp found an error */ 506#define VM_ABORT -1 /* like errexit -- abort */ 507#define VM_ABORTQ -2 /* like errexit -- abort" */ 508#define VM_QUIT -56 /* like errexit, but leave pStack & base alone */ 509 510 511void vmBranchRelative(FICL_VM *pVM, int offset); 512FICL_VM * vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack); 513void vmDelete (FICL_VM *pVM); 514void vmExecute(FICL_VM *pVM, FICL_WORD *pWord); 515char * vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter); 516STRINGINFO vmGetWord(FICL_VM *pVM); 517STRINGINFO vmGetWord0(FICL_VM *pVM); 518int vmGetWordToPad(FICL_VM *pVM); 519STRINGINFO vmParseString(FICL_VM *pVM, char delimiter); 520void vmPopIP (FICL_VM *pVM); 521void vmPushIP (FICL_VM *pVM, IPTYPE newIP); 522void vmQuit (FICL_VM *pVM); 523void vmReset (FICL_VM *pVM); 524void vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut); 525void vmTextOut(FICL_VM *pVM, char *text, int fNewline); 526void vmThrow (FICL_VM *pVM, int except); 527void vmThrowErr(FICL_VM *pVM, char *fmt, ...); 528 529#define vmGetRunningWord(pVM) ((pVM)->runningWord) 530 531 532/* 533** The inner interpreter - coded as a macro (see note for 534** INLINE_INNER_LOOP in sysdep.h for complaints about VC++ 5 535*/ 536#define M_INNER_LOOP(pVM) \ 537 for (;;) \ 538 { \ 539 FICL_WORD *tempFW = *(pVM)->ip++; \ 540 (pVM)->runningWord = tempFW; \ 541 tempFW->code(pVM); \ 542 } 543 544 545#if INLINE_INNER_LOOP != 0 546#define vmInnerLoop(pVM) M_INNER_LOOP(pVM) 547#else 548void vmInnerLoop(FICL_VM *pVM); 549#endif 550 551/* 552** vmCheckStack needs a vm pointer because it might have to say 553** something if it finds a problem. Parms popCells and pushCells 554** correspond to the number of parameters on the left and right of 555** a word's stack effect comment. 556*/ 557void vmCheckStack(FICL_VM *pVM, int popCells, int pushCells); 558 559/* 560** TIB access routines... 561** ANS forth seems to require the input buffer to be represented 562** as a pointer to the start of the buffer, and an index to the 563** next character to read. 564** PushTib points the VM to a new input string and optionally 565** returns a copy of the current state 566** PopTib restores the TIB state given a saved TIB from PushTib 567** GetInBuf returns a pointer to the next unused char of the TIB 568*/ 569void vmPushTib(FICL_VM *pVM, char *text, INT32 nChars, TIB *pSaveTib); 570void vmPopTib(FICL_VM *pVM, TIB *pTib); 571#define vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index) 572#define vmGetInBufLen(pVM) ((pVM)->tib.end - (pVM)->tib.cp) 573#define vmGetInBufEnd(pVM) ((pVM)->tib.end) 574#define vmSetTibIndex(pVM, i) (pVM)->tib.index = i 575#define vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp 576 577/* 578** Generally useful string manipulators omitted by ANSI C... 579** ltoa complements strtol 580*/ 581#if defined(_WIN32) && !FICL_MAIN 582/* #SHEESH 583** Why do Microsoft Meatballs insist on contaminating 584** my namespace with their string functions??? 585*/ 586#pragma warning(disable: 4273) 587#endif 588 589int isPowerOfTwo(FICL_UNS u); 590 591char *ltoa( FICL_INT value, char *string, int radix ); 592char *ultoa(FICL_UNS value, char *string, int radix ); 593char digit_to_char(int value); 594char *strrev( char *string ); 595char *skipSpace(char *cp, char *end); 596char *caseFold(char *cp); 597int strincmp(char *cp1, char *cp2, FICL_COUNT count); 598 599#if defined(_WIN32) && !FICL_MAIN 600#pragma warning(default: 4273) 601#endif 602 603/* 604** Ficl hash table - variable size. 605** assert(size > 0) 606** If size is 1, the table degenerates into a linked list. 607** A WORDLIST (see the search order word set in DPANS) is 608** just a pointer to a FICL_HASH in this implementation. 609*/ 610#if !defined HASHSIZE /* Default size of hash table. For most uniform */ 611#define HASHSIZE 127 /* performance, use a prime number! */ 612#endif 613 614typedef struct ficl_hash 615{ 616 struct ficl_hash *link; /* eventual inheritance support */ 617 unsigned size; 618 FICL_WORD *table[1]; 619} FICL_HASH; 620 621void hashForget(FICL_HASH *pHash, void *where); 622UNS16 hashHashCode(STRINGINFO si); 623void hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW); 624FICL_WORD *hashLookup(struct ficl_hash *pHash, 625 STRINGINFO si, 626 UNS16 hashCode); 627void hashReset(FICL_HASH *pHash); 628 629/* 630** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's 631** memory model. Description of fields: 632** 633** here -- points to the next free byte in the dictionary. This 634** pointer is forced to be CELL-aligned before a definition is added. 635** Do not assume any specific alignment otherwise - Use dictAlign(). 636** 637** smudge -- pointer to word currently being defined (or last defined word) 638** If the definition completes successfully, the word will be 639** linked into the hash table. If unsuccessful, dictUnsmudge 640** uses this pointer to restore the previous state of the dictionary. 641** Smudge prevents unintentional recursion as a side-effect: the 642** dictionary search algo examines only completed definitions, so a 643** word cannot invoke itself by name. See the ficl word "recurse". 644** NOTE: smudge always points to the last word defined. IMMEDIATE 645** makes use of this fact. Smudge is initially NULL. 646** 647** pForthWords -- pointer to the default wordlist (FICL_HASH). 648** This is the initial compilation list, and contains all 649** ficl's precompiled words. 650** 651** pCompile -- compilation wordlist - initially equal to pForthWords 652** pSearch -- array of pointers to wordlists. Managed as a stack. 653** Highest index is the first list in the search order. 654** nLists -- number of lists in pSearch. nLists-1 is the highest 655** filled slot in pSearch, and points to the first wordlist 656** in the search order 657** size -- number of cells in the dictionary (total) 658** dict -- start of data area. Must be at the end of the struct. 659*/ 660typedef struct ficl_dict 661{ 662 CELL *here; 663 FICL_WORD *smudge; 664 FICL_HASH *pForthWords; 665 FICL_HASH *pCompile; 666 FICL_HASH *pSearch[FICL_DEFAULT_VOCS]; 667 int nLists; 668 unsigned size; /* Number of cells in dict (total)*/ 669 CELL dict[1]; /* Base of dictionary memory */ 670} FICL_DICT; 671 672void *alignPtr(void *ptr); 673void dictAbortDefinition(FICL_DICT *pDict); 674void dictAlign(FICL_DICT *pDict); 675int dictAllot(FICL_DICT *pDict, int n); 676int dictAllotCells(FICL_DICT *pDict, int nCells); 677void dictAppendCell(FICL_DICT *pDict, CELL c); 678void dictAppendChar(FICL_DICT *pDict, char c); 679FICL_WORD *dictAppendWord(FICL_DICT *pDict, 680 char *name, 681 FICL_CODE pCode, 682 UNS8 flags); 683FICL_WORD *dictAppendWord2(FICL_DICT *pDict, 684 STRINGINFO si, 685 FICL_CODE pCode, 686 UNS8 flags); 687void dictAppendUNS(FICL_DICT *pDict, FICL_UNS u); 688int dictCellsAvail(FICL_DICT *pDict); 689int dictCellsUsed (FICL_DICT *pDict); 690void dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells); 691FICL_DICT *dictCreate(unsigned nCELLS); 692FICL_DICT *dictCreateHashed(unsigned nCells, unsigned nHash); 693void dictDelete(FICL_DICT *pDict); 694void dictEmpty(FICL_DICT *pDict, unsigned nHash); 695int dictIncludes(FICL_DICT *pDict, void *p); 696FICL_WORD *dictLookup(FICL_DICT *pDict, STRINGINFO si); 697#if FICL_WANT_LOCALS 698FICL_WORD *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si); 699#endif 700void dictResetSearchOrder(FICL_DICT *pDict); 701void dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr); 702void dictSetImmediate(FICL_DICT *pDict); 703void dictUnsmudge(FICL_DICT *pDict); 704CELL *dictWhere(FICL_DICT *pDict); 705 706 707/* 708** External interface to FICL... 709*/ 710/* 711** f i c l I n i t S y s t e m 712** Binds a global dictionary to the interpreter system and initializes 713** the dict to contain the ANSI CORE wordset. 714** You specify the address and size of the allocated area. 715** After that, ficl manages it. 716** First step is to set up the static pointers to the area. 717** Then write the "precompiled" portion of the dictionary in. 718** The dictionary needs to be at least large enough to hold the 719** precompiled part. Try 1K cells minimum. Use "words" to find 720** out how much of the dictionary is used at any time. 721*/ 722void ficlInitSystem(int nDictCells); 723 724/* 725** f i c l T e r m S y s t e m 726** Deletes the system dictionary and all virtual machines that 727** were created with ficlNewVM (see below). Call this function to 728** reclaim all memory used by the dictionary and VMs. 729*/ 730void ficlTermSystem(void); 731 732/* 733** f i c l E x e c 734** Evaluates a block of input text in the context of the 735** specified interpreter. Emits any requested output to the 736** interpreter's output function. If the input string is NULL 737** terminated, you can pass -1 as nChars rather than count it. 738** Execution returns when the text block has been executed, 739** or an error occurs. 740** Returns one of the VM_XXXX codes defined in ficl.h: 741** VM_OUTOFTEXT is the normal exit condition 742** VM_ERREXIT means that the interp encountered a syntax error 743** and the vm has been reset to recover (some or all 744** of the text block got ignored 745** VM_USEREXIT means that the user executed the "bye" command 746** to shut down the interpreter. This would be a good 747** time to delete the vm, etc -- or you can ignore this 748** signal. 749** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"' 750** commands. 751** Preconditions: successful execution of ficlInitSystem, 752** Successful creation and init of the VM by ficlNewVM (or equiv) 753*/ 754int ficlExec (FICL_VM *pVM, char *pText); 755int ficlExecC(FICL_VM *pVM, char *pText, INT32 nChars); 756int ficlExecXT(FICL_VM *pVM, FICL_WORD *pWord); 757 758/* 759** ficlExecFD(FICL_VM *pVM, int fd); 760 * Evaluates text from file passed in via fd. 761 * Execution returns when all of file has been executed or an 762 * error occurs. 763 */ 764int ficlExecFD(FICL_VM *pVM, int fd); 765 766/* 767** Create a new VM from the heap, and link it into the system VM list. 768** Initializes the VM and binds default sized stacks to it. Returns the 769** address of the VM, or NULL if an error occurs. 770** Precondition: successful execution of ficlInitSystem 771*/ 772FICL_VM *ficlNewVM(void); 773 774/* 775** Set the stack sizes (return and parameter) to be used for all 776** subsequently created VMs. Returns actual stack size to be used. 777*/ 778int ficlSetStackSize(int nStackCells); 779 780/* 781** Returns the address of the most recently defined word in the system 782** dictionary with the given name, or NULL if no match. 783** Precondition: successful execution of ficlInitSystem 784*/ 785FICL_WORD *ficlLookup(char *name); 786 787/* 788** f i c l G e t D i c t 789** Utility function - returns the address of the system dictionary. 790** Precondition: successful execution of ficlInitSystem 791*/ 792FICL_DICT *ficlGetDict(void); 793FICL_DICT *ficlGetEnv(void); 794void ficlSetEnv(char *name, UNS32 value); 795void ficlSetEnvD(char *name, UNS32 hi, UNS32 lo); 796#if FICL_WANT_LOCALS 797FICL_DICT *ficlGetLoc(void); 798#endif 799/* 800** f i c l B u i l d 801** Builds a word into the system default dictionary in a thread-safe way. 802** Preconditions: system must be initialized, and there must 803** be enough space for the new word's header! Operation is 804** controlled by ficlLockDictionary, so any initialization 805** required by your version of the function (if you "overrode" 806** it) must be complete at this point. 807** Parameters: 808** name -- the name of the word to be built 809** code -- code to execute when the word is invoked - must take a single param 810** pointer to a FICL_VM 811** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR! 812** Most words can use FW_DEFAULT. 813** nAllot - number of extra cells to allocate in the parameter area (usually zero) 814*/ 815int ficlBuild(char *name, FICL_CODE code, char flags); 816 817/* 818** f i c l C o m p i l e C o r e 819** Builds the ANS CORE wordset into the dictionary - called by 820** ficlInitSystem - no need to waste dict space by doing it again. 821*/ 822void ficlCompileCore(FICL_DICT *dp); 823void ficlCompileSoftCore(FICL_VM *pVM); 824 825/* 826** from words.c... 827*/ 828void constantParen(FICL_VM *pVM); 829void twoConstParen(FICL_VM *pVM); 830 831/* 832** So we can more easily debug... 833*/ 834#ifdef FICL_TRACE 835extern int ficl_trace; 836#endif 837 838#if defined(__i386__) && !defined(TESTMAIN) 839extern void ficlOutb(FICL_VM *pVM); 840extern void ficlInb(FICL_VM *pVM); 841#endif 842 843#ifdef __cplusplus 844} 845#endif 846 847#endif /* __FICL_H__ */ 848