-- file LiteralPack.Mesa -- last modified by Satterthwaite, August 28, 1978 2:58 PM DIRECTORY AltoDefs: FROM "altodefs" USING [CharsPerWord], Literals: FROM "literals", LiteralOps: FROM "literalops", StringDefs: FROM "stringdefs" USING [ SubString, SubStringDescriptor, AppendChar, AppendSubString, EqualSubStrings, WordsForString], Table: FROM "table" USING [ Base, Finger, Notifier, Limit, AddNotify, Allocate, Bounds, DropNotify]; LiteralPack: PROGRAM IMPORTS StringDefs, Table EXPORTS LiteralOps = PUBLIC BEGIN OPEN Literals; ltb: PRIVATE Table.Base; -- literal table base stb: PRIVATE Table.Base; -- string table base UpdateBases: PRIVATE Table.Notifier = BEGIN -- called whenever the main symbol table is repacked ltb ← base[ltType]; stb ← base[stType]; RETURN END; initialized: PRIVATE BOOLEAN ← FALSE; Initialize: PROCEDURE = BEGIN -- called to set up the compiler's literal table shvi: SLitHVIndex; IF initialized THEN Finalize[]; [] ← ForgetEntries[]; FOR shvi IN SLitHVIndex DO sHashVec[shvi] ← MSTNull ENDLOOP; stLimit ← localStart ← FIRST[STIndex]; locals ← markBit ← FALSE; Table.AddNotify[UpdateBases]; initialized ← TRUE; RETURN END; Finalize: PROCEDURE = BEGIN -- closes the symbol table blocks initialized ← FALSE; Table.DropNotify[UpdateBases]; RETURN END; -- literal table management LitHVLength: PRIVATE INTEGER = 53; LitHVIndex: PRIVATE TYPE = [0..LitHVLength); hashVec: PRIVATE ARRAY LitHVIndex OF LTIndex; Find: PROCEDURE [v: WORD] RETURNS [lti: LTIndex] = BEGIN hvi: LitHVIndex = v MOD LitHVLength; FOR lti ← hashVec[hvi], ltb[lti].link UNTIL lti = LTNull DO WITH entry: ltb[lti] SELECT FROM short => IF entry.value = v THEN EXIT; ENDCASE; REPEAT FINISHED => BEGIN lti ← Table.Allocate[ltType, SIZE[short LTRecord]]; ltb[lti] ← LTRecord[datum: short[value: v], link: hashVec[hvi]]; hashVec[hvi] ← lti; END; ENDLOOP; RETURN END; FindMultiWord: PRIVATE PROCEDURE [baseP: Table.Finger, desc: LitDescriptor] RETURNS [lti: LTIndex] = BEGIN i: CARDINAL; v: WORD; hvi: LitHVIndex; lLti: Table.Base RELATIVE POINTER [0..Table.Limit/2) TO long LTRecord; v ← 0; FOR i IN [0 .. desc.length) DO v ← v + baseP↑[desc.offset][i] ENDLOOP; hvi ← v MOD LitHVLength; FOR lti ← hashVec[hvi], ltb[lti].link UNTIL lti = LTNull DO WITH entry: ltb[lti] SELECT FROM long => IF desc.length = entry.length THEN FOR i IN [0 .. desc.length) DO IF entry.value[i] # baseP↑[desc.offset][i] THEN EXIT; REPEAT FINISHED => GO TO found; ENDLOOP; ENDCASE; REPEAT found => NULL; FINISHED => BEGIN lLti ← Table.Allocate[ltType, SIZE[long LTRecord] + desc.length]; ltb[lLti] ← LTRecord[ link: hashVec[hvi], datum: long[codeIndex: 0, length: desc.length, value: ]]; FOR i IN [0 .. desc.length) DO ltb[lLti].value[i] ← baseP↑[desc.offset][i] ENDLOOP; hashVec[hvi] ← lti ← lLti; END; ENDLOOP; RETURN END; Value: PROCEDURE [lti: LTIndex] RETURNS [WORD] = BEGIN WITH entry: ltb[lti] SELECT FROM short => RETURN [entry.value]; long => IF entry.length = 1 THEN RETURN [entry.value[0]]; ENDCASE; ERROR END; FindDescriptor: PROCEDURE [desc: DESCRIPTOR FOR ARRAY OF WORD] RETURNS [LTIndex] = BEGIN base: Table.Base ← LOOPHOLE[0]; RETURN [IF LENGTH[desc] = 1 THEN Find[desc[0]] ELSE FindMultiWord[@base, [offset:LOOPHOLE[BASE[desc]], length:LENGTH[desc]]]] END; DescriptorValue: PROCEDURE [lti: LTIndex] RETURNS [desc: LitDescriptor] = BEGIN WITH entry: ltb[lti] SELECT FROM short => desc ← [offset: LOOPHOLE[@entry.value-LOOPHOLE[ltb,CARDINAL]], length: 1]; long => desc ← [offset: LOOPHOLE[@entry.value-LOOPHOLE[ltb,CARDINAL]], length: entry.length]; ENDCASE => ERROR; RETURN END; CopyLiteral: PROCEDURE [literal: LTId] RETURNS [lti: LTIndex] = BEGIN desc: LitDescriptor; WITH entry: literal.baseP↑[literal.index] SELECT FROM short => lti ← Find[entry.value]; long => BEGIN desc ← [ offset: LOOPHOLE[@entry.value-LOOPHOLE[literal.baseP↑,CARDINAL]], length: entry.length]; lti ← FindMultiWord[literal.baseP, desc]; END; ENDCASE => ERROR END; ForgetEntries: PROCEDURE RETURNS [currentSize: CARDINAL] = BEGIN hvi: LitHVIndex; FOR hvi IN LitHVIndex DO hashVec[hvi] ← LTNull ENDLOOP; RETURN [Table.Bounds[ltType].size] END; -- string literal table management MSTNull: PRIVATE MSTIndex = LOOPHOLE[STNull]; SLitHVLength: PRIVATE INTEGER = 23; SLitHVIndex: PRIVATE TYPE = [0..SLitHVLength); sHashVec: PRIVATE ARRAY SLitHVIndex OF MSTIndex; stLimit, localStart: STIndex; locals: BOOLEAN; markBit: BOOLEAN; FindString: PROCEDURE [s: StringDefs.SubString] RETURNS [STIndex] = BEGIN CpW: CARDINAL = AltoDefs.CharsPerWord; hash: WORD; hvi: SLitHVIndex; i, nw: CARDINAL; sti: MSTIndex; v: STRING; desc: StringDefs.SubStringDescriptor; hash ← 0; FOR i IN [s.offset .. s.offset+s.length) DO hash ← hash + LOOPHOLE[s.base[i], CARDINAL] ENDLOOP; hvi ← hash MOD SLitHVLength; FOR sti ← sHashVec[hvi], stb[sti].link UNTIL sti = MSTNull DO v ← StringValue[sti]; desc ← [base:v, offset:0, length:v.length]; IF StringDefs.EqualSubStrings[s, @desc] THEN EXIT; REPEAT FINISHED => BEGIN nw ← StringDefs.WordsForString[s.length]; sti ← Table.Allocate[stType, SizeSTPrefix + nw]; stb[sti] ← STRecord[master[ info: 0, codeIndex: 0, local: FALSE, link: sHashVec[hvi], string: [ length: 0, maxlength: ((s.length + (CpW-1))/CpW) * CpW, text: ]]]; StringDefs.AppendSubString[@stb[sti].string, s]; FOR i IN [s.length .. stb[sti].string.maxlength) DO StringDefs.AppendChar[@stb[sti].string, 0C] ENDLOOP; stb[sti].string.length ← s.length; stLimit ← stLimit + (SizeSTPrefix + nw); sHashVec[hvi] ← sti; END; ENDLOOP; RETURN [sti] END; MasterString: PROCEDURE [sti: STIndex] RETURNS [MSTIndex] = BEGIN RETURN [WITH s: stb[sti] SELECT FROM master => LOOPHOLE[sti], copy => s.link, ENDCASE => MSTNull] END; StringReference: PROCEDURE [sti: STIndex] = BEGIN WITH s: stb[sti] SELECT FROM master => s.info ← s.info + 1; ENDCASE => NULL; RETURN END; StringValue: PROCEDURE [sti: STIndex] RETURNS [STRING] = BEGIN RETURN[@stb[MasterString[sti]].string] END; ResetLocalStrings: PROCEDURE RETURNS [key: STIndex] = BEGIN IF ~locals THEN key ← STNull ELSE BEGIN key ← localStart; markBit ← ~markBit END; locals ← FALSE; localStart ← LOOPHOLE[Table.Bounds[stType].size]; RETURN END; FindLocalString: PROCEDURE [key: STIndex] RETURNS [sti: STIndex] = BEGIN next: STIndex; master: MSTIndex = MasterString[key]; FOR sti ← localStart, next UNTIL sti = stLimit DO WITH s: stb[sti] SELECT FROM master => next ← sti + SizeSTPrefix + StringDefs.WordsForString[s.string.maxlength]; copy => BEGIN IF s.link = master THEN EXIT; next ← sti + SIZE[copy STRecord]; END; ENDCASE; REPEAT FINISHED => BEGIN sti ← Table.Allocate[stType, SIZE[copy STRecord]]; stb[sti] ← STRecord[copy[mark: markBit, link: master]]; stLimit ← stLimit + SIZE[copy STRecord]; locals ← TRUE; END; ENDLOOP; RETURN END; EnumerateLocalStrings: PROCEDURE [key: STIndex, proc: PROCEDURE [MSTIndex]] = BEGIN sti, next: STIndex; started, mark: BOOLEAN; IF key = STNull THEN RETURN; started ← FALSE; FOR sti ← key, next UNTIL sti = stLimit DO WITH s: stb[sti] SELECT FROM master => next ← sti + SizeSTPrefix + StringDefs.WordsForString[s.string.maxlength]; copy => BEGIN IF ~started THEN BEGIN mark ← s.mark; started ← TRUE END; IF s.mark # mark THEN EXIT; proc[s.link]; next ← sti + SIZE[copy STRecord]; END; ENDCASE => ERROR; ENDLOOP; END; EnumerateMasterStrings: PROCEDURE [proc: PROCEDURE [MSTIndex]] = BEGIN sti, next: STIndex; FOR sti ← FIRST[STIndex], next UNTIL sti = stLimit DO WITH s: stb[sti] SELECT FROM master => BEGIN proc[LOOPHOLE[sti]]; next ← sti + SizeSTPrefix + StringDefs.WordsForString[s.string.maxlength]; END; copy => next ← sti + SIZE[copy STRecord]; ENDCASE => ERROR; ENDLOOP; RETURN END; END.