1 /*******************************************************************
3 ** Forth Inspired Command Language
4 ** Author: John Sadler (john_sadler@alum.mit.edu)
5 ** Created: 19 July 1997
6 ** Dedicated to RHS, in loving memory
7 ** $Id: ficl.h,v 1.18 2001/12/05 07:21:34 jsadler Exp $
8 *******************************************************************/
10 ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
11 ** All rights reserved.
13 ** Get the latest Ficl release at http://ficl.sourceforge.net
15 ** I am interested in hearing from anyone who uses ficl. If you have
16 ** a problem, a success story, a defect, an enhancement request, or
17 ** if you would like to contribute to the ficl release, please
18 ** contact me by email at the address above.
20 ** L I C E N S E and D I S C L A I M E R
22 ** Redistribution and use in source and binary forms, with or without
23 ** modification, are permitted provided that the following conditions
25 ** 1. Redistributions of source code must retain the above copyright
26 ** notice, this list of conditions and the following disclaimer.
27 ** 2. Redistributions in binary form must reproduce the above copyright
28 ** notice, this list of conditions and the following disclaimer in the
29 ** documentation and/or other materials provided with the distribution.
31 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
32 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
35 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 #if !defined (__FICL_H__)
48 ** Ficl (Forth-inspired command language) is an ANS Forth
49 ** interpreter written in C. Unlike traditional Forths, this
50 ** interpreter is designed to be embedded into other systems
51 ** as a command/macro/development prototype language.
53 ** Where Forths usually view themselves as the center of the system
54 ** and expect the rest of the system to be coded in Forth, Ficl
55 ** acts as a component of the system. It is easy to export
56 ** code written in C or ASM to Ficl in the style of TCL, or to invoke
57 ** Ficl code from a compiled module. This allows you to do incremental
58 ** development in a way that combines the best features of threaded
59 ** languages (rapid development, quick code/test/debug cycle,
60 ** reasonably fast) with the best features of C (everyone knows it,
61 ** easier to support large blocks of code, efficient, type checking).
63 ** Ficl provides facilities for interoperating
64 ** with programs written in C: C functions can be exported to Ficl,
65 ** and Ficl commands can be executed via a C calling interface. The
66 ** interpreter is re-entrant, so it can be used in multiple instances
67 ** in a multitasking system. Unlike Forth, Ficl's outer interpreter
68 ** expects a text block as input, and returns to the caller after each
69 ** text block, so the "data pump" is somewhere in external code. This
70 ** is more like TCL than Forth, which usually expcets to be at the center
71 ** of the system, requesting input at its convenience. Each Ficl virtual
72 ** machine can be bound to a different I/O channel, and is independent
73 ** of all others in in the same address space except that all virtual
74 ** machines share a common dictionary (a sort or open symbol table that
75 ** defines all of the elements of the language).
77 ** Code is written in ANSI C for portability.
79 ** Summary of Ficl features and constraints:
80 ** - Standard: Implements the ANSI Forth CORE word set and part
81 ** of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and
82 ** TOOLS EXT, LOCAL and LOCAL ext and various extras.
83 ** - Extensible: you can export code written in Forth, C,
84 ** or asm in a straightforward way. Ficl provides open
85 ** facilities for extending the language in an application
86 ** specific way. You can even add new control structures!
87 ** - Ficl and C can interact in two ways: Ficl can encapsulate
88 ** C code, or C code can invoke Ficl code.
89 ** - Thread-safe, re-entrant: The shared system dictionary
90 ** uses a locking mechanism that you can either supply
91 ** or stub out to provide exclusive access. Each Ficl
92 ** virtual machine has an otherwise complete state, and
93 ** each can be bound to a separate I/O channel (or none at all).
94 ** - Simple encapsulation into existing systems: a basic implementation
95 ** requires three function calls (see the example program in testmain.c).
96 ** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data
97 ** environments. It does require somewhat more memory than a pure
98 ** ROM implementation because it builds its system dictionary in
99 ** RAM at startup time.
100 ** - Written an ANSI C to be as simple as I can make it to understand,
101 ** support, debug, and port. Compiles without complaint at /Az /W4
102 ** (require ANSI C, max warnings) under Microsoft VC++ 5.
103 ** - Does full 32 bit math (but you need to implement
104 ** two mixed precision math primitives (see sysdep.c))
105 ** - Indirect threaded interpreter is not the fastest kind of
106 ** Forth there is (see pForth 68K for a really fast subroutine
107 ** threaded interpreter), but it's the cleanest match to a
108 ** pure C implementation.
110 ** P O R T I N G F i c l
112 ** To install Ficl on your target system, you need an ANSI C compiler
113 ** and its runtime library. Inspect the system dependent macros and
114 ** functions in sysdep.h and sysdep.c and edit them to suit your
115 ** system. For example, INT16 is a short on some compilers and an
116 ** int on others. Check the default CELL alignment controlled by
117 ** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree,
118 ** ficlLockDictionary, and ficlTextOut to work with your operating system.
119 ** Finally, use testmain.c as a guide to installing the Ficl system and
120 ** one or more virtual machines into your code. You do not need to include
121 ** testmain.c in your build.
125 ** 1. Unimplemented system dependent CORE word: key
126 ** 2. Ficl uses the PAD in some CORE words - this violates the standard,
127 ** but it's cleaner for a multithreaded system. I'll have to make a
128 ** second pad for reference by the word PAD to fix this.
130 ** F o r M o r e I n f o r m a t i o n
133 ** http://ficl.sourceforge.net
134 ** Check this website for Forth literature (including the ANSI standard)
135 ** http://www.taygeta.com/forthlit.html
136 ** and here for software and more links
137 ** http://www.taygeta.com/forth.html
139 ** Obvious Performance enhancement opportunities
141 ** - work on interpret speed
142 ** - turn off locals (FICL_WANT_LOCALS)
144 ** - Change inner interpreter (and everything else)
145 ** so that a definition is a list of pointers to functions
146 ** and inline data rather than pointers to words. This gets
147 ** rid of vm->runningWord and a level of indirection in the
148 ** inner loop. I'll look at it for ficl 3.0
149 ** - Make the main hash table a bigger prime (HASHSIZE)
150 ** - FORGET about twiddling the hash function - my experience is
151 ** that that is a waste of time.
152 ** - Eliminate the need to pass the pVM parameter on the stack
153 ** by dedicating a register to it. Most words need access to the
154 ** vm, but the parameter passing overhead can be reduced. One way
155 ** requires that the host OS have a task switch callout. Create
156 ** a global variable for the running VM and refer to it in words
157 ** that need VM access. Alternative: use thread local storage.
158 ** For single threaded implementations, you can just use a global.
159 ** The first two solutions create portability problems, so I
160 ** haven't considered doing them. Another possibility is to
161 ** declare the pVm parameter to be "register", and hope the compiler
169 ** 15 Apr 1999 (sadler) Merged FreeBSD changes for exception wordset and
170 ** counted strings in ficlExec.
171 ** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an
172 ** "end" field, and all words respect this. ficlExec is passed a "size"
173 ** of TIB, as well as vmPushTib. This size is used to calculate the "end"
174 ** of the string, ie, base+size. If the size is not known, pass -1.
176 ** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing
177 ** words has been modified to conform to EXCEPTION EXT word set.
179 ** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT,
180 ** SEARCH / SEARCH EXT, TOOLS / TOOLS EXT.
181 ** Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD,
182 ** EMPTY to clear stack.
184 ** 29 jun 1998 (sadler) added variable sized hash table support
185 ** and ANS Forth optional SEARCH & SEARCH EXT word set.
186 ** 26 May 1998 (sadler)
188 ** 14 April 1998 (sadler) V1.04
189 ** Ficlwin: Windows version, Skip Carter's Linux port
190 ** 5 March 1998 (sadler) V1.03
191 ** Bug fixes -- passes John Ryan's ANS test suite "core.fr"
193 ** 24 February 1998 (sadler) V1.02
194 ** -Fixed bugs in <# # #>
195 ** -Changed FICL_WORD so that storage for the name characters
196 ** can be allocated from the dictionary as needed rather than
197 ** reserving 32 bytes in each word whether needed or not -
198 ** this saved 50% of the dictionary storage requirement.
199 ** -Added words in testmain for Win32 functions system,chdir,cwd,
200 ** also added a word that loads and evaluates a file.
202 ** December 1997 (sadler)
203 ** -Added VM_RESTART exception handling in ficlExec -- this lets words
204 ** that require additional text to succeed (like :, create, variable...)
205 ** recover gracefully from an empty input buffer rather than emitting
206 ** an error message. Definitions can span multiple input blocks with
208 ** -Changed #include order so that <assert.h> is included in sysdep.h,
209 ** and sysdep is included in all other files. This lets you define
210 ** NDEBUG in sysdep.h to disable assertions if you want to.
211 ** -Make PC specific system dependent code conditional on _M_IX86
212 ** defined so that ports can coexist in sysdep.h/sysdep.c
220 #include <limits.h> /* UCHAR_MAX */
223 ** Forward declarations... read on.
226 typedef struct ficl_word FICL_WORD
;
228 typedef struct vm FICL_VM
;
230 typedef struct ficl_dict FICL_DICT
;
232 typedef struct ficl_system FICL_SYSTEM
;
233 struct ficl_system_info
;
234 typedef struct ficl_system_info FICL_SYSTEM_INFO
;
237 ** the Good Stuff starts here...
239 #define FICL_VER "3.03"
240 #define FICL_VER_MAJOR 3
241 #define FICL_VER_MINOR 3
242 #if !defined (FICL_PROMPT)
243 #define FICL_PROMPT "ok> "
247 ** ANS Forth requires false to be zero, and true to be the ones
248 ** complement of false... that unifies logical and bitwise operations
251 #define FICL_TRUE (~(FICL_UNS)0)
252 #define FICL_FALSE (0)
253 #define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE)
257 ** A CELL is the main storage type. It must be large enough
258 ** to contain a pointer or a scalar. In order to accommodate
259 ** 32 bit and 64 bit processors, use abstract types for int,
260 ** unsigned, and float.
266 #if (FICL_WANT_FLOAT)
274 ** LVALUEtoCELL does a little pointer trickery to cast any CELL sized
275 ** lvalue (informal definition: an expression whose result has an
276 ** address) to CELL. Remember that constants and casts are NOT
277 ** themselves lvalues!
279 #define LVALUEtoCELL(v) (*(CELL *)&v)
282 ** PTRtoCELL is a cast through void * intended to satisfy the
283 ** most outrageously pedantic compiler... (I won't mention
286 #define PTRtoCELL (CELL *)(void *)
287 #define PTRtoSTRING (FICL_STRING *)(void *)
290 ** Strings in FICL are stored in Pascal style - with a count
291 ** preceding the text. We'll also NULL-terminate them so that
292 ** they work with the usual C lib string functions. (Belt &
293 ** suspenders? You decide.)
294 ** STRINGINFO hides the implementation with a couple of
295 ** macros for use in internal routines.
298 typedef unsigned char FICL_COUNT
;
299 #define FICL_STRING_MAX UCHAR_MAX
300 typedef struct _ficl_string
312 #define SI_COUNT(si) (si.count)
313 #define SI_PTR(si) (si.cp)
314 #define SI_SETLEN(si, len) (si.count = (FICL_UNS)(len))
315 #define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr))
317 ** Init a STRINGINFO from a pointer to NULL-terminated string
319 #define SI_PSZ(si, psz) \
320 {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);}
322 ** Init a STRINGINFO from a pointer to FICL_STRING
324 #define SI_PFS(si, pfs) \
325 {si.cp = pfs->text; si.count = pfs->count;}
328 ** Ficl uses this little structure to hold the address of
329 ** the block of text it's working on and an index to the next
330 ** unconsumed character in the string. Traditionally, this is
331 ** done by a Text Input Buffer, so I've called this struct TIB.
333 ** Since this structure also holds the size of the input buffer,
334 ** and since evaluate requires that, let's put the size here.
335 ** The size is stored as an end-pointer because that is what the
336 ** null-terminated string aware functions find most easy to deal
338 ** Notice, though, that nobody really uses this except evaluate,
339 ** so it might just be moved to FICL_VM instead. (sobral)
350 ** Stacks get heavy use in Ficl and Forth...
351 ** Each virtual machine implements two of them:
352 ** one holds parameters (data), and the other holds return
353 ** addresses and control flow information for the virtual
354 ** machine. (Note: C's automatic stack is implicitly used,
355 ** but not modeled because it doesn't need to be...)
356 ** Here's an abstract type for a stack
358 typedef struct _ficlStack
360 FICL_UNS nCells
; /* size of the stack */
361 CELL
*pFrame
; /* link reg for stack frame */
362 CELL
*sp
; /* stack pointer */
363 CELL base
[1]; /* Top of stack */
367 ** Stack methods... many map closely to required Forth words.
369 FICL_STACK
*stackCreate (unsigned nCells
);
370 void stackDelete (FICL_STACK
*pStack
);
371 int stackDepth (FICL_STACK
*pStack
);
372 void stackDrop (FICL_STACK
*pStack
, int n
);
373 CELL
stackFetch (FICL_STACK
*pStack
, int n
);
374 CELL
stackGetTop (FICL_STACK
*pStack
);
375 void stackLink (FICL_STACK
*pStack
, int nCells
);
376 void stackPick (FICL_STACK
*pStack
, int n
);
377 CELL
stackPop (FICL_STACK
*pStack
);
378 void *stackPopPtr (FICL_STACK
*pStack
);
379 FICL_UNS
stackPopUNS (FICL_STACK
*pStack
);
380 FICL_INT
stackPopINT (FICL_STACK
*pStack
);
381 void stackPush (FICL_STACK
*pStack
, CELL c
);
382 void stackPushPtr (FICL_STACK
*pStack
, void *ptr
);
383 void stackPushUNS (FICL_STACK
*pStack
, FICL_UNS u
);
384 void stackPushINT (FICL_STACK
*pStack
, FICL_INT i
);
385 void stackReset (FICL_STACK
*pStack
);
386 void stackRoll (FICL_STACK
*pStack
, int n
);
387 void stackSetTop (FICL_STACK
*pStack
, CELL c
);
388 void stackStore (FICL_STACK
*pStack
, int n
, CELL c
);
389 void stackUnlink (FICL_STACK
*pStack
);
391 #if (FICL_WANT_FLOAT)
392 float stackPopFloat (FICL_STACK
*pStack
);
393 void stackPushFloat(FICL_STACK
*pStack
, FICL_FLOAT f
);
397 ** Shortcuts (Guy Carver)
399 #define PUSHPTR(p) stackPushPtr(pVM->pStack,p)
400 #define PUSHUNS(u) stackPushUNS(pVM->pStack,u)
401 #define PUSHINT(i) stackPushINT(pVM->pStack,i)
402 #define PUSHFLOAT(f) stackPushFloat(pVM->fStack,f)
403 #define PUSH(c) stackPush(pVM->pStack,c)
404 #define POPPTR() stackPopPtr(pVM->pStack)
405 #define POPUNS() stackPopUNS(pVM->pStack)
406 #define POPINT() stackPopINT(pVM->pStack)
407 #define POPFLOAT() stackPopFloat(pVM->fStack)
408 #define POP() stackPop(pVM->pStack)
409 #define GETTOP() stackGetTop(pVM->pStack)
410 #define SETTOP(c) stackSetTop(pVM->pStack,LVALUEtoCELL(c))
411 #define GETTOPF() stackGetTop(pVM->fStack)
412 #define SETTOPF(c) stackSetTop(pVM->fStack,LVALUEtoCELL(c))
413 #define STORE(n,c) stackStore(pVM->pStack,n,LVALUEtoCELL(c))
414 #define DEPTH() stackDepth(pVM->pStack)
415 #define DROP(n) stackDrop(pVM->pStack,n)
416 #define DROPF(n) stackDrop(pVM->fStack,n)
417 #define FETCH(n) stackFetch(pVM->pStack,n)
418 #define PICK(n) stackPick(pVM->pStack,n)
419 #define PICKF(n) stackPick(pVM->fStack,n)
420 #define ROLL(n) stackRoll(pVM->pStack,n)
421 #define ROLLF(n) stackRoll(pVM->fStack,n)
424 ** The virtual machine (VM) contains the state for one interpreter.
425 ** Defined operations include:
426 ** Create & initialize
428 ** Execute a block of text
429 ** Parse a word out of the input stream
430 ** Call return, and branch
432 ** Throw an exception
435 typedef FICL_WORD
** IPTYPE
; /* the VM's instruction pointer */
438 ** Each VM has a placeholder for an output function -
439 ** this makes it possible to have each VM do I/O
440 ** through a different device. If you specify no
441 ** OUTFUNC, it defaults to ficlTextOut.
443 typedef void (*OUTFUNC
)(FICL_VM
*pVM
, char *text
, int fNewline
);
446 ** Each VM operates in one of two non-error states: interpreting
447 ** or compiling. When interpreting, words are simply executed.
448 ** When compiling, most words in the input stream have their
449 ** addresses inserted into the word under construction. Some words
450 ** (known as IMMEDIATE) are executed in the compile state, too.
452 /* values of STATE */
457 ** The pad is a small scratch area for text manipulation. ANS Forth
458 ** requires it to hold at least 84 characters.
465 ** ANS Forth requires that a word's name contain {1..31} characters.
467 #if !defined nFICLNAME
472 ** OK - now we can really define the VM...
476 FICL_SYSTEM
*pSys
; /* Which system this VM belongs to */
477 FICL_VM
*link
; /* Ficl keeps a VM list for simple teardown */
478 jmp_buf *pState
; /* crude exception mechanism... */
479 OUTFUNC textOut
; /* Output callback - see sysdep.c */
480 void * pExtend
; /* vm extension pointer for app use - initialized from FICL_SYSTEM */
481 short fRestart
; /* Set TRUE to restart runningWord */
482 IPTYPE ip
; /* instruction pointer */
483 FICL_WORD
*runningWord
;/* address of currently running word (often just *(ip-1) ) */
484 FICL_UNS state
; /* compiling or interpreting */
485 FICL_UNS base
; /* number conversion base */
486 FICL_STACK
*pStack
; /* param stack */
487 FICL_STACK
*rStack
; /* return stack */
489 FICL_STACK
*fStack
; /* float stack (optional) */
491 CELL sourceID
; /* -1 if EVALUATE, 0 if normal input */
492 TIB tib
; /* address of incoming text string */
494 CELL user
[FICL_USER_CELLS
];
496 char pad
[nPAD
]; /* the scratch area (see above) */
500 ** A FICL_CODE points to a function that gets called to help execute
501 ** a word in the dictionary. It always gets passed a pointer to the
502 ** running virtual machine, and from there it can get the address
503 ** of the parameter area of the word it's supposed to operate on.
504 ** For precompiled words, the code is all there is. For user defined
505 ** words, the code assumes that the word's parameter area is a list
506 ** of pointers to the code fields of other words to execute, and
507 ** may also contain inline data. The first parameter is always
508 ** a pointer to a code field.
510 typedef void (*FICL_CODE
)(FICL_VM
*pVm
);
513 #define VM_ASSERT(pVM) assert((*(pVM->ip - 1)) == pVM->runningWord)
515 #define VM_ASSERT(pVM)
519 ** Ficl models memory as a contiguous space divided into
520 ** words in a linked list called the dictionary.
521 ** A FICL_WORD starts each entry in the list.
522 ** Version 1.02: space for the name characters is allotted from
523 ** the dictionary ahead of the word struct, rather than using
524 ** a fixed size array for each name.
528 struct ficl_word
*link
; /* Previous word in the dictionary */
530 UNS8 flags
; /* Immediate, Smudge, Compile-only */
531 FICL_COUNT nName
; /* Number of chars in word name */
532 char *name
; /* First nFICLNAME chars of word name */
533 FICL_CODE code
; /* Native code to execute the word */
534 CELL param
[1]; /* First data cell of the word */
538 ** Worst-case size of a word header: nFICLNAME chars in name
540 #define CELLS_PER_WORD \
541 ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \
544 int wordIsImmediate(FICL_WORD
*pFW
);
545 int wordIsCompileOnly(FICL_WORD
*pFW
);
547 /* flag values for word header */
548 #define FW_IMMEDIATE 1 /* execute me even if compiling */
549 #define FW_COMPILE 2 /* error if executed when not compiling */
550 #define FW_SMUDGE 4 /* definition in progress - hide me */
551 #define FW_ISOBJECT 8 /* word is an object or object member variable */
553 #define FW_COMPIMMED (FW_IMMEDIATE | FW_COMPILE)
558 ** Exit codes for vmThrow
560 #define VM_INNEREXIT -256 /* tell ficlExecXT to exit inner loop */
561 #define VM_OUTOFTEXT -257 /* hungry - normal exit */
562 #define VM_RESTART -258 /* word needs more text to succeed - re-run it */
563 #define VM_USEREXIT -259 /* user wants to quit */
564 #define VM_ERREXIT -260 /* interp found an error */
565 #define VM_BREAK -261 /* debugger breakpoint */
566 #define VM_ABORT -1 /* like errexit -- abort */
567 #define VM_ABORTQ -2 /* like errexit -- abort" */
568 #define VM_QUIT -56 /* like errexit, but leave pStack & base alone */
571 void vmBranchRelative(FICL_VM
*pVM
, int offset
);
572 FICL_VM
* vmCreate (FICL_VM
*pVM
, unsigned nPStack
, unsigned nRStack
);
573 void vmDelete (FICL_VM
*pVM
);
574 void vmExecute (FICL_VM
*pVM
, FICL_WORD
*pWord
);
575 FICL_DICT
*vmGetDict (FICL_VM
*pVM
);
576 char * vmGetString (FICL_VM
*pVM
, FICL_STRING
*spDest
, char delimiter
);
577 STRINGINFO
vmGetWord (FICL_VM
*pVM
);
578 STRINGINFO
vmGetWord0 (FICL_VM
*pVM
);
579 int vmGetWordToPad (FICL_VM
*pVM
);
580 STRINGINFO
vmParseString (FICL_VM
*pVM
, char delimiter
);
581 STRINGINFO
vmParseStringEx(FICL_VM
*pVM
, char delimiter
, char fSkipLeading
);
582 CELL
vmPop (FICL_VM
*pVM
);
583 void vmPush (FICL_VM
*pVM
, CELL c
);
584 void vmPopIP (FICL_VM
*pVM
);
585 void vmPushIP (FICL_VM
*pVM
, IPTYPE newIP
);
586 void vmQuit (FICL_VM
*pVM
);
587 void vmReset (FICL_VM
*pVM
);
588 void vmSetTextOut (FICL_VM
*pVM
, OUTFUNC textOut
);
589 void vmTextOut (FICL_VM
*pVM
, char *text
, int fNewline
);
590 void vmTextOut (FICL_VM
*pVM
, char *text
, int fNewline
);
591 void vmThrow (FICL_VM
*pVM
, int except
);
592 void vmThrowErr (FICL_VM
*pVM
, char *fmt
, ...);
594 #define vmGetRunningWord(pVM) ((pVM)->runningWord)
598 ** The inner interpreter - coded as a macro (see note for
599 ** INLINE_INNER_LOOP in sysdep.h for complaints about VC++ 5
601 #define M_VM_STEP(pVM) \
602 FICL_WORD *tempFW = *(pVM)->ip++; \
603 (pVM)->runningWord = tempFW; \
606 #define M_INNER_LOOP(pVM) \
607 for (;;) { M_VM_STEP(pVM) }
610 #if INLINE_INNER_LOOP != 0
611 #define vmInnerLoop(pVM) M_INNER_LOOP(pVM)
613 void vmInnerLoop(FICL_VM
*pVM
);
617 ** vmCheckStack needs a vm pointer because it might have to say
618 ** something if it finds a problem. Parms popCells and pushCells
619 ** correspond to the number of parameters on the left and right of
620 ** a word's stack effect comment.
622 void vmCheckStack(FICL_VM
*pVM
, int popCells
, int pushCells
);
624 void vmCheckFStack(FICL_VM
*pVM
, int popCells
, int pushCells
);
628 ** TIB access routines...
629 ** ANS forth seems to require the input buffer to be represented
630 ** as a pointer to the start of the buffer, and an index to the
631 ** next character to read.
632 ** PushTib points the VM to a new input string and optionally
633 ** returns a copy of the current state
634 ** PopTib restores the TIB state given a saved TIB from PushTib
635 ** GetInBuf returns a pointer to the next unused char of the TIB
637 void vmPushTib (FICL_VM
*pVM
, char *text
, FICL_INT nChars
, TIB
*pSaveTib
);
638 void vmPopTib (FICL_VM
*pVM
, TIB
*pTib
);
639 #define vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index)
640 #define vmGetInBufLen(pVM) ((pVM)->tib.end - (pVM)->tib.cp)
641 #define vmGetInBufEnd(pVM) ((pVM)->tib.end)
642 #define vmGetTibIndex(pVM) (pVM)->tib.index
643 #define vmSetTibIndex(pVM, i) (pVM)->tib.index = i
644 #define vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp
647 ** Generally useful string manipulators omitted by ANSI C...
648 ** ltoa complements strtol
650 #if defined(_WIN32) && !FICL_MAIN
652 ** Why do Microsoft Meatballs insist on contaminating
653 ** my namespace with their string functions???
655 #pragma warning(disable: 4273)
658 int isPowerOfTwo(FICL_UNS u
);
660 char *ltoa( FICL_INT value
, char *string
, int radix
);
661 char *ultoa(FICL_UNS value
, char *string
, int radix
);
662 char digit_to_char(int value
);
663 char *strrev( char *string
);
664 char *skipSpace(char *cp
, char *end
);
665 char *caseFold(char *cp
);
666 int strincmp(char *cp1
, char *cp2
, FICL_UNS count
);
668 #if defined(_WIN32) && !FICL_MAIN
669 #pragma warning(default: 4273)
673 ** Ficl hash table - variable size.
675 ** If size is 1, the table degenerates into a linked list.
676 ** A WORDLIST (see the search order word set in DPANS) is
677 ** just a pointer to a FICL_HASH in this implementation.
679 #if !defined HASHSIZE /* Default size of hash table. For most uniform */
680 #define HASHSIZE 241 /* performance, use a prime number! */
683 typedef struct ficl_hash
685 struct ficl_hash
*link
; /* link to parent class wordlist for OO */
686 char *name
; /* optional pointer to \0 terminated wordlist name */
687 unsigned size
; /* number of buckets in the hash */
691 void hashForget (FICL_HASH
*pHash
, void *where
);
692 UNS16
hashHashCode (STRINGINFO si
);
693 void hashInsertWord(FICL_HASH
*pHash
, FICL_WORD
*pFW
);
694 FICL_WORD
*hashLookup (FICL_HASH
*pHash
, STRINGINFO si
, UNS16 hashCode
);
695 void hashReset (FICL_HASH
*pHash
);
698 ** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's
699 ** memory model. Description of fields:
701 ** here -- points to the next free byte in the dictionary. This
702 ** pointer is forced to be CELL-aligned before a definition is added.
703 ** Do not assume any specific alignment otherwise - Use dictAlign().
705 ** smudge -- pointer to word currently being defined (or last defined word)
706 ** If the definition completes successfully, the word will be
707 ** linked into the hash table. If unsuccessful, dictUnsmudge
708 ** uses this pointer to restore the previous state of the dictionary.
709 ** Smudge prevents unintentional recursion as a side-effect: the
710 ** dictionary search algo examines only completed definitions, so a
711 ** word cannot invoke itself by name. See the ficl word "recurse".
712 ** NOTE: smudge always points to the last word defined. IMMEDIATE
713 ** makes use of this fact. Smudge is initially NULL.
715 ** pForthWords -- pointer to the default wordlist (FICL_HASH).
716 ** This is the initial compilation list, and contains all
717 ** ficl's precompiled words.
719 ** pCompile -- compilation wordlist - initially equal to pForthWords
720 ** pSearch -- array of pointers to wordlists. Managed as a stack.
721 ** Highest index is the first list in the search order.
722 ** nLists -- number of lists in pSearch. nLists-1 is the highest
723 ** filled slot in pSearch, and points to the first wordlist
724 ** in the search order
725 ** size -- number of cells in the dictionary (total)
726 ** dict -- start of data area. Must be at the end of the struct.
732 FICL_HASH
*pForthWords
;
734 FICL_HASH
*pSearch
[FICL_DEFAULT_VOCS
];
736 unsigned size
; /* Number of cells in dict (total)*/
737 CELL
*dict
; /* Base of dictionary memory */
740 void *alignPtr(void *ptr
);
741 void dictAbortDefinition(FICL_DICT
*pDict
);
742 void dictAlign (FICL_DICT
*pDict
);
743 int dictAllot (FICL_DICT
*pDict
, int n
);
744 int dictAllotCells (FICL_DICT
*pDict
, int nCells
);
745 void dictAppendCell (FICL_DICT
*pDict
, CELL c
);
746 void dictAppendChar (FICL_DICT
*pDict
, char c
);
747 FICL_WORD
*dictAppendWord (FICL_DICT
*pDict
,
751 FICL_WORD
*dictAppendWord2(FICL_DICT
*pDict
,
755 void dictAppendUNS (FICL_DICT
*pDict
, FICL_UNS u
);
756 int dictCellsAvail (FICL_DICT
*pDict
);
757 int dictCellsUsed (FICL_DICT
*pDict
);
758 void dictCheck (FICL_DICT
*pDict
, FICL_VM
*pVM
, int n
);
759 void dictCheckThreshold(FICL_DICT
* dp
);
760 FICL_DICT
*dictCreate(unsigned nCELLS
);
761 FICL_DICT
*dictCreateHashed(unsigned nCells
, unsigned nHash
);
762 FICL_HASH
*dictCreateWordlist(FICL_DICT
*dp
, int nBuckets
);
763 void dictDelete (FICL_DICT
*pDict
);
764 void dictEmpty (FICL_DICT
*pDict
, unsigned nHash
);
766 void dictHashSummary(FICL_VM
*pVM
);
768 int dictIncludes (FICL_DICT
*pDict
, void *p
);
769 FICL_WORD
*dictLookup (FICL_DICT
*pDict
, STRINGINFO si
);
771 FICL_WORD
*ficlLookupLoc (FICL_SYSTEM
*pSys
, STRINGINFO si
);
773 void dictResetSearchOrder(FICL_DICT
*pDict
);
774 void dictSetFlags (FICL_DICT
*pDict
, UNS8 set
, UNS8 clr
);
775 void dictSetImmediate(FICL_DICT
*pDict
);
776 void dictUnsmudge (FICL_DICT
*pDict
);
777 CELL
*dictWhere (FICL_DICT
*pDict
);
783 ** See words.c: interpWord
784 ** By default, ficl goes through two attempts to parse each token from its input
785 ** stream: it first attempts to match it with a word in the dictionary, and
786 ** if that fails, it attempts to convert it into a number. This mechanism is now
787 ** extensible by additional steps. This allows extensions like floating point and
788 ** double number support to be factored cleanly.
790 ** Each parse step is a function that receives the next input token as a STRINGINFO.
791 ** If the parse step matches the token, it must apply semantics to the token appropriate
792 ** to the present value of VM.state (compiling or interpreting), and return FICL_TRUE.
793 ** Otherwise it returns FICL_FALSE. See words.c: isNumber for an example
795 ** Note: for the sake of efficiency, it's a good idea both to limit the number
796 ** of parse steps and to code each parse step so that it rejects tokens that
797 ** do not match as quickly as possible.
800 typedef int (*FICL_PARSE_STEP
)(FICL_VM
*pVM
, STRINGINFO si
);
803 ** Appends a parse step function to the end of the parse list (see
804 ** FICL_PARSE_STEP notes in ficl.h for details). Returns 0 if successful,
805 ** nonzero if there's no more room in the list. Each parse step is a word in
806 ** the dictionary. Precompiled parse steps can use (PARSE-STEP) as their
807 ** CFA - see parenParseStep in words.c.
809 int ficlAddParseStep(FICL_SYSTEM
*pSys
, FICL_WORD
*pFW
); /* ficl.c */
810 void ficlAddPrecompiledParseStep(FICL_SYSTEM
*pSys
, char *name
, FICL_PARSE_STEP pStep
);
811 void ficlListParseSteps(FICL_VM
*pVM
);
814 ** FICL_BREAKPOINT record.
815 ** origXT - if NULL, this breakpoint is unused. Otherwise it stores the xt
816 ** that the breakpoint overwrote. This is restored to the dictionary when the
817 ** BP executes or gets cleared
818 ** address - the location of the breakpoint (address of the instruction that
819 ** has been replaced with the breakpoint trap
820 ** origXT - The original contents of the location with the breakpoint
821 ** Note: address is NULL when this breakpoint is empty
823 typedef struct FICL_BREAKPOINT
831 ** F I C L _ S Y S T E M
832 ** The top level data structure of the system - ficl_system ties a list of
833 ** virtual machines with their corresponding dictionaries. Ficl 3.0 will
834 ** support multiple Ficl systems, allowing multiple concurrent sessions
835 ** to separate dictionaries with some constraints.
836 ** The present model allows multiple sessions to one dictionary provided
837 ** you implement ficlLockDictionary() as specified in sysdep.h
838 ** Note: the pExtend pointer is there to provide context for applications. It is copied
839 ** to each VM's pExtend field as that VM is created.
844 void *pExtend
; /* Initializes VM's pExtend pointer (for application use) */
848 #ifdef FICL_WANT_LOCALS
851 FICL_WORD
*pInterp
[3];
852 FICL_WORD
*parseList
[FICL_MAX_PARSE_STEPS
];
855 FICL_WORD
*pBranchParen
;
857 FICL_WORD
*pDoesParen
;
858 FICL_WORD
*pExitInner
;
859 FICL_WORD
*pExitParen
;
861 FICL_WORD
*pInterpret
;
862 FICL_WORD
*pLitParen
;
863 FICL_WORD
*pTwoLitParen
;
864 FICL_WORD
*pLoopParen
;
865 FICL_WORD
*pPLoopParen
;
866 FICL_WORD
*pQDoParen
;
867 FICL_WORD
*pSemiParen
;
871 FICL_WORD
*pCStringLit
;
872 FICL_WORD
*pStringLit
;
875 FICL_WORD
*pGetLocalParen
;
876 FICL_WORD
*pGet2LocalParen
;
877 FICL_WORD
*pGetLocal0
;
878 FICL_WORD
*pGetLocal1
;
879 FICL_WORD
*pToLocalParen
;
880 FICL_WORD
*pTo2LocalParen
;
881 FICL_WORD
*pToLocal0
;
882 FICL_WORD
*pToLocal1
;
883 FICL_WORD
*pLinkParen
;
884 FICL_WORD
*pUnLinkParen
;
889 FICL_BREAKPOINT bpStep
;
892 struct ficl_system_info
894 int size
; /* structure size tag for versioning */
895 int nDictCells
; /* Size of system's Dictionary */
896 OUTFUNC textOut
; /* default textOut function */
897 void *pExtend
; /* Initializes VM's pExtend pointer - for application use */
898 int nEnvCells
; /* Size of Environment dictionary */
902 #define ficlInitInfo(x) { memset((x), 0, sizeof(FICL_SYSTEM_INFO)); \
903 (x)->size = sizeof(FICL_SYSTEM_INFO); }
906 ** External interface to FICL...
909 ** f i c l I n i t S y s t e m
910 ** Binds a global dictionary to the interpreter system and initializes
911 ** the dict to contain the ANSI CORE wordset.
912 ** You can specify the address and size of the allocated area.
913 ** Using ficlInitSystemEx you can also specify the text output function.
914 ** After that, ficl manages it.
915 ** First step is to set up the static pointers to the area.
916 ** Then write the "precompiled" portion of the dictionary in.
917 ** The dictionary needs to be at least large enough to hold the
918 ** precompiled part. Try 1K cells minimum. Use "words" to find
919 ** out how much of the dictionary is used at any time.
921 FICL_SYSTEM
*ficlInitSystemEx(FICL_SYSTEM_INFO
*fsi
);
923 /* Deprecated call */
924 FICL_SYSTEM
*ficlInitSystem(int nDictCells
);
927 ** f i c l T e r m S y s t e m
928 ** Deletes the system dictionary and all virtual machines that
929 ** were created with ficlNewVM (see below). Call this function to
930 ** reclaim all memory used by the dictionary and VMs.
932 void ficlTermSystem(FICL_SYSTEM
*pSys
);
935 ** f i c l E v a l u a t e
936 ** Evaluates a block of input text in the context of the
937 ** specified interpreter. Also sets SOURCE-ID properly.
939 ** PLEASE USE THIS FUNCTION when throwing a hard-coded
940 ** string to the FICL interpreter.
942 int ficlEvaluate(FICL_VM
*pVM
, char *pText
);
946 ** Evaluates a block of input text in the context of the
947 ** specified interpreter. Emits any requested output to the
948 ** interpreter's output function. If the input string is NULL
949 ** terminated, you can pass -1 as nChars rather than count it.
950 ** Execution returns when the text block has been executed,
951 ** or an error occurs.
952 ** Returns one of the VM_XXXX codes defined in ficl.h:
953 ** VM_OUTOFTEXT is the normal exit condition
954 ** VM_ERREXIT means that the interp encountered a syntax error
955 ** and the vm has been reset to recover (some or all
956 ** of the text block got ignored
957 ** VM_USEREXIT means that the user executed the "bye" command
958 ** to shut down the interpreter. This would be a good
959 ** time to delete the vm, etc -- or you can ignore this
961 ** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"'
963 ** Preconditions: successful execution of ficlInitSystem,
964 ** Successful creation and init of the VM by ficlNewVM (or equiv)
966 ** If you call ficlExec() or one of its brothers, you MUST
967 ** ensure pVM->sourceID was set to a sensible value.
968 ** ficlExec() explicitly DOES NOT manage SOURCE-ID for you.
970 int ficlExec (FICL_VM
*pVM
, char *pText
);
971 int ficlExecC(FICL_VM
*pVM
, char *pText
, FICL_INT nChars
);
972 int ficlExecXT(FICL_VM
*pVM
, FICL_WORD
*pWord
);
975 ** ficlExecFD(FICL_VM *pVM, int fd);
976 * Evaluates text from file passed in via fd.
977 * Execution returns when all of file has been executed or an
980 int ficlExecFD(FICL_VM
*pVM
, int fd
);
983 ** Create a new VM from the heap, and link it into the system VM list.
984 ** Initializes the VM and binds default sized stacks to it. Returns the
985 ** address of the VM, or NULL if an error occurs.
986 ** Precondition: successful execution of ficlInitSystem
988 FICL_VM
*ficlNewVM(FICL_SYSTEM
*pSys
);
991 ** Force deletion of a VM. You do not need to do this
992 ** unless you're creating and discarding a lot of VMs.
993 ** For systems that use a constant pool of VMs for the life
994 ** of the system, ficltermSystem takes care of VM cleanup
997 void ficlFreeVM(FICL_VM
*pVM
);
1001 ** Set the stack sizes (return and parameter) to be used for all
1002 ** subsequently created VMs. Returns actual stack size to be used.
1004 int ficlSetStackSize(int nStackCells
);
1007 ** Returns the address of the most recently defined word in the system
1008 ** dictionary with the given name, or NULL if no match.
1009 ** Precondition: successful execution of ficlInitSystem
1011 FICL_WORD
*ficlLookup(FICL_SYSTEM
*pSys
, char *name
);
1014 ** f i c l G e t D i c t
1015 ** Utility function - returns the address of the system dictionary.
1016 ** Precondition: successful execution of ficlInitSystem
1018 FICL_DICT
*ficlGetDict(FICL_SYSTEM
*pSys
);
1019 FICL_DICT
*ficlGetEnv (FICL_SYSTEM
*pSys
);
1020 void ficlSetEnv (FICL_SYSTEM
*pSys
, char *name
, FICL_UNS value
);
1021 void ficlSetEnvD(FICL_SYSTEM
*pSys
, char *name
, FICL_UNS hi
, FICL_UNS lo
);
1022 #if FICL_WANT_LOCALS
1023 FICL_DICT
*ficlGetLoc (FICL_SYSTEM
*pSys
);
1026 ** f i c l B u i l d
1027 ** Builds a word into the system default dictionary in a thread-safe way.
1028 ** Preconditions: system must be initialized, and there must
1029 ** be enough space for the new word's header! Operation is
1030 ** controlled by ficlLockDictionary, so any initialization
1031 ** required by your version of the function (if you "overrode"
1032 ** it) must be complete at this point.
1034 ** name -- the name of the word to be built
1035 ** code -- code to execute when the word is invoked - must take a single param
1036 ** pointer to a FICL_VM
1037 ** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR!
1038 ** Most words can use FW_DEFAULT.
1039 ** nAllot - number of extra cells to allocate in the parameter area (usually zero)
1041 int ficlBuild(FICL_SYSTEM
*pSys
, char *name
, FICL_CODE code
, char flags
);
1044 ** f i c l C o m p i l e C o r e
1045 ** Builds the ANS CORE wordset into the dictionary - called by
1046 ** ficlInitSystem - no need to waste dict space by doing it again.
1048 void ficlCompileCore(FICL_SYSTEM
*pSys
);
1049 void ficlCompilePrefix(FICL_SYSTEM
*pSys
);
1050 void ficlCompileSearch(FICL_SYSTEM
*pSys
);
1051 void ficlCompileSoftCore(FICL_SYSTEM
*pSys
);
1052 void ficlCompileTools(FICL_SYSTEM
*pSys
);
1053 void ficlCompileFile(FICL_SYSTEM
*pSys
);
1055 void ficlCompileFloat(FICL_SYSTEM
*pSys
);
1056 int ficlParseFloatNumber( FICL_VM
*pVM
, STRINGINFO si
); /* float.c */
1058 #if FICL_PLATFORM_EXTEND
1059 void ficlCompilePlatform(FICL_SYSTEM
*pSys
);
1061 int ficlParsePrefix(FICL_VM
*pVM
, STRINGINFO si
);
1066 void constantParen(FICL_VM
*pVM
);
1067 void twoConstParen(FICL_VM
*pVM
);
1068 int ficlParseNumber(FICL_VM
*pVM
, STRINGINFO si
);
1069 void ficlTick(FICL_VM
*pVM
);
1070 void parseStepParen(FICL_VM
*pVM
);
1075 int isAFiclWord(FICL_DICT
*pd
, FICL_WORD
*pFW
);
1078 ** The following supports SEE and the debugger.
1103 WORDKIND
ficlWordClassify(FICL_WORD
*pFW
);
1106 ** Dictionary on-demand resizing
1108 extern CELL dictThreshold
;
1109 extern CELL dictIncrease
;
1112 ** Various FreeBSD goodies
1115 #if defined(__i386__) && !defined(TESTMAIN)
1116 extern void ficlOutb(FICL_VM
*pVM
);
1117 extern void ficlInb(FICL_VM
*pVM
);
1120 extern void ficlSetenv(FICL_VM
*pVM
);
1121 extern void ficlSetenvq(FICL_VM
*pVM
);
1122 extern void ficlGetenv(FICL_VM
*pVM
);
1123 extern void ficlUnsetenv(FICL_VM
*pVM
);
1124 extern void ficlCopyin(FICL_VM
*pVM
);
1125 extern void ficlCopyout(FICL_VM
*pVM
);
1126 extern void ficlFindfile(FICL_VM
*pVM
);
1127 extern void ficlCcall(FICL_VM
*pVM
);
1128 #if !defined(TESTMAIN)
1129 extern void ficlPnpdevices(FICL_VM
*pVM
);
1130 extern void ficlPnphandlers(FICL_VM
*pVM
);
1134 ** Used with File-Access wordset.
1136 #define FICL_FAM_READ 1
1137 #define FICL_FAM_WRITE 2
1138 #define FICL_FAM_APPEND 4
1139 #define FICL_FAM_BINARY 8
1141 #define FICL_FAM_OPEN_MODE(fam) ((fam) & (FICL_FAM_READ | FICL_FAM_WRITE | FICL_FAM_APPEND))
1144 #if (FICL_WANT_FILE)
1145 typedef struct ficlFILE
1152 #include <sys/linker_set.h>
1154 typedef void ficlCompileFcn(FICL_SYSTEM
*);
1155 #define FICL_COMPILE_SET(func) \
1156 DATA_SET(X4th_compile_set, func)
1157 SET_DECLARE(X4th_compile_set
, ficlCompileFcn
);
1159 #ifdef LOADER_VERIEXEC
1160 #include <verify_file.h>
1167 #endif /* __FICL_H__ */