-- BcdTab.Mesa
-- last edited by Satterthwaite on September 14, 1982 9:19 am
-- last edited by Lewis on 10-Dec-80 20:11:41
DIRECTORY
Alloc: TYPE USING [AddNotify, DropNotify, Handle, Notifier, Trim, Words],
BcdDefs: TYPE USING [httype, PackedString, sstype],
Environment: TYPE USING [charsPerWord],
Inline: TYPE USING [BITAND, BITXOR],
Strings: TYPE USING [
AppendChar, AppendSubString, EqualSubStrings, EquivalentSubStrings, String,
SubString, SubStringDescriptor],
Symbols: TYPE USING [HTIndex, HTNull, HTRecord, HVIndex, HVLength],
SymbolOps: TYPE USING [],
Table: TYPE USING [Base, Index];
BcdTab: PROGRAM
IMPORTS Alloc, Inline, Strings
EXPORTS SymbolOps = {
OPEN Symbols;
SubString: TYPE ~ Strings.SubString;
SubStringDescriptor: TYPE ~ Strings.SubStringDescriptor;
-- tables defining the current symbol table
table: Alloc.Handle;
hashVec: LONG POINTER TO ARRAY HVIndex OF HTIndex;
ht: LONG DESCRIPTOR FOR ARRAY --HTIndex-- OF HTRecord;
htb: Table.Base; -- hash table
ssb: LONG POINTER TO BcdDefs.PackedString; -- id string
UpdateBases: Alloc.Notifier ~ {
OPEN BcdDefs;
htb ← base[httype];
ssb ← LOOPHOLE[base[sstype]];
hashVec ← htb;
ht ← DESCRIPTOR[htb + hashVec↑.LENGTH*HTIndex.SIZE, ht.LENGTH]};
AllocateHash: PROC RETURNS [hti: HTIndex] ~ {
next: Table.Index ~ table.Words[BcdDefs.httype, HTRecord.SIZE];
hti ← ht.LENGTH;
ht ← DESCRIPTOR[ht.BASE, ht.LENGTH + 1];
ht[hti] ← HTRecord[link~HTNull, offset~ssb.string.length+1];
RETURN [hti - 1]};
-- variables for building the symbol string
ssw: Table.Index;
initialized: BOOL ← FALSE;
Initialize: PUBLIC PROC [ownTable: Alloc.Handle] ~ {
IF initialized THEN Finalize[]; hashVec ← NIL;
table ← ownTable; table.AddNotify[UpdateBases];
Reset[];
initialized ← TRUE};
Finalize: PUBLIC PROC ~ {
table.DropNotify[UpdateBases]; table ← NIL;
initialized ← FALSE};
Reset: PUBLIC PROC ~ {
nullSS: SubStringDescriptor ← [base~"null"L, offset~0, length~0];
table.Trim[BcdDefs.sstype, 0];
table.Trim[BcdDefs.httype, 0];
[] ← table.Words[BcdDefs.httype, HVLength*HTIndex.SIZE];
hashVec ← htb;
hashVec↑ ← ALL[HTNull];
ht ← DESCRIPTOR[htb + hashVec↑.LENGTH*HTIndex.SIZE, 0];
ssw ← table.Words[BcdDefs.sstype, StringBody.SIZE] + StringBody.SIZE;
ssb.string ← [length~0, maxlength~0, text~];
[] ← AllocateHash[];
IF EnterString[@nullSS] # HTNull THEN ERROR};
-- hash entry creation
EnterString: PUBLIC PROC [s: SubString] RETURNS [hti: HTIndex] ~ {
hvi: HVIndex ~ HashValue[s];
desc: SubStringDescriptor ← [base~@ssb.string, offset~, length~];
charsPerWord: CARDINAL ~ Environment.charsPerWord;
offset, length, nw: CARDINAL;
ssi: Table.Index;
FOR hti ← hashVec[hvi], ht[hti].link UNTIL hti = HTNull DO
SubStringForHash[@desc, hti];
IF Strings.EqualSubStrings[s, @desc] THEN RETURN [hti];
ENDLOOP;
offset ← ssb.string.length;
length ← s.length + 1;
nw ← (offset + length + (charsPerWord-1) - ssb.string.maxlength)/charsPerWord;
IF nw # 0 THEN {
IF (ssi ← table.Words[BcdDefs.sstype, nw]) # ssw THEN ERROR;
ssw ← ssw + nw;
ssb.string ← [
text~,
length~ssb.string.length, maxlength~ssb.string.maxlength+nw*charsPerWord]};
Strings.AppendChar[@ssb.string, LOOPHOLE[s.length, CHAR]];
Strings.AppendSubString[@ssb.string, s];
hti ← AllocateHash[];
ht[hti].link ← hashVec[hvi];
hashVec[hvi] ← hti;
RETURN};
-- the following copied from SymbolPack.mesa
ignoreCases: BOOL ← FALSE;
HashValue: PROC [s: SubString] RETURNS [HVIndex] ~ {
CharBits: PROC [CHAR, WORD] RETURNS [WORD] ~ LOOPHOLE[Inline.BITAND];
mask: WORD ~ 0DFh; -- masks out ASCII case shifts
n: CARDINAL ~ s.length;
b: Strings.String ~ s.base;
v: WORD ~ CharBits[b[s.offset], mask]*7fh + CharBits[b[s.offset + (n-1)], mask];
RETURN [Inline.BITXOR[v, n*0fh] MOD hashVec↑.LENGTH]};
FindString: PUBLIC PROC [s: SubString] RETURNS [found: BOOL, hti: HTIndex] ~ {
desc: SubStringDescriptor;
ss: SubString ~ @desc;
FOR hti ← hashVec[HashValue[s]], ht[hti].link UNTIL hti = HTNull DO
SubStringForHash[ss, hti];
found ← IF ignoreCases
THEN Strings.EquivalentSubStrings[s, ss]
ELSE Strings.EqualSubStrings[s, ss];
IF found THEN RETURN;
ENDLOOP;
RETURN [FALSE, HTNull]};
FindEquivalentString: PUBLIC PROC [s: SubString] RETURNS [found: BOOL, hti: HTIndex] ~ {
oldcase: BOOL ~ ignoreCases;
ignoreCases ← TRUE;
[found, hti] ← FindString[s];
ignoreCases ← oldcase;
RETURN};
SubStringForHash: PUBLIC PROC [s: SubString, hti: HTIndex] ~ {
s.base ← @ssb.string;
IF hti = HTNull THEN s.offset ← s.length ← 0
ELSE {s.offset ← ht[hti].offset; s.length ← ssb.size[ht[hti].offset]}};
}.