Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/ficl/dict.c
34677 views
1
/*******************************************************************
2
** d i c t . c
3
** Forth Inspired Command Language - dictionary methods
4
** Author: John Sadler ([email protected])
5
** Created: 19 July 1997
6
** $Id: dict.c,v 1.14 2001/12/05 07:21:34 jsadler 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 ([email protected])
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
55
#ifdef TESTMAIN
56
#include <stdio.h>
57
#include <ctype.h>
58
#else
59
#include <stand.h>
60
#endif
61
#include <string.h>
62
#include "ficl.h"
63
64
/* Dictionary on-demand resizing control variables */
65
CELL dictThreshold;
66
CELL dictIncrease;
67
68
69
static char *dictCopyName(FICL_DICT *pDict, STRINGINFO si);
70
71
/**************************************************************************
72
d i c t A b o r t D e f i n i t i o n
73
** Abort a definition in process: reclaim its memory and unlink it
74
** from the dictionary list. Assumes that there is a smudged
75
** definition in process...otherwise does nothing.
76
** NOTE: this function is not smart enough to unlink a word that
77
** has been successfully defined (ie linked into a hash). It
78
** only works for defs in process. If the def has been unsmudged,
79
** nothing happens.
80
**************************************************************************/
81
void dictAbortDefinition(FICL_DICT *pDict)
82
{
83
FICL_WORD *pFW;
84
ficlLockDictionary(TRUE);
85
pFW = pDict->smudge;
86
87
if (pFW->flags & FW_SMUDGE)
88
pDict->here = (CELL *)pFW->name;
89
90
ficlLockDictionary(FALSE);
91
return;
92
}
93
94
95
/**************************************************************************
96
a l i g n P t r
97
** Aligns the given pointer to FICL_ALIGN address units.
98
** Returns the aligned pointer value.
99
**************************************************************************/
100
void *alignPtr(void *ptr)
101
{
102
#if FICL_ALIGN > 0
103
char *cp;
104
CELL c;
105
cp = (char *)ptr + FICL_ALIGN_ADD;
106
c.p = (void *)cp;
107
c.u = c.u & (~FICL_ALIGN_ADD);
108
ptr = (CELL *)c.p;
109
#endif
110
return ptr;
111
}
112
113
114
/**************************************************************************
115
d i c t A l i g n
116
** Align the dictionary's free space pointer
117
**************************************************************************/
118
void dictAlign(FICL_DICT *pDict)
119
{
120
pDict->here = alignPtr(pDict->here);
121
}
122
123
124
/**************************************************************************
125
d i c t A l l o t
126
** Allocate or remove n chars of dictionary space, with
127
** checks for underrun and overrun
128
**************************************************************************/
129
int dictAllot(FICL_DICT *pDict, int n)
130
{
131
char *cp = (char *)pDict->here;
132
#if FICL_ROBUST
133
if (n > 0)
134
{
135
if ((unsigned)n <= dictCellsAvail(pDict) * sizeof (CELL))
136
cp += n;
137
else
138
return 1; /* dict is full */
139
}
140
else
141
{
142
n = -n;
143
if ((unsigned)n <= dictCellsUsed(pDict) * sizeof (CELL))
144
cp -= n;
145
else /* prevent underflow */
146
cp -= dictCellsUsed(pDict) * sizeof (CELL);
147
}
148
#else
149
cp += n;
150
#endif
151
pDict->here = PTRtoCELL cp;
152
return 0;
153
}
154
155
156
/**************************************************************************
157
d i c t A l l o t C e l l s
158
** Reserve space for the requested number of cells in the
159
** dictionary. If nCells < 0 , removes space from the dictionary.
160
**************************************************************************/
161
int dictAllotCells(FICL_DICT *pDict, int nCells)
162
{
163
#if FICL_ROBUST
164
if (nCells > 0)
165
{
166
if (nCells <= dictCellsAvail(pDict))
167
pDict->here += nCells;
168
else
169
return 1; /* dict is full */
170
}
171
else
172
{
173
nCells = -nCells;
174
if (nCells <= dictCellsUsed(pDict))
175
pDict->here -= nCells;
176
else /* prevent underflow */
177
pDict->here -= dictCellsUsed(pDict);
178
}
179
#else
180
pDict->here += nCells;
181
#endif
182
return 0;
183
}
184
185
186
/**************************************************************************
187
d i c t A p p e n d C e l l
188
** Append the specified cell to the dictionary
189
**************************************************************************/
190
void dictAppendCell(FICL_DICT *pDict, CELL c)
191
{
192
*pDict->here++ = c;
193
return;
194
}
195
196
197
/**************************************************************************
198
d i c t A p p e n d C h a r
199
** Append the specified char to the dictionary
200
**************************************************************************/
201
void dictAppendChar(FICL_DICT *pDict, char c)
202
{
203
char *cp = (char *)pDict->here;
204
*cp++ = c;
205
pDict->here = PTRtoCELL cp;
206
return;
207
}
208
209
210
/**************************************************************************
211
d i c t A p p e n d W o r d
212
** Create a new word in the dictionary with the specified
213
** name, code, and flags. Name must be NULL-terminated.
214
**************************************************************************/
215
FICL_WORD *dictAppendWord(FICL_DICT *pDict,
216
char *name,
217
FICL_CODE pCode,
218
UNS8 flags)
219
{
220
STRINGINFO si;
221
SI_SETLEN(si, strlen(name));
222
SI_SETPTR(si, name);
223
return dictAppendWord2(pDict, si, pCode, flags);
224
}
225
226
227
/**************************************************************************
228
d i c t A p p e n d W o r d 2
229
** Create a new word in the dictionary with the specified
230
** STRINGINFO, code, and flags. Does not require a NULL-terminated
231
** name.
232
**************************************************************************/
233
FICL_WORD *dictAppendWord2(FICL_DICT *pDict,
234
STRINGINFO si,
235
FICL_CODE pCode,
236
UNS8 flags)
237
{
238
FICL_COUNT len = (FICL_COUNT)SI_COUNT(si);
239
char *pName;
240
FICL_WORD *pFW;
241
242
ficlLockDictionary(TRUE);
243
244
/*
245
** NOTE: dictCopyName advances "here" as a side-effect.
246
** It must execute before pFW is initialized.
247
*/
248
pName = dictCopyName(pDict, si);
249
pFW = (FICL_WORD *)pDict->here;
250
pDict->smudge = pFW;
251
pFW->hash = hashHashCode(si);
252
pFW->code = pCode;
253
pFW->flags = (UNS8)(flags | FW_SMUDGE);
254
pFW->nName = (char)len;
255
pFW->name = pName;
256
/*
257
** Point "here" to first cell of new word's param area...
258
*/
259
pDict->here = pFW->param;
260
261
if (!(flags & FW_SMUDGE))
262
dictUnsmudge(pDict);
263
264
ficlLockDictionary(FALSE);
265
return pFW;
266
}
267
268
269
/**************************************************************************
270
d i c t A p p e n d U N S
271
** Append the specified FICL_UNS to the dictionary
272
**************************************************************************/
273
void dictAppendUNS(FICL_DICT *pDict, FICL_UNS u)
274
{
275
*pDict->here++ = LVALUEtoCELL(u);
276
return;
277
}
278
279
280
/**************************************************************************
281
d i c t C e l l s A v a i l
282
** Returns the number of empty cells left in the dictionary
283
**************************************************************************/
284
int dictCellsAvail(FICL_DICT *pDict)
285
{
286
return pDict->size - dictCellsUsed(pDict);
287
}
288
289
290
/**************************************************************************
291
d i c t C e l l s U s e d
292
** Returns the number of cells consumed in the dicionary
293
**************************************************************************/
294
int dictCellsUsed(FICL_DICT *pDict)
295
{
296
return pDict->here - pDict->dict;
297
}
298
299
300
/**************************************************************************
301
d i c t C h e c k
302
** Checks the dictionary for corruption and throws appropriate
303
** errors.
304
** Input: +n number of ADDRESS UNITS (not Cells) proposed to allot
305
** -n number of ADDRESS UNITS proposed to de-allot
306
** 0 just do a consistency check
307
**************************************************************************/
308
void dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int n)
309
{
310
if ((n >= 0) && (dictCellsAvail(pDict) * (int)sizeof(CELL) < n))
311
{
312
vmThrowErr(pVM, "Error: dictionary full");
313
}
314
315
if ((n <= 0) && (dictCellsUsed(pDict) * (int)sizeof(CELL) < -n))
316
{
317
vmThrowErr(pVM, "Error: dictionary underflow");
318
}
319
320
if (pDict->nLists > FICL_DEFAULT_VOCS)
321
{
322
dictResetSearchOrder(pDict);
323
vmThrowErr(pVM, "Error: search order overflow");
324
}
325
else if (pDict->nLists < 0)
326
{
327
dictResetSearchOrder(pDict);
328
vmThrowErr(pVM, "Error: search order underflow");
329
}
330
331
return;
332
}
333
334
335
/**************************************************************************
336
d i c t C o p y N a m e
337
** Copy up to nFICLNAME characters of the name specified by si into
338
** the dictionary starting at "here", then NULL-terminate the name,
339
** point "here" to the next available byte, and return the address of
340
** the beginning of the name. Used by dictAppendWord.
341
** N O T E S :
342
** 1. "here" is guaranteed to be aligned after this operation.
343
** 2. If the string has zero length, align and return "here"
344
**************************************************************************/
345
static char *dictCopyName(FICL_DICT *pDict, STRINGINFO si)
346
{
347
char *oldCP = (char *)pDict->here;
348
char *cp = oldCP;
349
char *name = SI_PTR(si);
350
int i = SI_COUNT(si);
351
352
if (i == 0)
353
{
354
dictAlign(pDict);
355
return (char *)pDict->here;
356
}
357
358
if (i > nFICLNAME)
359
i = nFICLNAME;
360
361
for (; i > 0; --i)
362
{
363
*cp++ = *name++;
364
}
365
366
*cp++ = '\0';
367
368
pDict->here = PTRtoCELL cp;
369
dictAlign(pDict);
370
return oldCP;
371
}
372
373
374
/**************************************************************************
375
d i c t C r e a t e
376
** Create and initialize a dictionary with the specified number
377
** of cells capacity, and no hashing (hash size == 1).
378
**************************************************************************/
379
FICL_DICT *dictCreate(unsigned nCells)
380
{
381
return dictCreateHashed(nCells, 1);
382
}
383
384
385
FICL_DICT *dictCreateHashed(unsigned nCells, unsigned nHash)
386
{
387
FICL_DICT *pDict;
388
size_t nAlloc;
389
390
nAlloc = sizeof (FICL_HASH) + nCells * sizeof (CELL)
391
+ (nHash - 1) * sizeof (FICL_WORD *);
392
393
pDict = ficlMalloc(sizeof (FICL_DICT));
394
assert(pDict);
395
memset(pDict, 0, sizeof (FICL_DICT));
396
pDict->dict = ficlMalloc(nAlloc);
397
assert(pDict->dict);
398
399
pDict->size = nCells;
400
dictEmpty(pDict, nHash);
401
return pDict;
402
}
403
404
405
/**************************************************************************
406
d i c t C r e a t e W o r d l i s t
407
** Create and initialize an anonymous wordlist
408
**************************************************************************/
409
FICL_HASH *dictCreateWordlist(FICL_DICT *dp, int nBuckets)
410
{
411
FICL_HASH *pHash;
412
413
dictAlign(dp);
414
pHash = (FICL_HASH *)dp->here;
415
dictAllot(dp, sizeof (FICL_HASH)
416
+ (nBuckets-1) * sizeof (FICL_WORD *));
417
418
pHash->size = nBuckets;
419
hashReset(pHash);
420
return pHash;
421
}
422
423
424
/**************************************************************************
425
d i c t D e l e t e
426
** Free all memory allocated for the given dictionary
427
**************************************************************************/
428
void dictDelete(FICL_DICT *pDict)
429
{
430
assert(pDict);
431
ficlFree(pDict);
432
return;
433
}
434
435
436
/**************************************************************************
437
d i c t E m p t y
438
** Empty the dictionary, reset its hash table, and reset its search order.
439
** Clears and (re-)creates the hash table with the size specified by nHash.
440
**************************************************************************/
441
void dictEmpty(FICL_DICT *pDict, unsigned nHash)
442
{
443
FICL_HASH *pHash;
444
445
pDict->here = pDict->dict;
446
447
dictAlign(pDict);
448
pHash = (FICL_HASH *)pDict->here;
449
dictAllot(pDict,
450
sizeof (FICL_HASH) + (nHash - 1) * sizeof (FICL_WORD *));
451
452
pHash->size = nHash;
453
hashReset(pHash);
454
455
pDict->pForthWords = pHash;
456
pDict->smudge = NULL;
457
dictResetSearchOrder(pDict);
458
return;
459
}
460
461
462
/**************************************************************************
463
d i c t H a s h S u m m a r y
464
** Calculate a figure of merit for the dictionary hash table based
465
** on the average search depth for all the words in the dictionary,
466
** assuming uniform distribution of target keys. The figure of merit
467
** is the ratio of the total search depth for all keys in the table
468
** versus a theoretical optimum that would be achieved if the keys
469
** were distributed into the table as evenly as possible.
470
** The figure would be worse if the hash table used an open
471
** addressing scheme (i.e. collisions resolved by searching the
472
** table for an empty slot) for a given size table.
473
**************************************************************************/
474
#if FICL_WANT_FLOAT
475
void dictHashSummary(FICL_VM *pVM)
476
{
477
FICL_DICT *dp = vmGetDict(pVM);
478
FICL_HASH *pFHash;
479
FICL_WORD **pHash;
480
unsigned size;
481
FICL_WORD *pFW;
482
unsigned i;
483
int nMax = 0;
484
int nWords = 0;
485
int nFilled;
486
double avg = 0.0;
487
double best;
488
int nAvg, nRem, nDepth;
489
490
dictCheck(dp, pVM, 0);
491
492
pFHash = dp->pSearch[dp->nLists - 1];
493
pHash = pFHash->table;
494
size = pFHash->size;
495
nFilled = size;
496
497
for (i = 0; i < size; i++)
498
{
499
int n = 0;
500
pFW = pHash[i];
501
502
while (pFW)
503
{
504
++n;
505
++nWords;
506
pFW = pFW->link;
507
}
508
509
avg += (double)(n * (n+1)) / 2.0;
510
511
if (n > nMax)
512
nMax = n;
513
if (n == 0)
514
--nFilled;
515
}
516
517
/* Calc actual avg search depth for this hash */
518
avg = avg / nWords;
519
520
/* Calc best possible performance with this size hash */
521
nAvg = nWords / size;
522
nRem = nWords % size;
523
nDepth = size * (nAvg * (nAvg+1))/2 + (nAvg+1)*nRem;
524
best = (double)nDepth/nWords;
525
526
sprintf(pVM->pad,
527
"%d bins, %2.0f%% filled, Depth: Max=%d, Avg=%2.1f, Best=%2.1f, Score: %2.0f%%",
528
size,
529
(double)nFilled * 100.0 / size, nMax,
530
avg,
531
best,
532
100.0 * best / avg);
533
534
ficlTextOut(pVM, pVM->pad, 1);
535
536
return;
537
}
538
#endif
539
540
/**************************************************************************
541
d i c t I n c l u d e s
542
** Returns TRUE iff the given pointer is within the address range of
543
** the dictionary.
544
**************************************************************************/
545
int dictIncludes(FICL_DICT *pDict, void *p)
546
{
547
return ((p >= (void *) &pDict->dict)
548
&& (p < (void *)(&pDict->dict + pDict->size))
549
);
550
}
551
552
/**************************************************************************
553
d i c t L o o k u p
554
** Find the FICL_WORD that matches the given name and length.
555
** If found, returns the word's address. Otherwise returns NULL.
556
** Uses the search order list to search multiple wordlists.
557
**************************************************************************/
558
FICL_WORD *dictLookup(FICL_DICT *pDict, STRINGINFO si)
559
{
560
FICL_WORD *pFW = NULL;
561
FICL_HASH *pHash;
562
int i;
563
UNS16 hashCode = hashHashCode(si);
564
565
assert(pDict);
566
567
ficlLockDictionary(1);
568
569
for (i = (int)pDict->nLists - 1; (i >= 0) && (!pFW); --i)
570
{
571
pHash = pDict->pSearch[i];
572
pFW = hashLookup(pHash, si, hashCode);
573
}
574
575
ficlLockDictionary(0);
576
return pFW;
577
}
578
579
580
/**************************************************************************
581
f i c l L o o k u p L o c
582
** Same as dictLookup, but looks in system locals dictionary first...
583
** Assumes locals dictionary has only one wordlist...
584
**************************************************************************/
585
#if FICL_WANT_LOCALS
586
FICL_WORD *ficlLookupLoc(FICL_SYSTEM *pSys, STRINGINFO si)
587
{
588
FICL_WORD *pFW = NULL;
589
FICL_DICT *pDict = pSys->dp;
590
FICL_HASH *pHash = ficlGetLoc(pSys)->pForthWords;
591
int i;
592
UNS16 hashCode = hashHashCode(si);
593
594
assert(pHash);
595
assert(pDict);
596
597
ficlLockDictionary(1);
598
/*
599
** check the locals dict first...
600
*/
601
pFW = hashLookup(pHash, si, hashCode);
602
603
/*
604
** If no joy, (!pFW) --------------------------v
605
** iterate over the search list in the main dict
606
*/
607
for (i = (int)pDict->nLists - 1; (i >= 0) && (!pFW); --i)
608
{
609
pHash = pDict->pSearch[i];
610
pFW = hashLookup(pHash, si, hashCode);
611
}
612
613
ficlLockDictionary(0);
614
return pFW;
615
}
616
#endif
617
618
619
/**************************************************************************
620
d i c t R e s e t S e a r c h O r d e r
621
** Initialize the dictionary search order list to sane state
622
**************************************************************************/
623
void dictResetSearchOrder(FICL_DICT *pDict)
624
{
625
assert(pDict);
626
pDict->pCompile = pDict->pForthWords;
627
pDict->nLists = 1;
628
pDict->pSearch[0] = pDict->pForthWords;
629
return;
630
}
631
632
633
/**************************************************************************
634
d i c t S e t F l a g s
635
** Changes the flags field of the most recently defined word:
636
** Set all bits that are ones in the set parameter, clear all bits
637
** that are ones in the clr parameter. Clear wins in case the same bit
638
** is set in both parameters.
639
**************************************************************************/
640
void dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr)
641
{
642
assert(pDict->smudge);
643
pDict->smudge->flags |= set;
644
pDict->smudge->flags &= ~clr;
645
return;
646
}
647
648
649
/**************************************************************************
650
d i c t S e t I m m e d i a t e
651
** Set the most recently defined word as IMMEDIATE
652
**************************************************************************/
653
void dictSetImmediate(FICL_DICT *pDict)
654
{
655
assert(pDict->smudge);
656
pDict->smudge->flags |= FW_IMMEDIATE;
657
return;
658
}
659
660
661
/**************************************************************************
662
d i c t U n s m u d g e
663
** Completes the definition of a word by linking it
664
** into the main list
665
**************************************************************************/
666
void dictUnsmudge(FICL_DICT *pDict)
667
{
668
FICL_WORD *pFW = pDict->smudge;
669
FICL_HASH *pHash = pDict->pCompile;
670
671
assert(pHash);
672
assert(pFW);
673
/*
674
** :noname words never get linked into the list...
675
*/
676
if (pFW->nName > 0)
677
hashInsertWord(pHash, pFW);
678
pFW->flags &= ~(FW_SMUDGE);
679
return;
680
}
681
682
683
/**************************************************************************
684
d i c t W h e r e
685
** Returns the value of the HERE pointer -- the address
686
** of the next free cell in the dictionary
687
**************************************************************************/
688
CELL *dictWhere(FICL_DICT *pDict)
689
{
690
return pDict->here;
691
}
692
693
694
/**************************************************************************
695
h a s h F o r g e t
696
** Unlink all words in the hash that have addresses greater than or
697
** equal to the address supplied. Implementation factor for FORGET
698
** and MARKER.
699
**************************************************************************/
700
void hashForget(FICL_HASH *pHash, void *where)
701
{
702
FICL_WORD *pWord;
703
unsigned i;
704
705
assert(pHash);
706
assert(where);
707
708
for (i = 0; i < pHash->size; i++)
709
{
710
pWord = pHash->table[i];
711
712
while ((void *)pWord >= where)
713
{
714
pWord = pWord->link;
715
}
716
717
pHash->table[i] = pWord;
718
}
719
720
return;
721
}
722
723
724
/**************************************************************************
725
h a s h H a s h C o d e
726
**
727
** Generate a 16 bit hashcode from a character string using a rolling
728
** shift and add stolen from PJ Weinberger of Bell Labs fame. Case folds
729
** the name before hashing it...
730
** N O T E : If string has zero length, returns zero.
731
**************************************************************************/
732
UNS16 hashHashCode(STRINGINFO si)
733
{
734
/* hashPJW */
735
UNS8 *cp;
736
UNS16 code = (UNS16)si.count;
737
UNS16 shift = 0;
738
739
if (si.count == 0)
740
return 0;
741
742
/* changed to run without errors under Purify -- lch */
743
for (cp = (UNS8 *)si.cp; si.count && *cp; cp++, si.count--)
744
{
745
code = (UNS16)((code << 4) + tolower(*cp));
746
shift = (UNS16)(code & 0xf000);
747
if (shift)
748
{
749
code ^= (UNS16)(shift >> 8);
750
code ^= (UNS16)shift;
751
}
752
}
753
754
return (UNS16)code;
755
}
756
757
758
759
760
/**************************************************************************
761
h a s h I n s e r t W o r d
762
** Put a word into the hash table using the word's hashcode as
763
** an index (modulo the table size).
764
**************************************************************************/
765
void hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW)
766
{
767
FICL_WORD **pList;
768
769
assert(pHash);
770
assert(pFW);
771
772
if (pHash->size == 1)
773
{
774
pList = pHash->table;
775
}
776
else
777
{
778
pList = pHash->table + (pFW->hash % pHash->size);
779
}
780
781
pFW->link = *pList;
782
*pList = pFW;
783
return;
784
}
785
786
787
/**************************************************************************
788
h a s h L o o k u p
789
** Find a name in the hash table given the hashcode and text of the name.
790
** Returns the address of the corresponding FICL_WORD if found,
791
** otherwise NULL.
792
** Note: outer loop on link field supports inheritance in wordlists.
793
** It's not part of ANS Forth - ficl only. hashReset creates wordlists
794
** with NULL link fields.
795
**************************************************************************/
796
FICL_WORD *hashLookup(FICL_HASH *pHash, STRINGINFO si, UNS16 hashCode)
797
{
798
FICL_UNS nCmp = si.count;
799
FICL_WORD *pFW;
800
UNS16 hashIdx;
801
802
if (nCmp > nFICLNAME)
803
nCmp = nFICLNAME;
804
805
for (; pHash != NULL; pHash = pHash->link)
806
{
807
if (pHash->size > 1)
808
hashIdx = (UNS16)(hashCode % pHash->size);
809
else /* avoid the modulo op for single threaded lists */
810
hashIdx = 0;
811
812
for (pFW = pHash->table[hashIdx]; pFW; pFW = pFW->link)
813
{
814
if ( (pFW->nName == si.count)
815
&& (!strincmp(si.cp, pFW->name, nCmp)) )
816
return pFW;
817
#if FICL_ROBUST
818
assert(pFW != pFW->link);
819
#endif
820
}
821
}
822
823
return NULL;
824
}
825
826
827
/**************************************************************************
828
h a s h R e s e t
829
** Initialize a FICL_HASH to empty state.
830
**************************************************************************/
831
void hashReset(FICL_HASH *pHash)
832
{
833
unsigned i;
834
835
assert(pHash);
836
837
for (i = 0; i < pHash->size; i++)
838
{
839
pHash->table[i] = NULL;
840
}
841
842
pHash->link = NULL;
843
pHash->name = NULL;
844
return;
845
}
846
847
/**************************************************************************
848
d i c t C h e c k T h r e s h o l d
849
** Verify if an increase in the dictionary size is warranted, and do it if
850
** so.
851
**************************************************************************/
852
853
void dictCheckThreshold(FICL_DICT* dp)
854
{
855
if( dictCellsAvail(dp) < dictThreshold.u ) {
856
dp->dict = ficlMalloc( dictIncrease.u * sizeof (CELL) );
857
assert(dp->dict);
858
dp->here = dp->dict;
859
dp->size = dictIncrease.u;
860
dictAlign(dp);
861
}
862
}
863
864
865