1 /*
2 * d i c t . c
3 * Forth Inspired Command Language - dictionary methods
4 * Author: John Sadler (john_sadler@alum.mit.edu)
5 * Created: 19 July 1997
6 * $Id: dictionary.c,v 1.2 2010/09/12 15:14:52 asau Exp $
7 */
8 /*
9 * This file implements the dictionary -- Ficl's model of
10 * memory management. All Ficl words are stored in the
11 * dictionary. A word is a named chunk of data with its
12 * associated code. Ficl treats all words the same, even
13 * precompiled ones, so your words become first-class
14 * extensions of the language. You can even define new
15 * control structures.
16 *
17 * 29 jun 1998 (sadler) added variable sized hash table support
18 */
19 /*
20 * Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
21 * All rights reserved.
22 *
23 * Get the latest Ficl release at http://ficl.sourceforge.net
24 *
25 * I am interested in hearing from anyone who uses Ficl. If you have
26 * a problem, a success story, a defect, an enhancement request, or
27 * if you would like to contribute to the Ficl release, please
28 * contact me by email at the address above.
29 *
30 * L I C E N S E and D I S C L A I M E R
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 */
53
54 #include "ficl.h"
55
56 #define FICL_SAFE_CALLBACK_FROM_SYSTEM(system) \
57 (((system) != NULL) ? &((system)->callback) : NULL)
58 #define FICL_SAFE_SYSTEM_FROM_DICTIONARY(dictionary) \
59 (((dictionary) != NULL) ? (dictionary)->system : NULL)
60 #define FICL_DICTIONARY_ASSERT(dictionary, expression) \
61 FICL_SYSTEM_ASSERT(FICL_SAFE_SYSTEM_FROM_DICTIONARY(dictionary), \
62 expression)
63
64 /*
65 * d i c t A b o r t D e f i n i t i o n
66 * Abort a definition in process: reclaim its memory and unlink it
67 * from the dictionary list. Assumes that there is a smudged
68 * definition in process...otherwise does nothing.
69 * NOTE: this function is not smart enough to unlink a word that
70 * has been successfully defined (ie linked into a hash). It
71 * only works for defs in process. If the def has been unsmudged,
72 * nothing happens.
73 */
74 void
ficlDictionaryAbortDefinition(ficlDictionary * dictionary)75 ficlDictionaryAbortDefinition(ficlDictionary *dictionary)
76 {
77 ficlWord *word;
78 ficlDictionaryLock(dictionary, FICL_TRUE);
79 word = dictionary->smudge;
80
81 if (word->flags & FICL_WORD_SMUDGED)
82 dictionary->here = (ficlCell *)word->name;
83
84 ficlDictionaryLock(dictionary, FICL_FALSE);
85 }
86
87 /*
88 * d i c t A l i g n
89 * Align the dictionary's free space pointer
90 */
91 void
ficlDictionaryAlign(ficlDictionary * dictionary)92 ficlDictionaryAlign(ficlDictionary *dictionary)
93 {
94 dictionary->here = ficlAlignPointer(dictionary->here);
95 }
96
97 /*
98 * d i c t A l l o t
99 * Allocate or remove n chars of dictionary space, with
100 * checks for underrun and overrun
101 */
102 void
ficlDictionaryAllot(ficlDictionary * dictionary,int n)103 ficlDictionaryAllot(ficlDictionary *dictionary, int n)
104 {
105 char *here = (char *)dictionary->here;
106 here += n;
107 dictionary->here = FICL_POINTER_TO_CELL(here);
108 }
109
110 /*
111 * d i c t A l l o t C e l l s
112 * Reserve space for the requested number of ficlCells in the
113 * dictionary. If nficlCells < 0 , removes space from the dictionary.
114 */
115 void
ficlDictionaryAllotCells(ficlDictionary * dictionary,int nficlCells)116 ficlDictionaryAllotCells(ficlDictionary *dictionary, int nficlCells)
117 {
118 dictionary->here += nficlCells;
119 }
120
121 /*
122 * d i c t A p p e n d C e l l
123 * Append the specified ficlCell to the dictionary
124 */
125 void
ficlDictionaryAppendCell(ficlDictionary * dictionary,ficlCell c)126 ficlDictionaryAppendCell(ficlDictionary *dictionary, ficlCell c)
127 {
128 *dictionary->here++ = c;
129 }
130
131 /*
132 * d i c t A p p e n d C h a r
133 * Append the specified char to the dictionary
134 */
135 void
ficlDictionaryAppendCharacter(ficlDictionary * dictionary,char c)136 ficlDictionaryAppendCharacter(ficlDictionary *dictionary, char c)
137 {
138 char *here = (char *)dictionary->here;
139 *here++ = c;
140 dictionary->here = FICL_POINTER_TO_CELL(here);
141 }
142
143 /*
144 * d i c t A p p e n d U N S
145 * Append the specified ficlUnsigned to the dictionary
146 */
147 void
ficlDictionaryAppendUnsigned(ficlDictionary * dictionary,ficlUnsigned u)148 ficlDictionaryAppendUnsigned(ficlDictionary *dictionary, ficlUnsigned u)
149 {
150 ficlCell c;
151
152 c.u = u;
153 ficlDictionaryAppendCell(dictionary, c);
154 }
155
156 void *
ficlDictionaryAppendData(ficlDictionary * dictionary,void * data,ficlInteger length)157 ficlDictionaryAppendData(ficlDictionary *dictionary, void *data,
158 ficlInteger length)
159 {
160 char *here = (char *)dictionary->here;
161 char *oldHere = here;
162 char *from = (char *)data;
163
164 if (length == 0) {
165 ficlDictionaryAlign(dictionary);
166 return ((char *)dictionary->here);
167 }
168
169 while (length) {
170 *here++ = *from++;
171 length--;
172 }
173
174 *here++ = '\0';
175
176 dictionary->here = FICL_POINTER_TO_CELL(here);
177 ficlDictionaryAlign(dictionary);
178 return (oldHere);
179 }
180
181 /*
182 * d i c t C o p y N a m e
183 * Copy up to FICL_NAME_LENGTH characters of the name specified by s into
184 * the dictionary starting at "here", then NULL-terminate the name,
185 * point "here" to the next available byte, and return the address of
186 * the beginning of the name. Used by dictAppendWord.
187 * N O T E S :
188 * 1. "here" is guaranteed to be aligned after this operation.
189 * 2. If the string has zero length, align and return "here"
190 */
191 char *
ficlDictionaryAppendString(ficlDictionary * dictionary,ficlString s)192 ficlDictionaryAppendString(ficlDictionary *dictionary, ficlString s)
193 {
194 void *data = FICL_STRING_GET_POINTER(s);
195 ficlInteger length = FICL_STRING_GET_LENGTH(s);
196
197 if (length > FICL_NAME_LENGTH)
198 length = FICL_NAME_LENGTH;
199
200 return (ficlDictionaryAppendData(dictionary, data, length));
201 }
202
203 ficlWord *
ficlDictionaryAppendConstantInstruction(ficlDictionary * dictionary,ficlString name,ficlInstruction instruction,ficlInteger value)204 ficlDictionaryAppendConstantInstruction(ficlDictionary *dictionary,
205 ficlString name, ficlInstruction instruction, ficlInteger value)
206 {
207 ficlWord *word = ficlDictionaryAppendWord(dictionary, name,
208 (ficlPrimitive)instruction, FICL_WORD_DEFAULT);
209
210 if (word != NULL)
211 ficlDictionaryAppendUnsigned(dictionary, value);
212 return (word);
213 }
214
215 ficlWord *
ficlDictionaryAppend2ConstantInstruction(ficlDictionary * dictionary,ficlString name,ficlInstruction instruction,ficl2Integer value)216 ficlDictionaryAppend2ConstantInstruction(ficlDictionary *dictionary,
217 ficlString name, ficlInstruction instruction, ficl2Integer value)
218 {
219 ficlWord *word = ficlDictionaryAppendWord(dictionary, name,
220 (ficlPrimitive)instruction, FICL_WORD_DEFAULT);
221
222 if (word != NULL) {
223 ficlDictionaryAppendUnsigned(dictionary,
224 FICL_2UNSIGNED_GET_HIGH(value));
225 ficlDictionaryAppendUnsigned(dictionary,
226 FICL_2UNSIGNED_GET_LOW(value));
227 }
228 return (word);
229 }
230
231 ficlWord *
ficlDictionaryAppendConstant(ficlDictionary * dictionary,char * name,ficlInteger value)232 ficlDictionaryAppendConstant(ficlDictionary *dictionary, char *name,
233 ficlInteger value)
234 {
235 ficlString s;
236 FICL_STRING_SET_FROM_CSTRING(s, name);
237 return (ficlDictionaryAppendConstantInstruction(dictionary, s,
238 ficlInstructionConstantParen, value));
239 }
240
241 ficlWord *
ficlDictionaryAppend2Constant(ficlDictionary * dictionary,char * name,ficl2Integer value)242 ficlDictionaryAppend2Constant(ficlDictionary *dictionary, char *name,
243 ficl2Integer value)
244 {
245 ficlString s;
246 FICL_STRING_SET_FROM_CSTRING(s, name);
247 return (ficlDictionaryAppend2ConstantInstruction(dictionary, s,
248 ficlInstruction2ConstantParen, value));
249 }
250
251 ficlWord *
ficlDictionarySetConstantInstruction(ficlDictionary * dictionary,ficlString name,ficlInstruction instruction,ficlInteger value)252 ficlDictionarySetConstantInstruction(ficlDictionary *dictionary,
253 ficlString name, ficlInstruction instruction, ficlInteger value)
254 {
255 ficlWord *word = ficlDictionaryLookup(dictionary, name);
256 ficlCell c;
257
258 if (word == NULL) {
259 word = ficlDictionaryAppendConstantInstruction(dictionary,
260 name, instruction, value);
261 } else {
262 word->code = (ficlPrimitive)instruction;
263 c.i = value;
264 word->param[0] = c;
265 }
266 return (word);
267 }
268
269 ficlWord *
ficlDictionarySetConstant(ficlDictionary * dictionary,char * name,ficlInteger value)270 ficlDictionarySetConstant(ficlDictionary *dictionary, char *name,
271 ficlInteger value)
272 {
273 ficlString s;
274 FICL_STRING_SET_FROM_CSTRING(s, name);
275 return (ficlDictionarySetConstantInstruction(dictionary, s,
276 ficlInstructionConstantParen, value));
277 }
278
279 ficlWord *
ficlDictionarySet2ConstantInstruction(ficlDictionary * dictionary,ficlString s,ficlInstruction instruction,ficl2Integer value)280 ficlDictionarySet2ConstantInstruction(ficlDictionary *dictionary, ficlString s,
281 ficlInstruction instruction, ficl2Integer value)
282 {
283 ficlWord *word;
284 word = ficlDictionaryLookup(dictionary, s);
285
286 /*
287 * only reuse the existing word if we're sure it has space for a
288 * 2constant
289 */
290 #if FICL_WANT_FLOAT
291 if ((word != NULL) &&
292 ((((ficlInstruction)word->code) == ficlInstruction2ConstantParen) ||
293 (((ficlInstruction)word->code) == ficlInstructionF2ConstantParen)))
294 #else
295 if ((word != NULL) &&
296 ((((ficlInstruction)word->code) == ficlInstruction2ConstantParen)))
297 #endif /* FICL_WANT_FLOAT */
298 {
299 word->code = (ficlPrimitive)instruction;
300 word->param[0].u = FICL_2UNSIGNED_GET_HIGH(value);
301 word->param[1].u = FICL_2UNSIGNED_GET_LOW(value);
302 } else {
303 word = ficlDictionaryAppend2ConstantInstruction(dictionary, s,
304 instruction, value);
305 }
306
307 return (word);
308 }
309
310 ficlWord *
ficlDictionarySet2Constant(ficlDictionary * dictionary,char * name,ficl2Integer value)311 ficlDictionarySet2Constant(ficlDictionary *dictionary, char *name,
312 ficl2Integer value)
313 {
314 ficlString s;
315 FICL_STRING_SET_FROM_CSTRING(s, name);
316
317 return (ficlDictionarySet2ConstantInstruction(dictionary, s,
318 ficlInstruction2ConstantParen, value));
319 }
320
321 ficlWord *
ficlDictionarySetConstantString(ficlDictionary * dictionary,char * name,char * value)322 ficlDictionarySetConstantString(ficlDictionary *dictionary, char *name,
323 char *value)
324 {
325 ficlString s;
326 ficl2Integer valueAs2Integer;
327 FICL_2INTEGER_SET(strlen(value), (intptr_t)value, valueAs2Integer);
328 FICL_STRING_SET_FROM_CSTRING(s, name);
329
330 return (ficlDictionarySet2ConstantInstruction(dictionary, s,
331 ficlInstruction2ConstantParen, valueAs2Integer));
332 }
333
334 /*
335 * d i c t A p p e n d W o r d
336 * Create a new word in the dictionary with the specified
337 * ficlString, code, and flags. Does not require a NULL-terminated
338 * name.
339 */
340 ficlWord *
ficlDictionaryAppendWord(ficlDictionary * dictionary,ficlString name,ficlPrimitive code,ficlUnsigned8 flags)341 ficlDictionaryAppendWord(ficlDictionary *dictionary, ficlString name,
342 ficlPrimitive code, ficlUnsigned8 flags)
343 {
344 ficlUnsigned8 length = (ficlUnsigned8)FICL_STRING_GET_LENGTH(name);
345 char *nameCopy;
346 ficlWord *word;
347
348 ficlDictionaryLock(dictionary, FICL_TRUE);
349
350 /*
351 * NOTE: ficlDictionaryAppendString advances "here" as a side-effect.
352 * It must execute before word is initialized.
353 */
354 nameCopy = ficlDictionaryAppendString(dictionary, name);
355 word = (ficlWord *)dictionary->here;
356 dictionary->smudge = word;
357 word->hash = ficlHashCode(name);
358 word->code = code;
359 word->semiParen = ficlInstructionSemiParen;
360 word->flags = (ficlUnsigned8)(flags | FICL_WORD_SMUDGED);
361 word->length = length;
362 word->name = nameCopy;
363
364 /*
365 * Point "here" to first ficlCell of new word's param area...
366 */
367 dictionary->here = word->param;
368
369 if (!(flags & FICL_WORD_SMUDGED))
370 ficlDictionaryUnsmudge(dictionary);
371
372 ficlDictionaryLock(dictionary, FICL_FALSE);
373 return (word);
374 }
375
376 /*
377 * d i c t A p p e n d W o r d
378 * Create a new word in the dictionary with the specified
379 * name, code, and flags. Name must be NULL-terminated.
380 */
381 ficlWord *
ficlDictionaryAppendPrimitive(ficlDictionary * dictionary,char * name,ficlPrimitive code,ficlUnsigned8 flags)382 ficlDictionaryAppendPrimitive(ficlDictionary *dictionary, char *name,
383 ficlPrimitive code, ficlUnsigned8 flags)
384 {
385 ficlString s;
386 FICL_STRING_SET_FROM_CSTRING(s, name);
387
388 return (ficlDictionaryAppendWord(dictionary, s, code, flags));
389 }
390
391 ficlWord *
ficlDictionarySetPrimitive(ficlDictionary * dictionary,char * name,ficlPrimitive code,ficlUnsigned8 flags)392 ficlDictionarySetPrimitive(ficlDictionary *dictionary, char *name,
393 ficlPrimitive code, ficlUnsigned8 flags)
394 {
395 ficlString s;
396 ficlWord *word;
397
398 FICL_STRING_SET_FROM_CSTRING(s, name);
399 word = ficlDictionaryLookup(dictionary, s);
400
401 if (word == NULL) {
402 word = ficlDictionaryAppendPrimitive(dictionary, name,
403 code, flags);
404 } else {
405 word->code = (ficlPrimitive)code;
406 word->flags = flags;
407 }
408 return (word);
409 }
410
411 ficlWord *
ficlDictionaryAppendInstruction(ficlDictionary * dictionary,char * name,ficlInstruction i,ficlUnsigned8 flags)412 ficlDictionaryAppendInstruction(ficlDictionary *dictionary, char *name,
413 ficlInstruction i, ficlUnsigned8 flags)
414 {
415 return (ficlDictionaryAppendPrimitive(dictionary, name,
416 (ficlPrimitive)i, (ficlUnsigned8)(FICL_WORD_INSTRUCTION | flags)));
417 }
418
419 ficlWord *
ficlDictionarySetInstruction(ficlDictionary * dictionary,char * name,ficlInstruction i,ficlUnsigned8 flags)420 ficlDictionarySetInstruction(ficlDictionary *dictionary, char *name,
421 ficlInstruction i, ficlUnsigned8 flags)
422 {
423 return (ficlDictionarySetPrimitive(dictionary, name,
424 (ficlPrimitive)i, (ficlUnsigned8)(FICL_WORD_INSTRUCTION | flags)));
425 }
426
427 /*
428 * d i c t C e l l s A v a i l
429 * Returns the number of empty ficlCells left in the dictionary
430 */
431 int
ficlDictionaryCellsAvailable(ficlDictionary * dictionary)432 ficlDictionaryCellsAvailable(ficlDictionary *dictionary)
433 {
434 return (dictionary->size - ficlDictionaryCellsUsed(dictionary));
435 }
436
437 /*
438 * d i c t C e l l s U s e d
439 * Returns the number of ficlCells consumed in the dicionary
440 */
441 int
ficlDictionaryCellsUsed(ficlDictionary * dictionary)442 ficlDictionaryCellsUsed(ficlDictionary *dictionary)
443 {
444 return (dictionary->here - dictionary->base);
445 }
446
447 /*
448 * d i c t C r e a t e
449 * Create and initialize a dictionary with the specified number
450 * of ficlCells capacity, and no hashing (hash size == 1).
451 */
452 ficlDictionary *
ficlDictionaryCreate(ficlSystem * system,unsigned size)453 ficlDictionaryCreate(ficlSystem *system, unsigned size)
454 {
455 return (ficlDictionaryCreateHashed(system, size, 1));
456 }
457
458 ficlDictionary *
ficlDictionaryCreateHashed(ficlSystem * system,unsigned size,unsigned bucketCount)459 ficlDictionaryCreateHashed(ficlSystem *system, unsigned size,
460 unsigned bucketCount)
461 {
462 ficlDictionary *dictionary;
463 size_t nAlloc;
464
465 nAlloc = sizeof (ficlDictionary) + (size * sizeof (ficlCell))
466 + sizeof (ficlHash) + (bucketCount - 1) * sizeof (ficlWord *);
467
468 dictionary = ficlMalloc(nAlloc);
469 FICL_SYSTEM_ASSERT(system, dictionary != NULL);
470
471 dictionary->size = size;
472 dictionary->system = system;
473
474 ficlDictionaryEmpty(dictionary, bucketCount);
475 return (dictionary);
476 }
477
478 /*
479 * d i c t C r e a t e W o r d l i s t
480 * Create and initialize an anonymous wordlist
481 */
482 ficlHash *
ficlDictionaryCreateWordlist(ficlDictionary * dictionary,int bucketCount)483 ficlDictionaryCreateWordlist(ficlDictionary *dictionary, int bucketCount)
484 {
485 ficlHash *hash;
486
487 ficlDictionaryAlign(dictionary);
488 hash = (ficlHash *)dictionary->here;
489 ficlDictionaryAllot(dictionary,
490 sizeof (ficlHash) + (bucketCount - 1) * sizeof (ficlWord *));
491
492 hash->size = bucketCount;
493 ficlHashReset(hash);
494 return (hash);
495 }
496
497 /*
498 * d i c t D e l e t e
499 * Free all memory allocated for the given dictionary
500 */
501 void
ficlDictionaryDestroy(ficlDictionary * dictionary)502 ficlDictionaryDestroy(ficlDictionary *dictionary)
503 {
504 FICL_DICTIONARY_ASSERT(dictionary, dictionary != NULL);
505 ficlFree(dictionary);
506 }
507
508 /*
509 * d i c t E m p t y
510 * Empty the dictionary, reset its hash table, and reset its search order.
511 * Clears and (re-)creates the hash table with the size specified by nHash.
512 */
513 void
ficlDictionaryEmpty(ficlDictionary * dictionary,unsigned bucketCount)514 ficlDictionaryEmpty(ficlDictionary *dictionary, unsigned bucketCount)
515 {
516 ficlHash *hash;
517
518 dictionary->here = dictionary->base;
519
520 ficlDictionaryAlign(dictionary);
521 hash = (ficlHash *)dictionary->here;
522 ficlDictionaryAllot(dictionary,
523 sizeof (ficlHash) + (bucketCount - 1) * sizeof (ficlWord *));
524
525 hash->size = bucketCount;
526 ficlHashReset(hash);
527
528 dictionary->forthWordlist = hash;
529 dictionary->smudge = NULL;
530 ficlDictionaryResetSearchOrder(dictionary);
531 }
532
533 /*
534 * i s A F i c l W o r d
535 * Vet a candidate pointer carefully to make sure
536 * it's not some chunk o' inline data...
537 * It has to have a name, and it has to look
538 * like it's in the dictionary address range.
539 * NOTE: this excludes :noname words!
540 */
541 int
ficlDictionaryIsAWord(ficlDictionary * dictionary,ficlWord * word)542 ficlDictionaryIsAWord(ficlDictionary *dictionary, ficlWord *word)
543 {
544 if ((((ficlInstruction)word) > ficlInstructionInvalid) &&
545 (((ficlInstruction)word) < ficlInstructionLast))
546 return (1);
547
548 if (!ficlDictionaryIncludes(dictionary, word))
549 return (0);
550
551 if (!ficlDictionaryIncludes(dictionary, word->name))
552 return (0);
553
554 if ((word->link != NULL) &&
555 !ficlDictionaryIncludes(dictionary, word->link))
556 return (0);
557
558 if ((word->length <= 0) || (word->name[word->length] != '\0'))
559 return (0);
560
561 if (strlen(word->name) != word->length)
562 return (0);
563
564 return (1);
565 }
566
567 /*
568 * f i n d E n c l o s i n g W o r d
569 * Given a pointer to something, check to make sure it's an address in the
570 * dictionary. If so, search backwards until we find something that looks
571 * like a dictionary header. If successful, return the address of the
572 * ficlWord found. Otherwise return NULL. nSEARCH_CELLS sets the maximum
573 * neighborhood this func will search before giving up
574 */
575 #define nSEARCH_CELLS 100
576
577 ficlWord *
ficlDictionaryFindEnclosingWord(ficlDictionary * dictionary,ficlCell * cell)578 ficlDictionaryFindEnclosingWord(ficlDictionary *dictionary, ficlCell *cell)
579 {
580 ficlWord *word;
581 int i;
582
583 if (!ficlDictionaryIncludes(dictionary, (void *)cell))
584 return (NULL);
585
586 for (i = nSEARCH_CELLS; i > 0; --i, --cell) {
587 word = (ficlWord *)
588 (cell + 1 - (sizeof (ficlWord) / sizeof (ficlCell)));
589 if (ficlDictionaryIsAWord(dictionary, word))
590 return (word);
591 }
592
593 return (NULL);
594 }
595
596 /*
597 * d i c t I n c l u d e s
598 * Returns FICL_TRUE iff the given pointer is within the address range of
599 * the dictionary.
600 */
601 int
ficlDictionaryIncludes(ficlDictionary * dictionary,void * p)602 ficlDictionaryIncludes(ficlDictionary *dictionary, void *p)
603 {
604 return ((p >= (void *) &dictionary->base) &&
605 (p < (void *)(&dictionary->base + dictionary->size)));
606 }
607
608 /*
609 * d i c t L o o k u p
610 * Find the ficlWord that matches the given name and length.
611 * If found, returns the word's address. Otherwise returns NULL.
612 * Uses the search order list to search multiple wordlists.
613 */
614 ficlWord *
ficlDictionaryLookup(ficlDictionary * dictionary,ficlString name)615 ficlDictionaryLookup(ficlDictionary *dictionary, ficlString name)
616 {
617 ficlWord *word = NULL;
618 ficlHash *hash;
619 int i;
620 ficlUnsigned16 hashCode = ficlHashCode(name);
621
622 FICL_DICTIONARY_ASSERT(dictionary, dictionary != NULL);
623
624 ficlDictionaryLock(dictionary, FICL_TRUE);
625
626 for (i = (int)dictionary->wordlistCount - 1; (i >= 0) && (!word); --i) {
627 hash = dictionary->wordlists[i];
628 word = ficlHashLookup(hash, name, hashCode);
629 }
630
631 ficlDictionaryLock(dictionary, FICL_FALSE);
632 return (word);
633 }
634
635 /*
636 * s e e
637 * TOOLS ( "<spaces>name" -- )
638 * Display a human-readable representation of the named word's definition.
639 * The source of the representation (object-code decompilation, source
640 * block, etc.) and the particular form of the display is implementation
641 * defined.
642 */
643 /*
644 * ficlSeeColon (for proctologists only)
645 * Walks a colon definition, decompiling
646 * on the fly. Knows about primitive control structures.
647 */
648 char *ficlDictionaryInstructionNames[] =
649 {
650 #define FICL_TOKEN(token, description) description,
651 #define FICL_INSTRUCTION_TOKEN(token, description, flags) description,
652 #include "ficltokens.h"
653 #undef FICL_TOKEN
654 #undef FICL_INSTRUCTION_TOKEN
655 };
656
657 void
ficlDictionarySee(ficlDictionary * dictionary,ficlWord * word,ficlCallback * callback)658 ficlDictionarySee(ficlDictionary *dictionary, ficlWord *word,
659 ficlCallback *callback)
660 {
661 char *trace;
662 ficlCell *cell = word->param;
663 ficlCell *param0 = cell;
664 char buffer[128];
665
666 for (; cell->i != ficlInstructionSemiParen; cell++) {
667 ficlWord *word = (ficlWord *)(cell->p);
668
669 trace = buffer;
670 if ((void *)cell == (void *)buffer)
671 *trace++ = '>';
672 else
673 *trace++ = ' ';
674 trace += sprintf(trace, "%3ld ", (long)(cell - param0));
675
676 if (ficlDictionaryIsAWord(dictionary, word)) {
677 ficlWordKind kind = ficlWordClassify(word);
678 ficlCell c, c2;
679
680 switch (kind) {
681 case FICL_WORDKIND_INSTRUCTION:
682 (void) sprintf(trace, "%s (instruction %ld)",
683 ficlDictionaryInstructionNames[(long)word],
684 (long)word);
685 break;
686 case FICL_WORDKIND_INSTRUCTION_WITH_ARGUMENT:
687 c = *++cell;
688 (void) sprintf(trace, "%s (instruction %ld), "
689 "with argument %ld (%#lx)",
690 ficlDictionaryInstructionNames[(long)word],
691 (long)word, (long)c.i, (unsigned long)c.u);
692 break;
693 case FICL_WORDKIND_INSTRUCTION_WORD:
694 (void) sprintf(trace,
695 "%s :: executes %s (instruction word %ld)",
696 word->name,
697 ficlDictionaryInstructionNames[
698 (long)word->code], (long)word->code);
699 break;
700 case FICL_WORDKIND_LITERAL:
701 c = *++cell;
702 if (ficlDictionaryIsAWord(dictionary, c.p) &&
703 (c.i >= ficlInstructionLast)) {
704 ficlWord *word = (ficlWord *)c.p;
705 (void) sprintf(trace,
706 "%.*s ( %#lx literal )",
707 word->length, word->name,
708 (unsigned long)c.u);
709 } else
710 (void) sprintf(trace,
711 "literal %ld (%#lx)", (long)c.i,
712 (unsigned long)c.u);
713 break;
714 case FICL_WORDKIND_2LITERAL:
715 c = *++cell;
716 c2 = *++cell;
717 (void) sprintf(trace,
718 "2literal %ld %ld (%#lx %#lx)",
719 (long)c2.i, (long)c.i, (unsigned long)c2.u,
720 (unsigned long)c.u);
721 break;
722 #if FICL_WANT_FLOAT
723 case FICL_WORDKIND_FLITERAL:
724 c = *++cell;
725 (void) sprintf(trace, "fliteral %f (%#lx)",
726 (double)c.f, (unsigned long)c.u);
727 break;
728 #endif /* FICL_WANT_FLOAT */
729 case FICL_WORDKIND_STRING_LITERAL: {
730 ficlCountedString *counted;
731 counted = (ficlCountedString *)(void *)++cell;
732 cell = (ficlCell *)
733 ficlAlignPointer(counted->text +
734 counted->length + 1) - 1;
735 (void) sprintf(trace, "s\" %.*s\"",
736 counted->length, counted->text);
737 }
738 break;
739 case FICL_WORDKIND_CSTRING_LITERAL: {
740 ficlCountedString *counted;
741 counted = (ficlCountedString *)(void *)++cell;
742 cell = (ficlCell *)
743 ficlAlignPointer(counted->text +
744 counted->length + 1) - 1;
745 (void) sprintf(trace, "c\" %.*s\"",
746 counted->length, counted->text);
747 }
748 break;
749 case FICL_WORDKIND_BRANCH0:
750 c = *++cell;
751 (void) sprintf(trace, "branch0 %ld",
752 (long)(cell + c.i - param0));
753 break;
754 case FICL_WORDKIND_BRANCH:
755 c = *++cell;
756 (void) sprintf(trace, "branch %ld",
757 (long)(cell + c.i - param0));
758 break;
759
760 case FICL_WORDKIND_QDO:
761 c = *++cell;
762 (void) sprintf(trace, "?do (leave %ld)",
763 (long)((ficlCell *)c.p - param0));
764 break;
765 case FICL_WORDKIND_DO:
766 c = *++cell;
767 (void) sprintf(trace, "do (leave %ld)",
768 (long)((ficlCell *)c.p - param0));
769 break;
770 case FICL_WORDKIND_LOOP:
771 c = *++cell;
772 (void) sprintf(trace, "loop (branch %ld)",
773 (long)(cell + c.i - param0));
774 break;
775 case FICL_WORDKIND_OF:
776 c = *++cell;
777 (void) sprintf(trace, "of (branch %ld)",
778 (long)(cell + c.i - param0));
779 break;
780 case FICL_WORDKIND_PLOOP:
781 c = *++cell;
782 (void) sprintf(trace, "+loop (branch %ld)",
783 (long)(cell + c.i - param0));
784 break;
785 default:
786 (void) sprintf(trace, "%.*s", word->length,
787 word->name);
788 break;
789 }
790 } else {
791 /* probably not a word - punt and print value */
792 (void) sprintf(trace, "%ld ( %#lx )", (long)cell->i,
793 (unsigned long)cell->u);
794 }
795
796 ficlCallbackTextOut(callback, buffer);
797 ficlCallbackTextOut(callback, "\n");
798 }
799
800 ficlCallbackTextOut(callback, ";\n");
801 }
802
803 /*
804 * d i c t R e s e t S e a r c h O r d e r
805 * Initialize the dictionary search order list to sane state
806 */
807 void
ficlDictionaryResetSearchOrder(ficlDictionary * dictionary)808 ficlDictionaryResetSearchOrder(ficlDictionary *dictionary)
809 {
810 FICL_DICTIONARY_ASSERT(dictionary, dictionary);
811 dictionary->compilationWordlist = dictionary->forthWordlist;
812 dictionary->wordlistCount = 1;
813 dictionary->wordlists[0] = dictionary->forthWordlist;
814 }
815
816 /*
817 * d i c t S e t F l a g s
818 * Changes the flags field of the most recently defined word:
819 * Set all bits that are ones in the set parameter.
820 */
821 void
ficlDictionarySetFlags(ficlDictionary * dictionary,ficlUnsigned8 set)822 ficlDictionarySetFlags(ficlDictionary *dictionary, ficlUnsigned8 set)
823 {
824 FICL_DICTIONARY_ASSERT(dictionary, dictionary->smudge);
825 dictionary->smudge->flags |= set;
826 }
827
828
829 /*
830 * d i c t C l e a r F l a g s
831 * Changes the flags field of the most recently defined word:
832 * Clear all bits that are ones in the clear parameter.
833 */
834 void
ficlDictionaryClearFlags(ficlDictionary * dictionary,ficlUnsigned8 clear)835 ficlDictionaryClearFlags(ficlDictionary *dictionary, ficlUnsigned8 clear)
836 {
837 FICL_DICTIONARY_ASSERT(dictionary, dictionary->smudge);
838 dictionary->smudge->flags &= ~clear;
839 }
840
841 /*
842 * d i c t S e t I m m e d i a t e
843 * Set the most recently defined word as IMMEDIATE
844 */
845 void
ficlDictionarySetImmediate(ficlDictionary * dictionary)846 ficlDictionarySetImmediate(ficlDictionary *dictionary)
847 {
848 FICL_DICTIONARY_ASSERT(dictionary, dictionary->smudge);
849 dictionary->smudge->flags |= FICL_WORD_IMMEDIATE;
850 }
851
852 /*
853 * d i c t U n s m u d g e
854 * Completes the definition of a word by linking it
855 * into the main list
856 */
857 void
ficlDictionaryUnsmudge(ficlDictionary * dictionary)858 ficlDictionaryUnsmudge(ficlDictionary *dictionary)
859 {
860 ficlWord *word = dictionary->smudge;
861 ficlHash *hash = dictionary->compilationWordlist;
862
863 FICL_DICTIONARY_ASSERT(dictionary, hash);
864 FICL_DICTIONARY_ASSERT(dictionary, word);
865
866 /*
867 * :noname words never get linked into the list...
868 */
869 if (word->length > 0)
870 ficlHashInsertWord(hash, word);
871 word->flags &= ~(FICL_WORD_SMUDGED);
872 }
873
874 /*
875 * d i c t W h e r e
876 * Returns the value of the HERE pointer -- the address
877 * of the next free ficlCell in the dictionary
878 */
879 ficlCell *
ficlDictionaryWhere(ficlDictionary * dictionary)880 ficlDictionaryWhere(ficlDictionary *dictionary)
881 {
882 return (dictionary->here);
883 }
884