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. pSymbolOperationsImpl.mesa Russ Atkinson, October 19, 1983 10:24 am Satterthwaite March 21, 1986 10:24:33 am PST This file has been shamelessly ripped off from SymbolPack.mesa of September 22, 1983 10:58 am. It is meant as an eventual replacement, which would permit symbol tables to exist without the use of global frames or excessive MDS (hooray!). There is NO provision for table movement! No fine-grain table There is a fine-grain table hash manipulation context management module management type manipulation information returning procedures compatibility hack b IN PackedBitCount body table management ΚΫ˜šœ™J™(Icode™,—J˜Jšœ™™™J˜šΟk ˜ Jšœœœœ˜;Jš œœœœœ˜+Jšœœœ˜ Jšœœ˜Jšœ œ˜Jšœœ˜Jšœ œœ ˜Jšœœœ˜Jšœœœ\˜j—J˜šœ˜Jšœœ˜,Jšœ˜Jšœ˜—˜Jšœœ˜Jšœ œ˜&Jšœ œ˜"šœ œ˜ Jšœ!˜!—šœ œ˜"Jšœ$˜$Jšœ$˜$Jšœ&˜&—šœ œ˜"Jšœ$˜$—šœ œ˜(Jšœ*˜*—Jšœœ˜,Jšœ œ˜(Jš œ œœœœ ˜-Jšœ œ˜(Jšœœ˜,šœ œ˜"Jšœ$˜$—Jšœ œ˜&Jšœ œ˜"Jšœ œ˜ Jšœ œ˜ Jšœ œœ˜$šœ œ˜ Jšœ!˜!—Jšœ œ˜"šœœ˜Jšœ"˜"—Jšœœ˜.šœœ˜,Jšœ3˜3—Jšœ œ˜"šœ œ˜ Jšœ!˜!—Jšœ œ˜"Jšœ œ˜(Jš œ œœœœ ˜-Jšœ œ˜*Jšœœ˜*šœœ˜Jšœ"˜"—Jšœ œ˜$Jšœ œ˜$J˜Jšœ œ˜%Jšœœœ˜$Jšœ œ˜"J˜Jšœœ$˜9•PostFix32 sp tabStops•postfix32 sp tabStops•postFix32 sp tabStopsšœœ'˜?J–32 sp tabStops–32 sp tabStops–32 sp tabStops˜—š Οnœœœœœ œ˜MJšœœœ˜)Jšœ œ œ˜2Jšœœœœ%˜9Jšœœ˜%Jšœ˜Jšœ˜Jšœ!Οc˜5JšœŸ,˜FJšœœ˜Jšœ˜J˜J˜!Jšœ  œ$œ˜OJ˜J˜ J˜"J˜ J˜!J˜!J˜!J˜"Jšœœ#˜6Jšœœ+˜?J˜J˜šœœœ˜5Jšœ™Jšœœ˜Jšœœ˜—šœ˜Jšœ™J˜#Jšœœ˜)šœ œ˜Jš œœœœœœ ˜˜DJ˜—šž œœœ%˜;Jšœœ˜Jšœœœ˜1J˜—šžœœœ&œ ˜Ošœ ˜&Jšœœ-œœ ˜P—š˜šœ$˜.˜šœœœœ˜=Jšœ ˜Jšœ˜ ——šœ˜Jšœœœ œ˜:—šœ˜ Jšœœœ œ˜:———Jšœ˜J˜—šžœœœ'˜