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