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