| | 1 | #ifdef RCSID |
| | 2 | static char RCSid[] = |
| | 3 | "$Header: d:/cvsroot/tads/TADS2/TOKTH.C,v 1.2 1999/05/17 02:52:13 MJRoberts Exp $"; |
| | 4 | #endif |
| | 5 | |
| | 6 | /* |
| | 7 | * Copyright (c) 1992, 2002 Michael J. Roberts. All Rights Reserved. |
| | 8 | * |
| | 9 | * Please see the accompanying license file, LICENSE.TXT, for information |
| | 10 | * on using and copying this software. |
| | 11 | */ |
| | 12 | /* |
| | 13 | Name |
| | 14 | tokth.c - hashed symbol table manipulation functions |
| | 15 | Function |
| | 16 | Implements hashed symbol tables. A hashed symbol table stores |
| | 17 | a table of pointers to linked lists of symbols; each entry in |
| | 18 | the table corresponds to a hash value, allowing a large table |
| | 19 | to be searched for a symbol rapidly. |
| | 20 | Notes |
| | 21 | Separated from tok.c to allow the run-time to link the hashed |
| | 22 | symbol table functions without needing to link the rest of the |
| | 23 | lexical analysis subsystem. |
| | 24 | Modified |
| | 25 | 04/11/92 MJRoberts - creation |
| | 26 | */ |
| | 27 | |
| | 28 | #include <ctype.h> |
| | 29 | #include <string.h> |
| | 30 | #include <stdlib.h> |
| | 31 | #include "os.h" |
| | 32 | #include "std.h" |
| | 33 | #include "mcm.h" |
| | 34 | #include "tok.h" |
| | 35 | #include "lin.h" |
| | 36 | #include "linf.h" |
| | 37 | |
| | 38 | /* compute a hash value */ |
| | 39 | uint tokhsh(char *nam) |
| | 40 | { |
| | 41 | uint hash = 0; |
| | 42 | |
| | 43 | while (*nam) hash = ((hash + *nam++) & (TOKHASHSIZE - 1)); |
| | 44 | return(hash); |
| | 45 | } |
| | 46 | |
| | 47 | /* for allocation - size of tokshdef without name portion */ |
| | 48 | struct toksh1def |
| | 49 | { |
| | 50 | tokthpdef tokshnxt; |
| | 51 | toks1def tokshsc; |
| | 52 | }; |
| | 53 | typedef struct toksh1def toksh1def; |
| | 54 | |
| | 55 | /* initialize a hashed symbol table */ |
| | 56 | void tokthini(errcxdef *errctx, mcmcxdef *memctx, toktdef *toktab1) |
| | 57 | { |
| | 58 | tokthdef *toktab = (tokthdef *)toktab1; /* convert to correct type */ |
| | 59 | int i; |
| | 60 | |
| | 61 | CLRSTRUCT(*toktab); |
| | 62 | toktab->tokthsc.toktfadd = tokthadd; /* set add-symbol method */ |
| | 63 | toktab->tokthsc.toktfsea = tokthsea; /* set search-table method */ |
| | 64 | toktab->tokthsc.toktfset = tokthset; /* update symbol */ |
| | 65 | toktab->tokthsc.toktfeach = toktheach; /* call fn for all symbols */ |
| | 66 | toktab->tokthsc.tokterr = errctx; /* set error handling context */ |
| | 67 | toktab->tokthmem = memctx; /* memory manager context */ |
| | 68 | toktab->tokthcpool = mcmalo(memctx, (ushort)TOKTHSIZE, |
| | 69 | &toktab->tokthpool[0]); |
| | 70 | toktab->tokthpcnt = 0; |
| | 71 | toktab->tokthsize = TOKTHSIZE; |
| | 72 | |
| | 73 | /* set hash table entries to point to nothing (MCMONINV) */ |
| | 74 | for (i = 0 ; i < TOKHASHSIZE ; ++i) |
| | 75 | toktab->tokthhsh[i].tokthpobj = MCMONINV; |
| | 76 | } |
| | 77 | |
| | 78 | /* add a symbol to a hashed symbol table */ |
| | 79 | void tokthadd(toktdef *toktab1, char *name, int namel, |
| | 80 | int typ, int val, int hash) |
| | 81 | { |
| | 82 | int siz = sizeof(toksh1def) + namel; |
| | 83 | toksdef *sym; |
| | 84 | tokshdef *symh; |
| | 85 | tokthdef *toktab = (tokthdef *)toktab1; |
| | 86 | |
| | 87 | if (toktab->tokthsize < siz) |
| | 88 | { |
| | 89 | mcmcxdef *mctx = toktab->tokthmem; |
| | 90 | |
| | 91 | /* insufficient space in current pool; add a new pool */ |
| | 92 | if (toktab->tokthpcnt >= TOKPOOLMAX) |
| | 93 | errsig(toktab->tokthsc.tokterr, ERR_MANYSYM); |
| | 94 | |
| | 95 | /* unlock current pool page, and note its final size */ |
| | 96 | mcmunlck(mctx, toktab->tokthpool[toktab->tokthpcnt]); |
| | 97 | toktab->tokthfinal[toktab->tokthpcnt] = toktab->tokthofs; |
| | 98 | |
| | 99 | /* allocate a new pool page, and leave it locked */ |
| | 100 | toktab->tokthcpool = mcmalo(mctx, (ushort)TOKTHSIZE, |
| | 101 | &toktab->tokthpool[++(toktab->tokthpcnt)]); |
| | 102 | toktab->tokthsize = TOKTHSIZE; |
| | 103 | toktab->tokthofs = 0; |
| | 104 | } |
| | 105 | symh = (tokshdef *)(toktab->tokthcpool + toktab->tokthofs); |
| | 106 | sym = &symh->tokshsc; |
| | 107 | |
| | 108 | /* link into list for this hash value */ |
| | 109 | OSCPYSTRUCT(symh->tokshnxt, toktab->tokthhsh[hash]); |
| | 110 | toktab->tokthhsh[hash].tokthpobj = toktab->tokthpool[toktab->tokthpcnt]; |
| | 111 | toktab->tokthhsh[hash].tokthpofs = toktab->tokthofs; |
| | 112 | |
| | 113 | /* fill in rest of toksdef */ |
| | 114 | sym->toksval = val; |
| | 115 | sym->tokslen = namel; |
| | 116 | sym->tokstyp = typ; |
| | 117 | sym->tokshsh = hash; |
| | 118 | sym->toksfr = 0; |
| | 119 | memcpy(sym->toksnam, name, (size_t)namel); |
| | 120 | |
| | 121 | /* update free pool pointer */ |
| | 122 | siz = osrndsz(siz); |
| | 123 | toktab->tokthofs += siz; |
| | 124 | if (siz > toktab->tokthsize) toktab->tokthsize = 0; |
| | 125 | else toktab->tokthsize -= siz; |
| | 126 | } |
| | 127 | |
| | 128 | /* |
| | 129 | * Scan a hash chain, calling a callback for each entry. If the |
| | 130 | * callback returns TRUE for any symbol, we stop there, and return TRUE. |
| | 131 | * If the callback returns FALSE for a symbol, we keep going. If the |
| | 132 | * callback returns FALSE for all symbols, we return FALSE. |
| | 133 | */ |
| | 134 | static int tokthscan(tokthdef *tab, uint hash, |
| | 135 | int (*cb)(void *, toksdef *, mcmon), |
| | 136 | void *cbctx) |
| | 137 | { |
| | 138 | tokshdef *symh; |
| | 139 | toksdef *sym; |
| | 140 | tokthpdef p; |
| | 141 | tokthpdef nxt; |
| | 142 | uchar *pg; |
| | 143 | mcmcxdef *mctx = tab->tokthmem; |
| | 144 | mcmon curobj; |
| | 145 | |
| | 146 | /* get first object, and lock its page if there is one */ |
| | 147 | OSCPYSTRUCT(p, tab->tokthhsh[hash]); |
| | 148 | if ((curobj = p.tokthpobj) != MCMONINV) |
| | 149 | pg = mcmlck(mctx, curobj); |
| | 150 | |
| | 151 | /* look for a match using the callback */ |
| | 152 | for ( ; p.tokthpobj != MCMONINV ; OSCPYSTRUCT(p, nxt)) |
| | 153 | { |
| | 154 | symh = (tokshdef *)(pg + p.tokthpofs); |
| | 155 | sym = &symh->tokshsc; |
| | 156 | OSCPYSTRUCT(nxt, symh->tokshnxt); |
| | 157 | |
| | 158 | /* check for a match; copy to return buffer if found */ |
| | 159 | if ((*cb)(cbctx, sym, p.tokthpobj)) |
| | 160 | { |
| | 161 | mcmunlck(mctx, p.tokthpobj); |
| | 162 | return(TRUE); |
| | 163 | } |
| | 164 | |
| | 165 | /* if the next page is different from this one, get new lock */ |
| | 166 | if (nxt.tokthpobj != curobj && nxt.tokthpobj != MCMONINV) |
| | 167 | { |
| | 168 | mcmunlck(mctx, curobj); |
| | 169 | curobj = nxt.tokthpobj; |
| | 170 | pg = mcmlck(mctx, curobj); |
| | 171 | } |
| | 172 | } |
| | 173 | |
| | 174 | /* unlock last object, if we had a lock at all */ |
| | 175 | if (curobj != MCMONINV) mcmunlck(mctx, curobj); |
| | 176 | return(FALSE); |
| | 177 | } |
| | 178 | |
| | 179 | struct tokseadef |
| | 180 | { |
| | 181 | char *tokseanam; |
| | 182 | toksdef tokseasym; |
| | 183 | toksdef *toksearet; |
| | 184 | mcmcxdef *tokseamctx; |
| | 185 | }; |
| | 186 | typedef struct tokseadef tokseadef; |
| | 187 | |
| | 188 | /* search callback */ |
| | 189 | static int tokthsea1(void *ctx0, toksdef *sym, mcmon objn) |
| | 190 | { |
| | 191 | tokseadef *ctx = (tokseadef *)ctx0; |
| | 192 | |
| | 193 | VARUSED(objn); |
| | 194 | |
| | 195 | if (sym->tokslen == ctx->tokseasym.tokslen && |
| | 196 | !memcmp(sym->toksnam, ctx->tokseanam, ctx->tokseasym.tokslen)) |
| | 197 | { |
| | 198 | memcpy(ctx->toksearet, sym, |
| | 199 | (size_t)(sizeof(toks1def) + ctx->tokseasym.tokslen)); |
| | 200 | return(TRUE); |
| | 201 | } |
| | 202 | else |
| | 203 | return(FALSE); |
| | 204 | } |
| | 205 | |
| | 206 | /* search a hashed symbol table for a symbol */ |
| | 207 | int tokthsea(toktdef *tab1, char *name, int namel, int hash, toksdef *ret) |
| | 208 | { |
| | 209 | tokseadef ctx; |
| | 210 | |
| | 211 | ctx.tokseanam = name; |
| | 212 | ctx.tokseasym.tokslen = namel; |
| | 213 | ctx.toksearet = ret; |
| | 214 | return(tokthscan((tokthdef *)tab1, hash, tokthsea1, &ctx)); |
| | 215 | } |
| | 216 | |
| | 217 | /* callback for tokthset */ |
| | 218 | static int tokthset1(void *ctx0, toksdef *sym, mcmon objn) |
| | 219 | { |
| | 220 | tokseadef *ctx = (tokseadef *)ctx0; |
| | 221 | |
| | 222 | if (sym->tokslen == ctx->tokseasym.tokslen |
| | 223 | && !memcmp(sym->toksnam, ctx->tokseasym.toksnam, |
| | 224 | ctx->tokseasym.tokslen)) |
| | 225 | { |
| | 226 | sym->toksval = ctx->tokseasym.toksval; |
| | 227 | sym->tokstyp = ctx->tokseasym.tokstyp; |
| | 228 | |
| | 229 | /* touch object, since it's been changed */ |
| | 230 | mcmtch(ctx->tokseamctx, objn); |
| | 231 | return(TRUE); |
| | 232 | } |
| | 233 | else |
| | 234 | return(FALSE); |
| | 235 | } |
| | 236 | |
| | 237 | /* update a symbol in a hashed symbol table */ |
| | 238 | void tokthset(toktdef *tab1, toksdef *newsym) |
| | 239 | { |
| | 240 | tokseadef ctx; |
| | 241 | tokthdef *tab = (tokthdef *)tab1; |
| | 242 | |
| | 243 | OSCPYSTRUCT(ctx.tokseasym, *newsym); |
| | 244 | ctx.tokseamctx = tab->tokthmem; |
| | 245 | tokthscan((tokthdef *)tab1, newsym->tokshsh, tokthset1, &ctx); |
| | 246 | } |
| | 247 | |
| | 248 | /* callback for tokthfind */ |
| | 249 | static int tokthfind1(void *ctx0, toksdef *sym, mcmon objn) |
| | 250 | { |
| | 251 | tokseadef *ctx = (tokseadef *)ctx0; |
| | 252 | |
| | 253 | VARUSED(objn); |
| | 254 | |
| | 255 | if (sym->toksval == ctx->tokseasym.toksval |
| | 256 | && sym->tokstyp == ctx->tokseasym.tokstyp) |
| | 257 | { |
| | 258 | memcpy(ctx->toksearet, sym, |
| | 259 | (size_t)(sizeof(toks1def) + sym->tokslen)); |
| | 260 | return(TRUE); |
| | 261 | } |
| | 262 | else |
| | 263 | return(FALSE); |
| | 264 | } |
| | 265 | |
| | 266 | /* find a symbol of a particular type and value */ |
| | 267 | int tokthfind(toktdef *tab1, int typ, uint val, toksdef *ret) |
| | 268 | { |
| | 269 | tokseadef ctx; |
| | 270 | int i; |
| | 271 | |
| | 272 | ctx.tokseasym.tokstyp = typ; |
| | 273 | ctx.tokseasym.toksval = val; |
| | 274 | ctx.toksearet = ret; |
| | 275 | |
| | 276 | for (i = 0 ; i < TOKHASHSIZE ; ++i) |
| | 277 | { |
| | 278 | if (tokthscan((tokthdef *)tab1, i, tokthfind1, &ctx)) |
| | 279 | return(TRUE); |
| | 280 | } |
| | 281 | return(FALSE); |
| | 282 | } |
| | 283 | |
| | 284 | /* call a callback for each function in a hashed symbol table */ |
| | 285 | void toktheach(toktdef *tab1, |
| | 286 | void (*cb)(void *, toksdef *), void *ctx) |
| | 287 | { |
| | 288 | tokthdef *tab = (tokthdef *)tab1; |
| | 289 | uchar *p; |
| | 290 | uint max; |
| | 291 | uint ofs; |
| | 292 | tokshdef *symh; |
| | 293 | toksdef *sym; |
| | 294 | uint siz; |
| | 295 | uint i; |
| | 296 | |
| | 297 | for (i = 0 ; i <= tab->tokthpcnt ; ++i) |
| | 298 | { |
| | 299 | /* lock the current page */ |
| | 300 | p = mcmlck(tab->tokthmem, tab->tokthpool[i]); |
| | 301 | |
| | 302 | ERRBEGIN(tab1->tokterr) |
| | 303 | |
| | 304 | max = (i == tab->tokthpcnt ? tab->tokthofs : tab->tokthfinal[i]); |
| | 305 | for (ofs = 0 ; ofs < max ; ) |
| | 306 | { |
| | 307 | /* get this symbol */ |
| | 308 | symh = (tokshdef *)(p + ofs); |
| | 309 | sym = &symh->tokshsc; |
| | 310 | |
| | 311 | /* call the user callback */ |
| | 312 | (*cb)(ctx, sym); |
| | 313 | |
| | 314 | /* advance to the next symbol on this page */ |
| | 315 | siz = sizeof(toksh1def) + sym->tokslen; |
| | 316 | ofs += osrndsz(siz); |
| | 317 | } |
| | 318 | |
| | 319 | ERRCLEAN(tab1->tokterr) |
| | 320 | mcmunlck(tab->tokthmem, tab->tokthpool[i]); |
| | 321 | ERRENDCLN(tab1->tokterr) |
| | 322 | |
| | 323 | /* done with current page; unlock it */ |
| | 324 | mcmunlck(tab->tokthmem, tab->tokthpool[i]); |
| | 325 | } |
| | 326 | } |
| | 327 | |