Files
scummvm-cursorfix/engines/glk/tads/tads2/tokenizer_hash.cpp
2026-02-02 04:50:13 +01:00

336 lines
8.9 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* hashed symbol table manipulation functions
*
* Implements hashed symbol tables. A hashed symbol table stores
* a table of pointers to linked lists of symbols; each entry in
* the table corresponds to a hash value, allowing a large table
* to be searched for a symbol rapidly.
*
* Notes: Separated from tokenizer.cpp to allow the run-time to link the hashed
* symbol table functions without needing to link the rest of the
* lexical analysis subsystem.
*/
#include "glk/tads/tads2/tokenizer.h"
#include "glk/tads/tads2/error.h"
#include "glk/tads/os_glk.h"
namespace Glk {
namespace TADS {
namespace TADS2 {
/* compute a hash value */
uint tokhsh(char *nam)
{
uint hash = 0;
while (*nam) hash = ((hash + *nam++) & (TOKHASHSIZE - 1));
return(hash);
}
/* for allocation - size of tokshdef without name portion */
struct toksh1def
{
tokthpdef tokshnxt;
toks1def tokshsc;
};
typedef struct toksh1def toksh1def;
/* initialize a hashed symbol table */
void tokthini(errcxdef *errctx, mcmcxdef *memctx, toktdef *toktab1)
{
tokthdef *toktab = (tokthdef *)toktab1; /* convert to correct type */
int i;
CLRSTRUCT(*toktab);
toktab->tokthsc.toktfadd = tokthadd; /* set add-symbol method */
toktab->tokthsc.toktfsea = tokthsea; /* set search-table method */
toktab->tokthsc.toktfset = tokthset; /* update symbol */
toktab->tokthsc.toktfeach = toktheach; /* call fn for all symbols */
toktab->tokthsc.tokterr = errctx; /* set error handling context */
toktab->tokthmem = memctx; /* memory manager context */
toktab->tokthcpool = mcmalo(memctx, (ushort)TOKTHSIZE,
&toktab->tokthpool[0]);
toktab->tokthpcnt = 0;
toktab->tokthsize = TOKTHSIZE;
/* set hash table entries to point to nothing (MCMONINV) */
for (i = 0 ; i < TOKHASHSIZE ; ++i)
toktab->tokthhsh[i].tokthpobj = MCMONINV;
}
/* add a symbol to a hashed symbol table */
void tokthadd(toktdef *toktab1, char *name, int namel,
int typ, int val, int hash)
{
int siz = sizeof(toksh1def) + namel;
toksdef *sym;
tokshdef *symh;
tokthdef *toktab = (tokthdef *)toktab1;
if (toktab->tokthsize < siz)
{
mcmcxdef *mctx = toktab->tokthmem;
/* insufficient space in current pool; add a new pool */
if (toktab->tokthpcnt >= TOKPOOLMAX)
errsig(toktab->tokthsc.tokterr, ERR_MANYSYM);
/* unlock current pool page, and note its final size */
mcmunlck(mctx, toktab->tokthpool[toktab->tokthpcnt]);
toktab->tokthfinal[toktab->tokthpcnt] = toktab->tokthofs;
/* allocate a new pool page, and leave it locked */
toktab->tokthcpool = mcmalo(mctx, (ushort)TOKTHSIZE,
&toktab->tokthpool[++(toktab->tokthpcnt)]);
toktab->tokthsize = TOKTHSIZE;
toktab->tokthofs = 0;
}
symh = (tokshdef *)(toktab->tokthcpool + toktab->tokthofs);
sym = &symh->tokshsc;
/* link into list for this hash value */
OSCPYSTRUCT(symh->tokshnxt, toktab->tokthhsh[hash]);
toktab->tokthhsh[hash].tokthpobj = toktab->tokthpool[toktab->tokthpcnt];
toktab->tokthhsh[hash].tokthpofs = toktab->tokthofs;
/* fill in rest of toksdef */
sym->toksval = val;
sym->tokslen = namel;
sym->tokstyp = typ;
sym->tokshsh = hash;
sym->toksfr = 0;
memcpy(sym->toksnam, name, (size_t)namel);
/* update free pool pointer */
siz = osrndsz(siz);
toktab->tokthofs += siz;
if (siz > toktab->tokthsize) toktab->tokthsize = 0;
else toktab->tokthsize -= siz;
}
/*
* Scan a hash chain, calling a callback for each entry. If the
* callback returns TRUE for any symbol, we stop there, and return TRUE.
* If the callback returns FALSE for a symbol, we keep going. If the
* callback returns FALSE for all symbols, we return FALSE.
*/
static int tokthscan(tokthdef *tab, uint hash,
int (*cb)(void *, toksdef *, mcmon),
void *cbctx)
{
tokshdef *symh;
toksdef *sym;
tokthpdef p;
tokthpdef nxt;
uchar *pg = nullptr;
mcmcxdef *mctx = tab->tokthmem;
mcmon curobj;
/* get first object, and lock its page if there is one */
OSCPYSTRUCT(p, tab->tokthhsh[hash]);
if ((curobj = p.tokthpobj) != MCMONINV)
pg = mcmlck(mctx, curobj);
/* look for a match using the callback */
for ( ; p.tokthpobj != MCMONINV ; OSCPYSTRUCT(p, nxt))
{
symh = (tokshdef *)(pg + p.tokthpofs);
sym = &symh->tokshsc;
OSCPYSTRUCT(nxt, symh->tokshnxt);
/* check for a match; copy to return buffer if found */
if ((*cb)(cbctx, sym, p.tokthpobj))
{
mcmunlck(mctx, p.tokthpobj);
return(TRUE);
}
/* if the next page is different from this one, get new lock */
if (nxt.tokthpobj != curobj && nxt.tokthpobj != MCMONINV)
{
mcmunlck(mctx, curobj);
curobj = nxt.tokthpobj;
pg = mcmlck(mctx, curobj);
}
}
/* unlock last object, if we had a lock at all */
if (curobj != MCMONINV) mcmunlck(mctx, curobj);
return(FALSE);
}
struct tokseadef
{
char *tokseanam;
toksdef tokseasym;
toksdef *toksearet;
mcmcxdef *tokseamctx;
};
typedef struct tokseadef tokseadef;
/* search callback */
static int tokthsea1(void *ctx0, toksdef *sym, mcmon objn)
{
tokseadef *ctx = (tokseadef *)ctx0;
VARUSED(objn);
if (sym->tokslen == ctx->tokseasym.tokslen &&
!memcmp(sym->toksnam, ctx->tokseanam, ctx->tokseasym.tokslen))
{
memcpy(ctx->toksearet, sym,
(size_t)(sizeof(toks1def) + ctx->tokseasym.tokslen));
return(TRUE);
}
else
return(FALSE);
}
/* search a hashed symbol table for a symbol */
int tokthsea(toktdef *tab1, char *name, int namel, int hash, toksdef *ret)
{
tokseadef ctx;
ctx.tokseanam = name;
ctx.tokseasym.tokslen = namel;
ctx.toksearet = ret;
return(tokthscan((tokthdef *)tab1, hash, tokthsea1, &ctx));
}
/* callback for tokthset */
static int tokthset1(void *ctx0, toksdef *sym, mcmon objn)
{
tokseadef *ctx = (tokseadef *)ctx0;
if (sym->tokslen == ctx->tokseasym.tokslen
&& !memcmp(sym->toksnam, ctx->tokseasym.toksnam,
ctx->tokseasym.tokslen))
{
sym->toksval = ctx->tokseasym.toksval;
sym->tokstyp = ctx->tokseasym.tokstyp;
/* touch object, since it's been changed */
mcmtch(ctx->tokseamctx, objn);
return(TRUE);
}
else
return(FALSE);
}
/* update a symbol in a hashed symbol table */
void tokthset(toktdef *tab1, toksdef *newsym)
{
tokseadef ctx;
tokthdef *tab = (tokthdef *)tab1;
OSCPYSTRUCT(ctx.tokseasym, *newsym);
ctx.tokseamctx = tab->tokthmem;
tokthscan((tokthdef *)tab1, newsym->tokshsh, tokthset1, &ctx);
}
/* callback for tokthfind */
static int tokthfind1(void *ctx0, toksdef *sym, mcmon objn)
{
tokseadef *ctx = (tokseadef *)ctx0;
VARUSED(objn);
if (sym->toksval == ctx->tokseasym.toksval
&& sym->tokstyp == ctx->tokseasym.tokstyp)
{
memcpy(ctx->toksearet, sym,
(size_t)(sizeof(toks1def) + sym->tokslen));
return(TRUE);
}
else
return(FALSE);
}
/* find a symbol of a particular type and value */
int tokthfind(toktdef *tab1, int typ, uint val, toksdef *ret)
{
tokseadef ctx;
int i;
ctx.tokseasym.tokstyp = typ;
ctx.tokseasym.toksval = val;
ctx.toksearet = ret;
for (i = 0 ; i < TOKHASHSIZE ; ++i)
{
if (tokthscan((tokthdef *)tab1, i, tokthfind1, &ctx))
return(TRUE);
}
return(FALSE);
}
/* call a callback for each function in a hashed symbol table */
void toktheach(toktdef *tab1,
void (*cb)(void *, toksdef *), void *ctx)
{
tokthdef *tab = (tokthdef *)tab1;
uchar *p;
uint max;
uint ofs;
tokshdef *symh;
toksdef *sym;
uint siz;
uint i;
for (i = 0 ; i <= tab->tokthpcnt ; ++i)
{
/* lock the current page */
p = mcmlck(tab->tokthmem, tab->tokthpool[i]);
ERRBEGIN(tab1->tokterr)
max = (i == tab->tokthpcnt ? tab->tokthofs : tab->tokthfinal[i]);
for (ofs = 0 ; ofs < max ; )
{
/* get this symbol */
symh = (tokshdef *)(p + ofs);
sym = &symh->tokshsc;
/* call the user callback */
(*cb)(ctx, sym);
/* advance to the next symbol on this page */
siz = sizeof(toksh1def) + sym->tokslen;
ofs += osrndsz(siz);
}
ERRCLEAN(tab1->tokterr)
mcmunlck(tab->tokthmem, tab->tokthpool[i]);
ERRENDCLN(tab1->tokterr)
/* done with current page; unlock it */
mcmunlck(tab->tokthmem, tab->tokthpool[i]);
}
}
} // End of namespace TADS2
} // End of namespace TADS
} // End of namespace Glk