-- SymTab.Mesa Edited by Lewis on 31-Dec-80 10:54:41
-- last edited by Levin on July 6, 1982 4:49 pm
DIRECTORY
Alloc USING [AddNotify, DropNotify, Handle, Notifier, Trim, Words],
Inline USING [BITAND, BITXOR],
PackagerDefs USING [globalData, packhttype, packsstype],
PackEnviron USING [BcdStringHandle, CharsPerWord],
Strings USING [
AppendChar, AppendSubString, EqualSubStrings, EquivalentSubStrings,
String, SubString, SubStringDescriptor],
SymTabDefs USING [HTIndex, HTNull, HTRecord, HVIndex, HVLength],
SymTabOps,
Table USING [Base, Index];
SymTab: PROGRAM
IMPORTS Alloc, Inline, PackagerDefs, Strings
EXPORTS SymTabOps
SHARES SymTabDefs =
BEGIN OPEN SymTabDefs, PackagerDefs;
SubString: TYPE = Strings.SubString;
SubStringDescriptor: TYPE = Strings.SubStringDescriptor;
table: Alloc.Handle ← NIL;
-- Tables defining the current symbol table
hashVec: LONG DESCRIPTOR FOR ARRAY --HVIndex-- OF HTIndex;
ht: LONG DESCRIPTOR FOR ARRAY --HTIndex-- OF HTRecord;
htb: Table.Base; -- hash table
ssb: PackEnviron.BcdStringHandle; -- id string
UpdateBases: Alloc.Notifier =
BEGIN
htb ← base[packhttype];
ssb ← base[packsstype];
hashVec ← DESCRIPTOR[htb, LENGTH[hashVec]];
ht ← DESCRIPTOR[htb + LENGTH[hashVec]*SIZE[HTIndex], LENGTH[ht]];
END;
AllocateHash: PROCEDURE RETURNS [hti: HTIndex] =
BEGIN
next: Table.Index = table.Words[packhttype, SIZE[HTRecord]];
hti ← LENGTH[ht];
IF hti*SIZE[HTRecord]+LENGTH[hashVec] # LOOPHOLE[next, INTEGER] THEN
ERROR;
ht ← DESCRIPTOR[BASE[ht], LENGTH[ht]+1];
ht[hti] ← HTRecord[link: HTNull, offset: ssb.string.length+1];
RETURN[hti - 1];
END;
-- Variables for building the symbol string
ssw: Table.Index;
tableOpen: BOOLEAN ← FALSE;
Initialize: PUBLIC PROCEDURE =
BEGIN
IF tableOpen THEN Finalize[];
hashVec ← DESCRIPTOR[NIL, HVLength];
table ← PackagerDefs.globalData.ownTable;
table.AddNotify[UpdateBases];
Reset[];
tableOpen ← TRUE;
END;
Finalize: PUBLIC PROCEDURE =
BEGIN
tableOpen ← FALSE;
table.DropNotify[UpdateBases];
table ← NIL;
END;
Reset: PUBLIC PROCEDURE =
BEGIN
nullss: SubStringDescriptor ← [base: "null"L, offset: 0, length: 0];
table.Trim[packsstype, 0];
table.Trim[packhttype, 0];
[] ← table.Words[packhttype, HVLength*SIZE[HTIndex]];
hashVec ← DESCRIPTOR[htb, HVLength];
FOR i: HVIndex IN HVIndex DO hashVec[i] ← HTNull ENDLOOP;
ht ← DESCRIPTOR[htb+LENGTH[hashVec]*SIZE[HTIndex], 0];
ssw ← table.Words[packsstype, SIZE[StringBody]] + SIZE[StringBody];
ssb.string ← [length: 0, maxlength: 0, text: ];
[] ← AllocateHash[];
IF EnterString[@nullss] # HTNull THEN ERROR;
END;
-- Hash entry creation
EnterString: PUBLIC PROCEDURE [s: SubString] RETURNS [hti: HTIndex] =
BEGIN
hvi: HVIndex;
desc: SubStringDescriptor ← [base: @ssb.string, offset:, length:];
CharsPerWord: CARDINAL = PackEnviron.CharsPerWord;
offset, length, nw: CARDINAL;
ssi: Table.Index;
hvi ← HashValue[s];
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
BEGIN
IF (ssi ← table.Words[packsstype, nw]) # ssw THEN ERROR;
ssw ← ssw + nw;
ssb.string ← [
length: ssb.string.length,
text: ,
maxlength: ssb.string.maxlength + nw*CharsPerWord];
END;
Strings.AppendChar[@ssb.string, LOOPHOLE[s.length, CHARACTER]];
Strings.AppendSubString[@ssb.string, s];
hti ← AllocateHash[];
ht[hti].link ← hashVec[hvi]; hashVec[hvi] ← hti;
END;
ignoreCases: BOOLEAN ← FALSE;
HashValue: PROC [s: SubString] RETURNS [HVIndex] =
BEGIN
CharMask: PROC [CHARACTER, WORD] RETURNS [CARDINAL] =
LOOPHOLE[Inline.BITAND];
mask: WORD = 137B; -- masks out ASCII case shifts
n: CARDINAL = s.length;
b: Strings.String = s.base;
v: WORD ←
CharMask[b[s.offset], mask]*177B + CharMask[b[s.offset+(n-1)], mask];
RETURN[Inline.BITXOR[v, n*17B] MOD LENGTH[hashVec]]
END;
FindString: PUBLIC PROC [
s: SubString] RETURNS [found: BOOLEAN, hti: HTIndex] =
BEGIN
desc: SubStringDescriptor;
ss: SubString = @desc;
hti ← hashVec[HashValue[s]];
WHILE hti # HTNull
DO
SubStringForHash[ss, hti];
found ←
IF ignoreCases THEN Strings.EquivalentSubStrings[s,ss]
ELSE Strings.EqualSubStrings[s,ss];
IF found THEN RETURN;
hti ← ht[hti].link;
ENDLOOP;
RETURN[FALSE, HTNull]
END;
FindEquivalentString: PUBLIC PROCEDURE [
s: SubString] RETURNS [found: BOOLEAN, hti: HTIndex] =
BEGIN
oldcase: BOOLEAN = ignoreCases;
ignoreCases ← TRUE;
[found, hti] ← FindString[s];
ignoreCases ← oldcase;
END;
SubStringForHash: PUBLIC PROCEDURE [s: SubString, hti: HTIndex] =
BEGIN -- gets string for hash table entry
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]};
END;
END.