-- BcdTab.Mesa -- last edited by Sandman on October 8, 1980 4:06 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AltoDefs USING [CharsPerWord], BcdDefs USING [httype, sstype], BcdOps USING [NameString], InlineDefs USING [BITAND, BITXOR], Strings USING [ AppendChar, AppendSubString, EqualSubStrings, EquivalentSubStrings, String, SubString, SubStringDescriptor], Symbols: FROM "bcdsymbols" USING [HTIndex, HTNull, HTRecord, HVIndex, HVLength], SymbolOps: FROM "bcdsymbolops" USING [], Table USING [AddNotify, Allocate, Base, DropNotify, Index, Notifier, Trim]; BcdTab: PROGRAM IMPORTS InlineDefs, Table, Strings EXPORTS SymbolOps = BEGIN OPEN Symbols; SubString: TYPE = Strings.SubString; SubStringDescriptor: TYPE = Strings.SubStringDescriptor; -- tables defining the current symbol table hashVec: LONG POINTER TO ARRAY HVIndex OF HTIndex; ht: LONG DESCRIPTOR FOR ARRAY --HTIndex-- OF HTRecord; htb: Table.Base; -- hash table ssb: BcdOps.NameString; -- id string UpdateBases: Table.Notifier = { OPEN BcdDefs; htb ← base[httype]; ssb ← LOOPHOLE[base[sstype]]; hashVec ← htb; ht ← DESCRIPTOR[htb + LENGTH[hashVec↑]*SIZE[HTIndex], LENGTH[ht]]}; AllocateHash: PROC RETURNS [hti: HTIndex] = { next: Table.Index = Table.Allocate[BcdDefs.httype, 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]}; -- variables for building the symbol string ssw: Table.Index; initialized: BOOLEAN ← FALSE; Initialize: PUBLIC PROC = { IF initialized THEN Finalize[]; hashVec ← NIL; Table.AddNotify[UpdateBases]; Reset[]; initialized ← TRUE}; Finalize: PUBLIC PROC = {initialized ← FALSE; Table.DropNotify[UpdateBases]}; Reset: PUBLIC PROC = { nullSS: SubStringDescriptor ← [base: ""L, offset:, length: 0]; Table.Trim[BcdDefs.sstype, 0]; Table.Trim[BcdDefs.httype, 0]; [] ← Table.Allocate[BcdDefs.httype, HVLength*SIZE[HTIndex]]; hashVec ← htb; hashVec↑ ← ALL[HTNull]; ht ← DESCRIPTOR[htb + LENGTH[hashVec↑]*SIZE[HTIndex], 0]; ssw ← Table.Allocate[BcdDefs.sstype, SIZE[StringBody]] + SIZE[StringBody]; 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 = AltoDefs.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.Allocate[BcdDefs.sstype, nw]) # ssw THEN ERROR; ssw ← ssw + nw; ssb.string ← [length: ssb.string.length, text:, maxlength: ssb.string.maxlength + nw*CharsPerWord]}; Strings.AppendChar[@ssb.string, LOOPHOLE[s.length, CHARACTER]]; Strings.AppendSubString[@ssb.string, s]; hti ← AllocateHash[]; ht[hti].link ← hashVec[hvi]; hashVec[hvi] ← hti; RETURN}; -- the following copied from symboltable.mesa ignoreCases: BOOLEAN ← FALSE; HashValue: PROC [s: SubString] RETURNS [HVIndex] = { CharBits: PROC [CHARACTER, WORD] RETURNS [WORD] = LOOPHOLE[InlineDefs.BITAND]; Mask: WORD = 337B; -- masks out ASCII case shifts n: CARDINAL = s.length; b: Strings.String = s.base; v: WORD = CharBits[b[s.offset], Mask]*177B + CharBits[b[s.offset + (n - 1)], Mask]; RETURN[InlineDefs.BITXOR[v, n*17B] MOD LENGTH[hashVec↑]]}; FindString: PUBLIC PROC [s: SubString] RETURNS [found: BOOLEAN, hti: HTIndex] = { 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]}; FindEquivalentString: PUBLIC PROC [s: SubString] RETURNS [found: BOOLEAN, hti: HTIndex] = { oldcase: BOOLEAN = 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]}}; END.