<> <> <> <> DIRECTORY ConvertUnsafe: TYPE USING [LS, SubString, EqualSubStrings], PrincOpsUtils: TYPE USING [BITAND, BITXOR], FS: TYPE USING [OpenFile, Read], SymbolOperations: TYPE, Symbols: TYPE, SymbolSegment: TYPE, TimeStamp: TYPE USING [Stamp], Tree: TYPE USING [Link, Null], VM: TYPE USING [Interval, nullInterval, wordsPerPage, AddressForPageNumber, Allocate, Free, MakeReadOnly]; SymbolOperationsImpl: MONITOR IMPORTS PrincOpsUtils, ConvertUnsafe, FS, VM EXPORTS SymbolOperations = BEGIN Base: TYPE = Symbols.Base; BitAddress: TYPE = Symbols.BitAddress; BitCount: TYPE = Symbols.BitCount; BTIndex: TYPE = Symbols.BTIndex; BTNull: BTIndex = Symbols.BTNull; CSEIndex: TYPE = Symbols.CSEIndex; CSENull: CSEIndex = Symbols.CSENull; typeANY: CSEIndex = Symbols.typeANY; typeTYPE: CSEIndex = Symbols.typeTYPE; CTXIndex: TYPE = Symbols.CTXIndex; CTXNull: CTXIndex = Symbols.CTXNull; ExtIndex: TYPE = SymbolSegment.ExtIndex; ExtNull: ExtIndex = SymbolSegment.ExtNull; ExtensionType: TYPE = Symbols.ExtensionType; FGHeader: TYPE = SymbolSegment.FGHeader; FGHeaderPtr: TYPE = LONG POINTER TO FGHeader; FGTEntry: TYPE = SymbolSegment.FGTEntry; FieldBitCount: TYPE = Symbols.FieldBitCount; ISEIndex: TYPE = Symbols.ISEIndex; ISENull: ISEIndex = Symbols.ISENull; HashVector: TYPE = Symbols.HashVector; HTRecord: TYPE = Symbols.HTRecord; HVIndex: TYPE = Symbols.HVIndex; Linkage: TYPE = Symbols.Linkage; LongString: TYPE = ConvertUnsafe.LS; MDIndex: TYPE = Symbols.MDIndex; MDNull: MDIndex = Symbols.MDNull; MDRecord: TYPE = Symbols.MDRecord; Name: TYPE = Symbols.Name; nullName: Name = Symbols.nullName; PackedBitCount: TYPE = Symbols.PackedBitCount; RecordSEIndex: TYPE = Symbols.RecordSEIndex; RecordSENull: RecordSEIndex = Symbols.RecordSENull; RefClass: TYPE = Symbols.RefClass; SEIndex: TYPE = Symbols.SEIndex; SENull: SEIndex = Symbols.SENull; SERecord: TYPE = Symbols.SERecord; STHeader: TYPE = SymbolSegment.STHeader; STHeaderPtr: TYPE = LONG POINTER TO STHeader; SubString: TYPE = ConvertUnsafe.SubString; TransferMode: TYPE = Symbols.TransferMode; Type: TYPE = Symbols.Type; nullType: Type = Symbols.nullType; TypeClass: TYPE = Symbols.TypeClass; WordCount: TYPE = Symbols.WordCount; WordLength: NAT = Symbols.WordLength; wordsPerPage: NAT = VM.wordsPerPage; wordFill: CARDINAL = WordLength-1; SymbolTableBase: TYPE = SymbolOperations.SymbolTableBase; SymbolTableBaseRep: TYPE = SymbolOperations.SymbolTableBaseRep; Acquire: PUBLIC PROC[file: FS.OpenFile, startPage: CARDINAL, pages: CARDINAL] RETURNS[stb: SymbolTableBase _ NIL] = { interval: VM.Interval = VM.Allocate[count: pages]; b: LONG POINTER = VM.AddressForPageNumber[interval.page]; tB: SymbolSegment.Base = LOOPHOLE[b]; p: STHeaderPtr = b; q: FGHeaderPtr; file.Read[startPage, pages, b]; -- read the contents interval.MakeReadOnly[]; -- don't want anyone messing with our tables stb _ NEW[SymbolTableBaseRep]; stb.file _ file; stb.interval _ interval; stb.hashVec _ b+p.hvBlock.offset; stb.ht _ DESCRIPTOR[b+p.htBlock.offset, p.htBlock.size/SIZE[Symbols.HTRecord]]; stb.ssb _ b + p.ssBlock.offset; stb.seb _ tB + p.seBlock.offset; stb.ctxb _ tB + p.ctxBlock.offset; stb.mdb _ tB + p.mdBlock.offset; stb.bb _ tB + p.bodyBlock.offset; stb.tb _ tB + p.treeBlock.offset; stb.ltb _ tB + p.litBlock.offset; stb.extb _ tB + p.extBlock.offset; stb.mdLimit _ FIRST[Symbols.MDIndex] + p.mdBlock.size; stb.extLimit _ FIRST[SymbolSegment.ExtIndex] + p.extBlock.size; stb.mainCtx _ p.outerCtx; stb.stHandle _ p; IF p.fgRelPgBase = 0 OR pages <= p.fgRelPgBase THEN { <> stb.sourceFile _ NIL; stb.fgTable _ NIL} ELSE { <> q _ b + p.fgRelPgBase*wordsPerPage; stb.sourceFile _ LOOPHOLE[@q.sourceFile]; stb.fgTable _ DESCRIPTOR[ LOOPHOLE[stb.sourceFile, LONG POINTER TO ARRAY OF FGTEntry], q.length]; }; }; Release: PUBLIC PROC[stb: SymbolTableBase] = { interval: VM.Interval = stb.interval; IF interval # VM.nullInterval THEN { VM.Free[interval]; stb^ _ []; -- ground state }; }; <> <<>> FindString: PUBLIC PROC[stb: SymbolTableBase, s: SubString] RETURNS[name: Name] = { ss: SubString; name _ stb.hashVec[HashValue[stb, s]]; WHILE name # nullName DO ss _ SubStringForName[stb, name]; IF s.EqualSubStrings[ss] THEN EXIT; name _ stb.ht[name].link; ENDLOOP; }; HashValue: PUBLIC PROC[stb: SymbolTableBase, s: SubString] RETURNS[HVIndex] = { CharBits: PROC[CHAR, WORD] RETURNS[WORD] = LOOPHOLE[PrincOpsUtils.BITAND]; Mask: WORD = 337b; -- masks out ASCII case shifts v: WORD = CharBits[s.base[s.offset], Mask]*177b + CharBits[s.base[s.offset+(s.length-1)], Mask]; RETURN[PrincOpsUtils.BITXOR[v, s.length*17b] MOD stb.hashVec^.LENGTH]}; SubStringForName: PUBLIC PROC[stb: SymbolTableBase, name: Name] RETURNS[s: SubString] = { s.base _ stb.ssb; IF name = nullName THEN s.offset _ s.length _ 0 ELSE s.length _ stb.ht[name].ssIndex - (s.offset _ stb.ht[name-1].ssIndex)}; <<>> <> <<>> CtxEntries: PUBLIC PROC[stb: SymbolTableBase, ctx: CTXIndex] RETURNS[n: CARDINAL_0] = { IF ctx = CTXNull THEN RETURN; WITH c: stb.ctxb[ctx] SELECT FROM included => IF ~c.reset THEN RETURN; ENDCASE; FOR sei: ISEIndex _ FirstCtxSe[stb, ctx], NextSe[stb, sei] UNTIL sei = ISENull DO n _ n+1; ENDLOOP; }; FirstCtxSe: PUBLIC PROC[stb: SymbolTableBase, ctx: CTXIndex] RETURNS[ISEIndex] = { RETURN[IF ctx = CTXNull THEN ISENull ELSE stb.ctxb[ctx].seList]}; NextSe: PUBLIC PROC[stb: SymbolTableBase, sei: ISEIndex] RETURNS[ISEIndex _ ISENull] = { IF sei # ISENull THEN { WITH id: stb.seb[sei] SELECT FROM sequential => RETURN[sei + SERecord.id.sequential.SIZE]; linked => RETURN[id.link]; ENDCASE; }; }; SearchContext: PUBLIC PROC[stb: SymbolTableBase, name: Name, ctx: CTXIndex] RETURNS[ISEIndex _ ISENull] = { sei, root: ISEIndex; IF ctx # CTXNull AND name # nullName THEN { sei _ root _ stb.ctxb[ctx].seList; DO IF sei = ISENull THEN EXIT; IF stb.seb[sei].hash = name THEN RETURN[sei]; WITH id: stb.seb[sei] SELECT FROM sequential => sei _ sei + SERecord.id.sequential.SIZE; linked => IF (sei _ id.link) = root THEN EXIT; ENDCASE => EXIT; ENDLOOP; }; }; SeiForValue: PUBLIC PROC[stb: SymbolTableBase, value: CARDINAL, ctx: CTXIndex] RETURNS[ISEIndex _ ISENull] = { FOR sei: ISEIndex _ FirstCtxSe[stb, ctx], NextSe[stb, sei] UNTIL sei = ISENull DO IF stb.seb[sei].idValue = value THEN RETURN[sei] ENDLOOP; }; <<>> <> <<>> FindMdi: PUBLIC PROC[stb: SymbolTableBase, stamp: TimeStamp.Stamp] RETURNS[MDIndex _ MDNull] = { FOR mdi: MDIndex _ MDIndex.FIRST, mdi + MDRecord.SIZE UNTIL mdi = stb.mdLimit DO IF stb.mdb[mdi].stamp = stamp THEN RETURN[mdi] ENDLOOP; }; <<>> <> <<>> ArgCtx: PUBLIC PROC[stb: SymbolTableBase, type: CSEIndex] RETURNS[CTXIndex] = { sei: RecordSEIndex = ArgRecord[stb, type]; RETURN[IF sei = RecordSENull THEN CTXNull ELSE stb.seb[sei].fieldCtx]}; ArgRecord: PUBLIC PROC[stb: SymbolTableBase, type: CSEIndex] RETURNS[RecordSEIndex _ RecordSENull] = { IF type # nullType THEN { WITH stb.seb[type] SELECT FROM record => RETURN[LOOPHOLE[type, RecordSEIndex]]; ENDCASE; }; }; ClusterSe: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[Type] = { WITH t: stb.seb[type] SELECT FROM id => { next: Type = t.idInfo; IF NOT t.extended THEN WITH u: stb.seb[next] SELECT FROM id => IF t.hash = u.hash THEN RETURN[ClusterSe[stb, next]]; ENDCASE; }; ENDCASE; RETURN[type]}; NormalType: PUBLIC PROC[stb: SymbolTableBase, type: CSEIndex] RETURNS[nType: CSEIndex] = { WITH t: stb.seb[type] SELECT FROM subrange => nType _ NormalType[stb, UnderType[stb, t.rangeType]]; long, real => nType _ NormalType[stb, UnderType[stb, t.rangeType]]; ENDCASE => nType _ type; }; RecordLink: PUBLIC PROC[stb: SymbolTableBase, type: RecordSEIndex] RETURNS[RecordSEIndex _ RecordSENull] = { WITH t: stb.seb[type] SELECT FROM linked => RETURN[LOOPHOLE[UnderType[stb, t.linkType], RecordSEIndex]]; ENDCASE; }; RecordRoot: PUBLIC PROC[stb: SymbolTableBase, type: RecordSEIndex] RETURNS[root: RecordSEIndex] = { root _ type; FOR next: RecordSEIndex _ RecordLink[stb, root], RecordLink[stb, next] WHILE next # RecordSENull DO root _ next ENDLOOP; }; ReferentType: PUBLIC PROC[stb: SymbolTableBase, type: CSEIndex] RETURNS[CSEIndex _ typeANY] = { sei: CSEIndex = NormalType[stb, type]; WITH t: stb.seb[sei] SELECT FROM ref => RETURN[UnderType[stb, t.refType]]; ENDCASE; }; TransferTypes: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[typeIn, typeOut: RecordSEIndex _ RecordSENull] = { sei: CSEIndex = UnderType[stb, type]; WITH t: stb.seb[sei] SELECT FROM transfer => { typeIn _ ArgRecord[stb, t.typeIn]; typeOut _ ArgRecord[stb, t.typeOut]; }; ENDCASE; }; TypeForm: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[TypeClass _ nil] = { IF type # nullType THEN RETURN[stb.seb[UnderType[stb, type]].typeTag]; }; TypeLink: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[Type _ nullType] = { sei: CSEIndex = UnderType[stb, type]; WITH se: stb.seb[sei] SELECT FROM record => WITH se SELECT FROM linked => RETURN[linkType]; ENDCASE; ENDCASE; }; TypeRoot: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[root: Type] = { root _ type; FOR next: Type _ TypeLink[stb, root], TypeLink[stb, next] WHILE next # nullType DO root _ next; ENDLOOP; }; UnderType: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[CSEIndex] = { sei: Type _ type; WHILE sei # nullType DO WITH se: stb.seb[sei] SELECT FROM id => {IF se.idType # typeTYPE THEN ERROR; sei _ se.idInfo}; ENDCASE => EXIT; ENDLOOP; RETURN[LOOPHOLE[sei, CSEIndex]]}; XferMode: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[TransferMode _ none] = { sei: CSEIndex = UnderType[stb, type]; WITH t: stb.seb[sei] SELECT FROM transfer => RETURN[t.mode]; ENDCASE; }; <<>> <> Untruncate: PRIVATE PROC[n: CARDINAL] RETURNS[LONG CARDINAL] = { IF n # 0 THEN RETURN[n]; RETURN[CARDINAL.LAST.LONG+1]}; BitsForRange: PUBLIC PROC[stb: SymbolTableBase, maxValue: CARDINAL] RETURNS[nBits: CARDINAL _ 1] = { fieldMax: CARDINAL _ 1; WHILE nBits < WordLength AND fieldMax < maxValue DO nBits _ nBits + 1; fieldMax _ 2*fieldMax + 1; ENDLOOP; }; BitsForType: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[BitCount _ 0] = { sei: CSEIndex = UnderType[stb, type]; IF sei # CSENull THEN { n: BitCount _ 0; WITH t: stb.seb[sei] SELECT FROM basic => n _ t.length; enumerated => IF NOT t.empty THEN RETURN[BitsForRange[stb, Cardinality[stb, sei]-1]]; record => n _ t.length; array => { n _ BitsPerElement[stb, t.componentType, t.packed]*Cardinality[stb, t.indexType]; IF n > WordLength THEN n _ ((n + wordFill)/WordLength)*WordLength}; opaque => n _ t.length; relative => n _ BitsForType[stb, t.offsetType]; subrange => IF NOT t.empty THEN n _ BitsForRange[stb, Cardinality[stb, sei]-1]; ENDCASE => n _ WordsForType[stb, sei]*WordLength; RETURN[n]}; }; PackedSize: ARRAY PackedBitCount OF CARDINAL = [1, 2, 4, 4, 8, 8, 8, 8]; BitsPerElement: PUBLIC PROC[stb: SymbolTableBase, type: Type, packed: BOOL] RETURNS[BitCount] = { nBits: BitCount = BitsForType[stb, type]; RETURN[ IF packed AND (nBits#0 AND nBits<=PackedBitCount.LAST) -- IN PackedBitCount THEN PackedSize[PackedBitCount[nBits]] ELSE (nBits+wordFill)/WordLength * WordLength ]; }; Cardinality: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[LONG CARDINAL _ 0] = { sei: CSEIndex = UnderType[stb, type]; WITH t: stb.seb[sei] SELECT FROM enumerated => <> IF NOT t.empty THEN RETURN[Untruncate[t.nValues]]; subrange => IF NOT t.empty THEN RETURN[t.range.LONG+1]; basic => IF t.code = Symbols.codeCHAR THEN RETURN[256]; relative => RETURN[Cardinality[stb, t.offsetType]]; ENDCASE; }; FindExtension: PUBLIC PROC[stb: SymbolTableBase, sei: ISEIndex] RETURNS[type: ExtensionType, tree: Tree.Link] = { FOR exti: SymbolSegment.ExtIndex _ SymbolSegment.ExtIndex.FIRST, exti + SymbolSegment.ExtRecord.SIZE UNTIL exti = stb.extLimit DO IF stb.extb[exti].sei = sei THEN RETURN[stb.extb[exti].type, stb.extb[exti].tree]; ENDLOOP; RETURN[$none, Tree.Null]}; FnField: PUBLIC PROC[stb: SymbolTableBase, field: ISEIndex] RETURNS[offset: BitAddress, size: FieldBitCount] = { word, nW: CARDINAL; word _ 0; FOR sei: ISEIndex _ FirstCtxSe[stb, stb.seb[field].idCtx], NextSe[stb, sei] DO nW _ CARDINAL[WordsForType[stb, stb.seb[sei].idType]]; IF sei = field THEN EXIT; word _ word + nW; ENDLOOP; RETURN[offset: BitAddress[wd: word, bd: 0], size: nW * WordLength]}; NameForSe: PUBLIC PROC[stb: SymbolTableBase, sei: ISEIndex] RETURNS[Name _ nullName] = { IF sei # ISENull THEN RETURN[stb.seb[sei].hash]}; LinkMode: PUBLIC PROC[stb: SymbolTableBase, sei: ISEIndex] RETURNS[Linkage] = { IF stb.seb[sei].idType = typeTYPE THEN RETURN[IF TypeForm[stb, stb.seb[sei].idInfo] = opaque THEN $type ELSE $manifest] ELSE SELECT XferMode[stb, stb.seb[sei].idType] FROM proc, program => RETURN[IF stb.seb[sei].constant AND NOT stb.seb[sei].extended THEN $manifest ELSE $val]; signal, error => RETURN[IF stb.seb[sei].constant THEN $manifest ELSE $val]; ENDCASE => RETURN[IF stb.seb[sei].constant THEN $manifest ELSE $ref]; }; RecField: PUBLIC PROC[stb: SymbolTableBase, field: ISEIndex] RETURNS[offset: BitAddress, size: FieldBitCount] = { RETURN[offset: stb.seb[field].idValue, size: stb.seb[field].idInfo]}; RCType: PUBLIC PROC[stb: SymbolTableBase, type: CSEIndex] RETURNS[RefClass] = { next: Type; struc: RefClass _ simple; FOR sei: CSEIndex _ type, UnderType[stb, next] DO WITH t: stb.seb[sei] SELECT FROM record => SELECT TRUE FROM ~t.hints.refField => RETURN[$none]; t.hints.unifield => next _ stb.seb[stb.ctxb[t.fieldCtx].seList].idType; ENDCASE => RETURN[$composite]; ref => RETURN[IF t.counted THEN struc ELSE $none]; array => {struc _ $composite; next _ t.componentType}; relative => next _ t.offsetType; subrange => next _ t.rangeType; long => next _ t.rangeType; union => RETURN[IF t.hints.refField THEN $composite ELSE $none]; sequence => {struc _ $composite; next _ t.componentType}; zone => RETURN[IF t.counted THEN struc ELSE $none]; ENDCASE => RETURN[$none]; ENDLOOP; }; VariantField: PUBLIC PROC[stb: SymbolTableBase, type: CSEIndex] RETURNS[sei: ISEIndex _ ISENull] = { WITH t: stb.seb[type] SELECT FROM record => FOR sei _ FirstCtxSe[stb, t.fieldCtx], NextSe[stb, sei] UNTIL sei = ISENull DO SELECT TypeForm[stb, stb.seb[sei].idType] FROM sequence, union => EXIT; ENDCASE; ENDLOOP; ENDCASE; }; WordsForType: PUBLIC PROC[stb: SymbolTableBase, type: Type] RETURNS[wc: WordCount _ 0] = { sei: CSEIndex = UnderType[stb, type]; IF sei # CSENull THEN { itemsPerWord: ARRAY PackedBitCount OF [0..16] = [16, 8, 4, 4, 2, 2, 2, 2]; WITH t: stb.seb[sei] SELECT FROM mode => wc _ 1; -- fudge for compiler (Pass4.Binding) basic => wc _ (t.length + wordFill)/WordLength; enumerated => IF NOT t.empty THEN wc _ 1; record => wc _ (t.length.LONG + wordFill)/WordLength; ref => wc _ 1; array => { cc: WordCount = Cardinality[stb, t.indexType]; b: BitCount = BitsPerElement[stb, t.componentType, t.packed]; IF b # 0 AND b <= PackedBitCount.LAST THEN <> wc _ (cc + (itemsPerWord[b]-1))/itemsPerWord[b] ELSE wc _ cc * ((b+wordFill)/WordLength)}; arraydesc => wc _ 2; transfer => wc _ (IF t.mode = port THEN 2 ELSE 1); relative => wc _ WordsForType[stb, t.offsetType]; opaque => wc _ (t.length.LONG + wordFill)/WordLength; zone => wc _ (IF t.mds THEN 1 ELSE 2); subrange => IF NOT t.empty THEN wc _ 1; long => wc _ WordsForType[stb, t.rangeType] + 1; real => wc _ 2; ENDCASE; }; }; <<>> <> ParentBti: PUBLIC PROC[stb: SymbolTableBase, bti: BTIndex] RETURNS[BTIndex] = { UNTIL stb.bb[bti].link.which = parent DO bti _ stb.bb[bti].link.index; ENDLOOP; RETURN[stb.bb[bti].link.index]}; SiblingBti: PUBLIC PROC[stb: SymbolTableBase, bti: BTIndex] RETURNS[BTIndex] = { RETURN[IF stb.bb[bti].link.which = sibling THEN stb.bb[bti].link.index ELSE BTNull]}; SonBti: PUBLIC PROC[stb: SymbolTableBase, bti: BTIndex] RETURNS[BTIndex] = { RETURN[stb.bb[bti].firstSon]}; EnumerateBodies: PUBLIC PROC[ stb: SymbolTableBase, root: BTIndex, proc: PROC[BTIndex] RETURNS[stop: BOOL]] RETURNS[bti: BTIndex] = { prev: BTIndex; bti _ root; UNTIL bti = BTNull DO IF proc[bti] THEN GO TO Stopped; IF stb.bb[bti].firstSon # BTNull THEN bti _ stb.bb[bti].firstSon ELSE DO IF bti = root THEN GO TO Done; prev _ bti; bti _ stb.bb[bti].link.index; IF stb.bb[prev].link.which # parent THEN EXIT; ENDLOOP; REPEAT Stopped => NULL; Done => bti _ BTNull; ENDLOOP; }; END.