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