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