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