DIRECTORY Basics, BitOps, Convert, CoreClasses, CoreFlat, CoreOps, CoreProperties, IO, RefTab, Rope; CoreFlatImpl: CEDAR PROGRAM IMPORTS Basics, BitOps, Convert, CoreClasses, CoreOps, CoreProperties, IO, RefTab, Rope EXPORTS CoreFlat = BEGIN OPEN CoreFlat; PathError: PUBLIC ERROR [msg: ROPE _ NIL] = CODE; MakeError: PROC [m: ROPE _ NIL] = { IF m=NIL THEN m _ "parse failed"; ERROR PathError[m]; }; cutLabelProp: ATOM _ CoreProperties.RegisterProperty[$CoreCutLabel]; CellInstanceCutLabels: PUBLIC PROC [on: CellInstance, l1, l2, l3, l4, l5, l6: ROPE _ NIL] RETURNS [same: CellInstance] = { same _ CellInstanceCutLabelList[on, LabelList[l1, l2, l3, l4, l5, l6]] }; CellInstanceCutLabelList: PUBLIC PROC [on: CellInstance, labels: LIST OF ROPE] RETURNS [same: CellInstance] = { lbls: LIST OF ROPE _ NARROW[CoreProperties.GetCellInstanceProp[on, cutLabelProp]]; lbls _ CombineLabelLists[lbls, labels]; CoreProperties.PutCellInstanceProp[on, cutLabelProp, lbls]; same _ on; }; CellTypeCutLabels: PUBLIC PROC [on: CellType, l1, l2, l3, l4, l5, l6: ROPE _ NIL] RETURNS [same: CellType] = { same _ CellTypeCutLabelList[on, LabelList[l1, l2, l3, l4, l5, l6]] }; CellTypeCutLabelList: PUBLIC PROC [on: CellType, labels: LIST OF ROPE] RETURNS [same: CellType] = { lbls: LIST OF ROPE _ NARROW[CoreProperties.GetCellTypeProp[on, cutLabelProp]]; lbls _ CombineLabelLists[lbls, labels]; CoreProperties.PutCellTypeProp[on, cutLabelProp, lbls]; same _ on; }; CellClassCutLabels: PUBLIC PROC [on: CellClass, l1, l2, l3, l4, l5, l6: ROPE _ NIL] RETURNS [same: CellClass] = { same _ CellClassCutLabelList[on, LabelList[l1, l2, l3, l4, l5, l6]] }; CellClassCutLabelList: PUBLIC PROC [on: CellClass, labels: LIST OF ROPE] RETURNS [same: CellClass] = { lbls: LIST OF ROPE _ NARROW[CoreProperties.GetCellClassProp[on, cutLabelProp]]; lbls _ CombineLabelLists[lbls, labels]; CoreProperties.PutCellClassProp[on, cutLabelProp, lbls]; same _ on; }; CreateCutSet: PUBLIC PROC [instances, cellTypes, cellClasses, labels: LIST OF ROPE _ NIL, flatCells: FlatCellTypes _ NIL, flatten: FlatCellTypes _ NIL, change: FlatCellTypeCutSets _ NIL] RETURNS [cutSet: CutSet] = { cutSet _ NEW[CutSetRec _ [ instances: instances, cellTypes: cellTypes, cellClasses: cellClasses, labels: labels, flatCells: flatCells, flatten: flatten, change: change]]; }; CutSetMember: PUBLIC PROC [root: CellType, flatCell: FlatCellTypeRec, cutSet: CutSet] RETURNS [member: BOOL _ FALSE] = { parent: CellType; instance: CellInstance; cellType: CellType; [parent, instance, cellType] _ ResolveFlatCellType[root, flatCell]; member _ CutSetMemberResolved[flatCell, instance, cellType, cutSet] }; CutSetMemberResolved: PUBLIC PROC [flatCell: FlatCellTypeRec, instance: CellInstance, cellType: CellType, cutSet: CutSet] RETURNS [member: BOOL _ FALSE] = { name: ROPE _ NIL; IF cellType.class=CoreClasses.transistorCellClass OR cellType.class=CoreClasses.unspecifiedCellClass THEN RETURN[TRUE]; IF cutSet=NIL THEN RETURN[FALSE]; FOR cl: FlatCellTypeCutSets _ cutSet.change, cl.rest UNTIL cl=NIL DO IF flatCell.path.length >= cl.first.flatCell.path.length THEN { FOR i: InstancePathIndex IN [0..cl.first.flatCell.path.length) DO IF flatCell.path.bits[i]#cl.first.flatCell.path.bits[i] THEN EXIT; REPEAT FINISHED => RETURN[CutSetMemberResolved[flatCell, instance, cellType, cl.first.cutSet]]; ENDLOOP; }; ENDLOOP; FOR flats: FlatCellTypes _ cutSet.flatten, flats.rest UNTIL flats=NIL DO IF FlatCellTypeEqualRec[flats.first^, flatCell] THEN RETURN[FALSE]; ENDLOOP; FOR flats: FlatCellTypes _ cutSet.flatCells, flats.rest UNTIL flats=NIL DO IF FlatCellTypeEqualRec[flats.first^, flatCell] THEN RETURN[TRUE]; ENDLOOP; IF instance#NIL THEN { name _ CoreClasses.GetCellInstanceName[instance]; IF name#NIL THEN IF OneInOther[LIST[name], cutSet.instances] THEN RETURN [TRUE]; }; name _ CoreOps.GetCellTypeName[cellType]; IF name#NIL THEN IF OneInOther[LIST[name], cutSet.cellTypes] THEN RETURN [TRUE]; IF OneInOther[LIST[cellType.class.name], cutSet.cellClasses] THEN RETURN [TRUE]; IF instance#NIL THEN IF OneInOther[NARROW[CoreProperties.GetCellInstanceProp[instance, cutLabelProp]], cutSet.labels] THEN RETURN [TRUE]; IF OneInOther[NARROW[CoreProperties.GetCellTypeProp[cellType, cutLabelProp]], cutSet.labels] THEN RETURN [TRUE]; IF OneInOther[NARROW[CoreProperties.GetCellClassProp[cellType.class, cutLabelProp]], cutSet.labels] THEN RETURN [TRUE]; }; OneInOther: PROC [one, other: LIST OF ROPE] RETURNS [yes: BOOL _ FALSE] = { FOR this: LIST OF ROPE _ one, this.rest UNTIL this=NIL DO FOR that: LIST OF ROPE _ other, that.rest UNTIL that=NIL DO IF Rope.Equal[CoreOps.FixStupidRef[this.first], CoreOps.FixStupidRef[that.first]] THEN RETURN[TRUE]; ENDLOOP; ENDLOOP; }; LabelList: PROC [l1, l2, l3, l4, l5, l6: ROPE _ NIL] RETURNS [labels: LIST OF ROPE _ NIL] = { IF l1#NIL THEN labels _ CONS[l1, labels]; IF l2#NIL THEN labels _ CONS[l2, labels]; IF l3#NIL THEN labels _ CONS[l3, labels]; IF l4#NIL THEN labels _ CONS[l4, labels]; IF l5#NIL THEN labels _ CONS[l5, labels]; IF l6#NIL THEN labels _ CONS[l6, labels]; }; CombineLabelLists: PROC [l1, l2: LIST OF ROPE _ NIL] RETURNS [combined: LIST OF ROPE] = { combined _ l1; FOR lbls: LIST OF ROPE _ l2, lbls.rest UNTIL lbls=NIL DO combined _ CONS[lbls.first, combined]; ENDLOOP; }; BelowCutSet: PUBLIC PROC [root: CellType, flatCell: FlatCellTypeRec, cutSet: CutSet] RETURNS [below: BOOL _ FALSE] = { SearchForCut: UnboundFlatCellProc = { SELECT TRUE FROM FlatCellTypeEqualRec[flatCell, target] => NULL; CutSetMemberResolved[flatCell, instance, cell, cutSet] => below _ TRUE; ENDCASE => NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, SearchForCut]; }; SearchForCut[cell: root, target: flatCell]; }; ParseInstancePath: PUBLIC PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [path: InstancePath] = { instance: CellInstance; within: CellType; token: ROPE; ts: IO.STREAM; firstChar: CHAR; tokenKind: IO.TokenKind; [path, instance, within, token, ts, firstChar, tokenKind] _ ParsePartialInstancePath[root, pathRope, cutSet]; path _ AddInstance[path, instance, within]; CheckNoMore[ts, firstChar, tokenKind]; }; InstancePathRope: PUBLIC PROC [root: CellType, path: InstancePath] RETURNS [pathRope: ROPE _ NIL] = { AppendName: UnboundFlatCellProc = { IF instance#NIL AND cell=instance.type THEN { name: ROPE _ CoreClasses.GetCellInstanceName[instance]; IF name=NIL THEN { cellTypeName: ROPE _ CoreOps.InheritCellTypeName[instance.type]; name _ Convert.RopeFromInt[CoreClasses.InstanceIndex[parent, instance]]; IF cellTypeName#NIL THEN name _ Rope.Cat[name, "(", cellTypeName, ")"]; }; pathRope _ Rope.Cat[pathRope, "/", name]; }; NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, AppendName]; }; AppendName[root, [path, 0]]; }; InstancePathEqual: PUBLIC PROC [one, other: InstancePath] RETURNS [equal: BOOL] = { equal _ one.length=other.length AND one.bits=other.bits; }; InstancePathHash: PUBLIC PROC [path: InstancePath] RETURNS [hash: CARDINAL _ 0] = { bits: BitOps.BitQWord _ BitOps.QuadShift[LOOPHOLE[path.bits], path.length-64]; FOR i: NAT IN [0..4) DO hash _ Basics.BITXOR[hash, bits[i]]; ENDLOOP; }; AddInstance: PUBLIC PROC [currentPath: InstancePath, instance: CoreClasses.CellInstance, parent: CellType] RETURNS [newPath: InstancePath] = { newPath _ currentPath; IF instance#NIL THEN { withinCT: CellType _ CoreOps.ToBasic[parent]; withinRCT: CoreClasses.RecordCellType _ NARROW[withinCT.data]; index: NAT _ CoreClasses.InstanceIndex[withinCT, instance]; IF index=-1 THEN ERROR; -- instance not found in parent CellType newPath _ ExtendPath[currentPath, index, withinRCT]; }; }; ExtendPath: PUBLIC PROC [currentPath: InstancePath, index: NAT, rct: CoreClasses.RecordCellType] RETURNS [newPath: InstancePath] = { pathBits: NAT _ BitOps.NBits[rct.size]; newPath _ currentPath; FOR bit: NAT IN [0..pathBits) DO newPath.bits[newPath.length+bit] _ BitOps.EBFW[index, bit, pathBits]; ENDLOOP; newPath.length _ newPath.length + pathBits; }; BindInstance: PUBLIC PROC [parent: FlatCellTypeRec, actual, public: WireSeq, bindings: Bindings] RETURNS [newBindings: Bindings] = { BindPublicToActual: CoreOps.EachWirePairProc = { bind: FlatWire _ NIL; IF bindings#NIL THEN bind _ NARROW [RefTab.Fetch[x: bindings, key: actualWire].val]; [] _ RefTab.Store[x: newBindings, key: publicWire, val: IF bind=NIL THEN NEW[FlatWireRec _ [flatCell: parent, wire: actualWire]] ELSE bind]; }; newBindings _ RefTab.Create[public.size+1]; IF CoreOps.VisitBindingSeq[actual: actual, public: public, eachWirePair: BindPublicToActual] THEN ERROR; }; RaiseRootOfInstancePath: PUBLIC PROC [by, path: InstancePath] RETURNS [raised: InstancePath] ~ { length: NATURAL ~ NATURAL[path.length] + by.length; raised _ [ length: length, bits: LOOPHOLE[BitOps.QOR[ LOOPHOLE[by.bits], BitOps.QShift[LOOPHOLE[path.bits], -by.length] ]]]; RETURN}; ParseCellTypePath: PUBLIC PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [flatCell: FlatCellTypeRec] = { instance: CellInstance; within: CellType; token: ROPE; ts: IO.STREAM; firstChar: CHAR; tokenKind: IO.TokenKind; thisCell: CellType; [flatCell, instance, within, token, ts, firstChar, tokenKind, thisCell] _ ParsePartialCellTypePath[root, pathRope, cutSet]; flatCell.path _ AddInstance[flatCell.path, instance, within]; CheckNoMore[ts, firstChar, tokenKind]; }; CellTypePathRope: PUBLIC PROC [root: CellType, flatCell: FlatCellTypeRec] RETURNS [pathRope: ROPE] = { pathRope _ InstancePathRope[root, flatCell.path]; IF flatCell.recastCount>0 THEN pathRope _ Rope.Cat[pathRope, "*", Convert.RopeFromInt[flatCell.recastCount]]; }; FlatCellTypeEqual: PUBLIC PROC [key1, key2: REF ANY] RETURNS [equal: BOOL] = { equal _ FlatCellTypeEqualRec[NARROW [key1, FlatCellType]^, NARROW [key2, FlatCellType]^]; }; FlatCellTypeEqualRec: PUBLIC PROC [one, other: FlatCellTypeRec] RETURNS [equal: BOOL] = { equal _ InstancePathEqual[one.path, other.path] AND one.recastCount=other.recastCount; }; FlatCellTypeHash: PUBLIC PROC [flatCell: REF ANY] RETURNS [hash: CARDINAL] = { hash _ FlatCellTypeHashRec[NARROW[flatCell, FlatCellType]^]; }; FlatCellTypeHashRec: PUBLIC PROC [flatCell: FlatCellTypeRec] RETURNS [hash: CARDINAL] = { hash _ InstancePathHash[flatCell.path]; hash _ Basics.BITXOR[hash, flatCell.recastCount]; }; ResolveFlatCellType: PUBLIC PROC [root: CellType, flatCell: FlatCellTypeRec] RETURNS [parent: CellType, instance: CellInstance, cellType: CellType] = { Search: UnboundFlatCellProc = { upParent _ parent; upInstance _ instance; upCellType _ cell; NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, Search] }; upParent: CellType _ NIL; upInstance: CellInstance _ NIL; upCellType: CellType _ NIL; Search[cell: root, target: flatCell]; parent _ upParent; instance _ upInstance; cellType _ upCellType; }; BoundFlatCellType: PUBLIC PROC [root: CellType, flatCell: FlatCellTypeRec] RETURNS [bindings: Bindings, instance: CellInstance, cellType: CellType] = { Search: BoundFlatCellProc = { upBindings _ bindings; upInstance _ instance; upCellType _ cell; NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, Search] }; upBindings: Bindings _ NIL; upInstance: CellInstance _ NIL; upCellType: CellType _ NIL; Search[cell: root, target: flatCell]; bindings _ upBindings; instance _ upInstance; cellType _ upCellType; }; FindAnyFlatCell: PUBLIC PROC [root: CellType, cellType: CellType] RETURNS [flatCellType: FlatCellTypeRec _ []] = { Find: PROC [cell: CellType, flatCell: FlatCellTypeRec _ []] RETURNS [BOOL] = { IF RefTab.Fetch[cellTypeVisit, cell].found THEN RETURN [FALSE]; IF NOT RefTab.Insert[cellTypeVisit, cell, $Visited] THEN ERROR; IF cell=cellType THEN { flatCellType _ flatCell; RETURN [TRUE]; }; SELECT TRUE FROM cell.class=CoreClasses.transistorCellClass => NULL; cell.class=CoreClasses.recordCellClass => { rct: CoreClasses.RecordCellType _ NARROW[cell.data]; FOR i: NAT IN [0..rct.size) DO IF Find[rct[i].type, [ExtendPath[flatCell.path, i, rct], 0]] THEN RETURN [TRUE]; ENDLOOP; }; ENDCASE => { new: CellType _ CoreOps.Recast[cell]; IF Find[new, [flatCell.path, IF cell=new THEN flatCell.recastCount ELSE flatCell.recastCount+1]] THEN RETURN [TRUE]; }; RETURN [FALSE]; }; cellTypeVisit: RefTab.Ref _ RefTab.Create[]; -- Marks visited cells IF NOT Find[root] THEN ERROR PathError["Cell type is not reachable from root"]; }; RaiseRootOfFlatCell: PUBLIC PROC [by: InstancePath, flatCell: FlatCellTypeRec] RETURNS [raised: FlatCellTypeRec] ~ { raised _ flatCell; raised.path _ RaiseRootOfInstancePath[by, raised.path]; RETURN}; ParseWirePath: PUBLIC PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [flatWire: FlatWireRec] = { AddWire: PROC [subWire: NAT] = { pathBits: NAT _ BitOps.NBits[flatWire.wire.size]; instanceBits: PACKED ARRAY [0..16) OF BOOL _ LOOPHOLE[subWire]; FOR bit: NAT IN [0..pathBits) DO flatWire.path.bits[flatWire.path.length+bit] _ instanceBits[16-pathBits+bit]; ENDLOOP; flatWire.path.length _ flatWire.path.length + pathBits; flatWire.wire _ flatWire.wire[subWire]; IF flatWire.wireRoot=actual THEN publicWire _ publicWire[subWire]; }; InternalRoot: PROC = { rct: CoreClasses.RecordCellType _ NIL; flatWire.flatCell.path _ AddInstance[flatWire.flatCell.path, instance, within]; flatWire.flatCell.recastCount _ 0; [rct, flatWire.flatCell] _ MakeRecord[IF instance=NIL THEN root ELSE instance.type, instance, flatWire.flatCell, cutSet]; flatWire.wire _ rct.internal; flatWire.wireRoot _ internal; }; ParseQuotedNameWire: PROC = { depth: NAT _ 1; DO char: CHAR _ IO.GetChar[ts ! IO.EndOfStream => GOTO oops]; token _ Rope.Cat[token, Rope.FromChar[char]]; SELECT char FROM '{ => depth _ depth+1; '} => {IF depth=1 THEN EXIT; depth _ depth-1}; ENDCASE; ENDLOOP; EXITS oops => MakeError["Missing end brace on quoted short name"]; }; AppendNameWire: PROC = { state _ sawWireNameOrNumber; IF RootWire[]#none THEN MakeError["Cannot name a wire actual, internal, or public"]; FOR subWire: CARDINAL IN [0..flatWire.wire.size) DO IF Rope.Equal[token, CoreOps.GetShortWireName[IF flatWire.wireRoot=actual THEN publicWire[subWire] ELSE flatWire.wire[subWire]]] THEN { AddWire[subWire]; EXIT; }; REPEAT FINISHED => { -- This hack is for Don Curry's benefit hackName: ROPE _ token; DO [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => EXIT]; hackName _ Rope.Cat[hackName, token]; ENDLOOP; FOR subWire: CARDINAL IN [0..flatWire.wire.size) DO IF Rope.Equal[hackName, CoreOps.GetShortWireName[IF flatWire.wireRoot=actual THEN publicWire[subWire] ELSE flatWire.wire[subWire]]] THEN { AddWire[subWire]; EXIT; }; REPEAT FINISHED => MakeError["Can't find wire"]; ENDLOOP; }; ENDLOOP; }; AppendNumberWire: PROC = { subWire: CARDINAL _ Convert.CardFromRope[token]; IF flatWire.wire=NIL THEN InternalRoot[]; IF subWire>=flatWire.wire.size THEN MakeError["No such wire"]; AddWire[subWire]; }; PossibleRootWire: PROC = { wireType: RootWireType _ RootWire[]; SELECT wireType FROM public => { state _ sawWireRoot; flatWire.flatCell.path _ AddInstance[flatWire.flatCell.path, instance, within]; flatWire.wire _ thisCell.public; flatWire.wireRoot _ public; }; internal => { state _ sawWireRoot; InternalRoot[]; }; actual => { parentCT: CellType _ within; IF instance=NIL THEN MakeError["Can't access actual of root"]; state _ sawWireRoot; flatWire.wire _ instance.actual; publicWire _ instance.type.public; flatWire.wireRoot _ actual; flatWire.flatCell.recastCount _ 0; UNTIL parentCT.class=CoreClasses.recordCellClass DO new: CellType _ CoreOps.Recast[parentCT]; IF new#parentCT THEN flatWire.flatCell.recastCount _ flatWire.flatCell.recastCount + 1; parentCT _ new; ENDLOOP; flatWire.instanceIndex _ CoreClasses.InstanceIndex[parentCT, instance]; }; none => { InternalRoot[]; AppendNameWire[]; }; ENDCASE => ERROR; }; RootWireType: TYPE = {public, internal, actual, none}; RootWire: PROC RETURNS [RootWireType] = { RETURN [SELECT TRUE FROM Rope.Equal[token, "PUBLIC", FALSE] => public, Rope.Equal[token, "INTERNAL", FALSE] => internal, Rope.Equal[token, "ACTUAL", FALSE] => actual, ENDCASE => none]; }; WirePathParseStates: TYPE = {start, expectMaybeRoot, sawWireRoot, expectWireNameOrNumber, sawWireNameOrNumber, sawLeft, sawNumber, sawRight}; instance: CoreClasses.CellInstance; within: CellType; token: ROPE; ts: IO.STREAM; firstChar: CHAR; tokenKind: IO.TokenKind; thisCell: CellType; publicWire: Wire _ NIL; state: WirePathParseStates _ start; [flatWire.flatCell, instance, within, token, ts, firstChar, tokenKind, thisCell] _ ParsePartialCellTypePath[root, pathRope, cutSet]; flatWire.validPath _ TRUE; DO SELECT state FROM start => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '[ => state _ sawLeft; '. => state _ expectMaybeRoot; '{ => {ParseQuotedNameWire[]; PossibleRootWire[]}; ENDCASE => MakeError[]; tokenID => PossibleRootWire[]; tokenDECIMAL => {AppendNumberWire[]; state _ sawWireNameOrNumber}; ENDCASE => MakeError[]; expectMaybeRoot => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '[ => state _ sawLeft; '{ => {ParseQuotedNameWire[]; PossibleRootWire[]}; ENDCASE => MakeError[]; tokenID => PossibleRootWire[]; tokenDECIMAL => {AppendNumberWire[]; state _ sawWireNameOrNumber}; ENDCASE => MakeError[]; sawWireRoot => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '. => state _ expectWireNameOrNumber; ENDCASE => MakeError[]; ENDCASE => MakeError[]; expectWireNameOrNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '[ => state _ sawLeft; '{ => {ParseQuotedNameWire[]; AppendNameWire[]}; ENDCASE => MakeError[]; tokenID => AppendNameWire[]; tokenDECIMAL => {AppendNumberWire[]; state _ sawWireNameOrNumber}; ENDCASE => MakeError[]; sawWireNameOrNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '. => state _ expectWireNameOrNumber; '[ => state _ sawLeft; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawLeft => SELECT tokenKind FROM tokenDECIMAL => {AppendNumberWire[]; state _ sawNumber}; ENDCASE => MakeError[]; sawNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '] => state _ sawRight; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawRight => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '. => state _ expectWireNameOrNumber; '[ => state _ sawLeft; '{ => {ParseQuotedNameWire[]; AppendNameWire[]}; ENDCASE => MakeError[]; tokenID => AppendNameWire[]; tokenDECIMAL => {AppendNumberWire[]; state _ sawWireNameOrNumber}; ENDCASE => MakeError[]; ENDCASE => MakeError[]; [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => {tokenKind _ tokenEOF; EXIT}]; ENDLOOP; IF state=sawWireRoot OR state=expectWireNameOrNumber OR state=sawLeft OR state=sawNumber THEN MakeError[]; }; WirePathRope: PUBLIC PROC [root: CellType, wire: FlatWireRec] RETURNS [pathRope: ROPE] = { cellType: CellType _ ResolveFlatCellType[root, wire.flatCell].cellType; rootWire: Wire; IF wire.wireRoot=actual THEN { wire.flatCell.path _ ExtendPath[wire.flatCell.path, wire.instanceIndex, NARROW[cellType.data, CoreClasses.RecordCellType]]; wire.flatCell.recastCount _ 0; }; pathRope _ CellTypePathRope[root, wire.flatCell]; IF (NOT Rope.IsEmpty[pathRope]) AND wire.wireRoot#internal THEN pathRope _ Rope.Cat[pathRope, "."]; pathRope _ Rope.Cat[pathRope, SELECT wire.wireRoot FROM internal => NIL, public => "public", actual => "actual", ENDCASE => ERROR]; rootWire _ SELECT wire.wireRoot FROM public => cellType.public, internal => NARROW [cellType.data, CoreClasses.RecordCellType].internal, actual => NARROW [cellType.data, CoreClasses.RecordCellType][wire.instanceIndex].type.public, ENDCASE => ERROR; IF wire.validPath THEN { visitWire: Wire _ rootWire; begin: NAT _ 0; index: NAT; name: ROPE; UNTIL begin=wire.path.length DO pathBits: NAT _ BitOps.NBits[visitWire.size]; instanceBits: PACKED ARRAY [0..16) OF BOOL _ ALL [FALSE]; FOR bit: NAT IN [0..pathBits) DO instanceBits[16-pathBits+bit] _ wire.path.bits[begin+bit]; ENDLOOP; begin _ begin + pathBits; index _ LOOPHOLE[instanceBits]; visitWire _ visitWire[index]; name _ CoreOps.GetShortWireName[visitWire]; IF name=NIL THEN name _ Convert.RopeFromInt[index]; IF NOT Rope.IsEmpty[pathRope] THEN pathRope _ Rope.Cat[pathRope, "."]; pathRope _ Rope.Cat[pathRope, name]; ENDLOOP; } ELSE { IF NOT Rope.IsEmpty[pathRope] THEN pathRope _ Rope.Cat[pathRope, "."]; pathRope _ Rope.Cat[pathRope, CoreOps.GetFullWireName[rootWire, wire.wire]]; }; }; FlatWireEqual: PUBLIC PROC [key1, key2: REF ANY] RETURNS [equal: BOOL] = { equal _ FlatWireEqualRec[NARROW [key1, FlatWire]^, NARROW [key2, FlatWire]^]; }; FlatWireEqualRec: PUBLIC PROC [one, other: FlatWireRec] RETURNS [equal: BOOL] = { equal _ one.wire=other.wire AND FlatCellTypeEqualRec[one.flatCell, other.flatCell]; }; FlatWireHash: PUBLIC PROC [wire: REF ANY] RETURNS [hash: CARDINAL] = { hash _ FlatWireHashRec[NARROW [wire, FlatWire]^]; }; FlatWireHashRec: PUBLIC PROC [wire: FlatWireRec] RETURNS [hash: CARDINAL] = { hash _ FlatCellTypeHashRec[wire.flatCell]; hash _ Basics.BITXOR[hash, Basics.LowHalf[LOOPHOLE[wire.wire]]]; hash _ Basics.BITXOR[hash, Basics.HighHalf[LOOPHOLE[wire.wire]]]; }; CanonizeWire: PUBLIC PROC [root: CellType, child: FlatWireRec] RETURNS [parent: FlatWireRec] = { WindUp: UnboundFlatCellProc = { new: Wire; -- will contain recomputed value if possible previousCells _ CONS [cell, previousCells]; -- save for recast wind up previousInstances _ CONS [instance, previousInstances]; -- save for recast wind up NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, NIL, WindUp]; previousCells _ previousCells.rest; -- restore to entry state previousInstances _ previousInstances.rest; -- restore to entry state IF stop OR previousCells=NIL THEN RETURN; -- at top level... IF instance=previousInstances.first AND cell=previousCells.first THEN RETURN; -- In-place reacst new _ CoreOps.CorrespondingActual[actual: IF instance=NIL OR instance.type#cell THEN previousCells.first.public ELSE instance.actual, public: cell.public, subPublic: canonized.wire]; -- recast or RCT IF new=NIL THEN stop _ TRUE -- can't proceed any further ELSE canonized _ [flatCell: flatParent, wireRoot: internal, wire: new]; }; canonized: FlatWireRec _ child; -- will be backtracked in place previousCells: LIST OF CellType _ NIL; -- to keep track of recasts previousInstances: LIST OF CellInstance _ NIL; -- to keep track of recasts stop: BOOL _ FALSE; WindUp[cell: root, target: child.flatCell]; IF CoreOps.RecursiveMember[root.public, canonized.wire] THEN canonized.wireRoot _ public; -- final upgrade: we went up to the last recursion stage succesfully RETURN [parent: canonized]; -- too bad we must rename the result... }; RaiseRootOfFlatWire: PUBLIC PROC [by: InstancePath, flatWire: FlatWireRec] RETURNS [raised: FlatWireRec] ~ { raised _ flatWire; raised.flatCell _ RaiseRootOfFlatCell[by, raised.flatCell]; RETURN}; NextUnboundCellType: PUBLIC PROC [cell: CellType, target: FlatCellTypeRec, flatCell: FlatCellTypeRec, instance: CellInstance, index: NAT, parent: CellType, flatParent: FlatCellTypeRec, data: REF ANY, proc: UnboundFlatCellProc] = { IF FlatCellTypeEqualRec[target, flatCell] THEN RETURN; IF cell.class=CoreClasses.recordCellClass THEN { rct: CoreClasses.RecordCellType _ NARROW[cell.data]; pathBits: NAT _ BitOps.NBits[rct.size]; childFlatCell: FlatCellTypeRec _ [flatCell.path, 0]; instance: CellInstance; IF FlatCellTypeEqualRec[target, allFlatCells] THEN { FOR inst: NAT IN [0..rct.size) DO instance _ rct[inst]; childFlatCell.path _ ExtendPath[flatCell.path, inst, rct]; proc[cell: instance.type, target: target, flatCell: childFlatCell, instance: instance, index: inst, parent: cell, flatParent: flatCell, data: data]; ENDLOOP; } ELSE { instanceBits: PACKED ARRAY [0..16) OF BOOL _ ALL [FALSE]; IF target.path.length<=flatCell.path.length THEN ERROR; -- illegal move FOR bit: NAT IN [0..pathBits) DO instanceBits[16-pathBits+bit] _ target.path.bits[flatCell.path.length+bit]; childFlatCell.path.bits[flatCell.path.length+bit] _ target.path.bits[flatCell.path.length+bit]; ENDLOOP; index _ LOOPHOLE[instanceBits]; instance _ rct[index]; childFlatCell.path.length _ childFlatCell.path.length + pathBits; proc[cell: instance.type, target: target, flatCell: childFlatCell, instance: instance, index: index, parent: cell, flatParent: flatCell, data: data]; } } ELSE { new: CellType _ NIL; IF cell.class.recast=NIL THEN ERROR; -- illegal move new _ CoreOps.Recast[cell]; IF new#cell THEN flatCell.recastCount _ flatCell.recastCount + 1; proc[cell: new, target: target, flatCell: flatCell, instance: instance, index: index, parent: parent, flatParent: flatParent, data: data]; }; }; NextBoundCellType: PUBLIC PROC [cell: CellType, target: FlatCellTypeRec, flatCell: FlatCellTypeRec, instance: CellInstance, index: NAT, parent: CellType, flatParent: FlatCellTypeRec, data: REF ANY, bindings: Bindings, proc: BoundFlatCellProc] = { BindCellType: UnboundFlatCellProc = { newBindings: Bindings _ IF instance=previousInstance AND cell=previousCell THEN bindings ELSE BindInstance[parent: flatParent, actual: IF instance=NIL OR instance.type#cell THEN previousCell.public ELSE instance.actual, public: cell.public, bindings: bindings]; proc[cell, target, flatCell, instance, index, parent, flatParent, data, newBindings]; }; previousCell: CellType _ cell; previousInstance: CellInstance _ instance; NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, BindCellType]; }; InitialBindingTable: PUBLIC PROC [root: CellType] RETURNS [bindings: Bindings] = { Bind: CoreOps.EachWireProc = { IF subWires _ (NOT RefTab.Fetch[bindings, wire].found) THEN { fw: FlatWire = NEW [FlatWireRec _ [wireRoot: public, wire: wire]]; IF NOT RefTab.Insert[bindings, wire, fw] THEN ERROR; }; }; bindings _ RefTab.Create[]; IF CoreOps.VisitWireSeq[root.public, Bind] THEN ERROR; bindings _ bindings; }; ParsePartialCellTypePath: PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [flatCell: FlatCellTypeRec, instance: CellInstance _ NIL, within: CellType, token: ROPE, ts: IO.STREAM, firstChar: CHAR, tokenKind: IO.TokenKind, thisCell: CellType _ NIL] = { RecastToClass: PROC = { DO IF NOT first THEN { new: CellType _ NIL; CheckRecast[flatCell, instance, thisCell, cutSet]; new _ CoreOps.Recast[thisCell]; IF new#thisCell THEN flatCell.recastCount _ flatCell.recastCount + 1; thisCell _ new; }; first _ FALSE; IF Rope.Equal[token, thisCell.class.name] THEN EXIT; ENDLOOP; state _ sawCellClassNameOrRecastNumber; }; RecastByNumber: PROC = { recastNumber: CARDINAL _ Convert.CardFromRope[token]; FOR rn: CARDINAL IN [0..recastNumber) DO new: CellType _ NIL; CheckRecast[flatCell, instance, thisCell, cutSet]; new _ CoreOps.Recast[thisCell]; IF new#thisCell THEN flatCell.recastCount _ flatCell.recastCount + 1; thisCell _ new; ENDLOOP; state _ sawRecastNumber; }; CheckCellClassName: PROC = { IF NOT Rope.Equal[token, thisCell.class.name] THEN MakeError[Rope.Cat["Incorrect cell class name ", token]]; state _ sawCellClassName; }; CellTypePathParseStates: TYPE = {start, sawAsterisk, sawRecastNumber, sawLeftParan, sawCellClassName, sawCellClassNameOrRecastNumber}; state: CellTypePathParseStates _ start; first: BOOL _ TRUE; [flatCell.path, instance, within, token, ts, firstChar, tokenKind] _ ParsePartialInstancePath[root, pathRope, cutSet]; thisCell _ IF instance=NIL THEN root ELSE instance.type; flatCell.recastCount _ 0; IF tokenKind#tokenEOF THEN DO SELECT state FROM start => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '* => state _ sawAsterisk; '., '[, '{ => EXIT; ENDCASE => MakeError[]; tokenID => EXIT; tokenDECIMAL => EXIT; ENDCASE => MakeError[]; sawAsterisk => SELECT tokenKind FROM tokenID => RecastToClass[]; tokenDECIMAL => RecastByNumber[]; ENDCASE => MakeError[]; sawRecastNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '( => state _ sawLeftParan; '* => state _ sawAsterisk; '., '[, '{ => EXIT; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawLeftParan => SELECT tokenKind FROM tokenID => CheckCellClassName[]; ENDCASE => MakeError[]; sawCellClassName => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM ') => state _ sawCellClassNameOrRecastNumber; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawCellClassNameOrRecastNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '* => state _ sawAsterisk; '., '[, '{ => EXIT; ENDCASE => MakeError[]; ENDCASE => MakeError[]; ENDCASE => MakeError[]; [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => {tokenKind _ tokenEOF; EXIT}]; ENDLOOP; IF state=sawAsterisk OR state=sawLeftParan OR state=sawCellClassName THEN MakeError[]; }; ParsePartialInstancePath: PROC [root: CellType, pathRope: ROPE, cutSet: CutSet] RETURNS [path: InstancePath _ nullInstancePath, instance: CellInstance _ NIL, within: CellType, token: ROPE, ts: IO.STREAM, firstChar: CHAR, tokenKind: IO.TokenKind] = { AppendNameInstance: PROC = { found: BOOL _ FALSE; rct: CoreClasses.RecordCellType; path _ AddInstance[path, instance, within]; within _ IF instance=NIL THEN root ELSE instance.type; rct _ MakeRecord[within, instance, [path, 0], cutSet].rct; FOR inst: CARDINAL IN [0..rct.size) DO IF Rope.Equal[token, CoreClasses.GetCellInstanceName[rct[inst]]] THEN { instance _ rct[inst]; found _ TRUE; EXIT; }; REPEAT FINISHED => FOR inst: CARDINAL IN [0..rct.size) DO IF Rope.Equal[token, CoreOps.GetCellTypeName[rct[inst].type]] THEN { IF found THEN MakeError["Append by cell type name is ambiguous"]; instance _ rct[inst]; found _ TRUE; }; ENDLOOP; ENDLOOP; IF NOT found THEN MakeError[Rope.Cat["Can't find instance or cell type of name ", token]]; state _ sawInstanceNameOrNumber; }; AppendNumberInstance: PROC = { rct: CoreClasses.RecordCellType; inst: CARDINAL _ Convert.CardFromRope[token]; path _ AddInstance[path, instance, within]; within _ IF instance=NIL THEN root ELSE instance.type; rct _ MakeRecord[within, instance, [path, 0], cutSet].rct; IF inst>=rct.size THEN MakeError[Rope.Cat["No such instance ", token]]; instance _ rct[inst]; state _ sawInstanceNumber; }; CheckCellTypeName: PROC = { IF NOT Rope.Equal[token, CoreOps.InheritCellTypeName[instance.type]] THEN MakeError[Rope.Cat["Incorrect cell type name ", token]]; state _ sawCellTypeName; }; InstancePathParseStates: TYPE = {start, expectInstanceNameOrNumber, sawInstanceNumber, sawLeftParan, sawCellTypeName, sawInstanceNameOrNumber}; state: InstancePathParseStates _ start; within _ root; ts _ IO.RIS[pathRope]; DO [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => {tokenKind _ tokenEOF; EXIT}]; SELECT state FROM start => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '/ => state _ expectInstanceNameOrNumber; '*, '[, '{ => EXIT; ENDCASE => MakeError[]; tokenID => EXIT; tokenDECIMAL => EXIT; ENDCASE => MakeError[]; expectInstanceNameOrNumber => SELECT tokenKind FROM tokenID => AppendNameInstance[]; tokenDECIMAL => AppendNumberInstance[]; ENDCASE => MakeError[]; sawInstanceNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '( => state _ sawLeftParan; '/ => state _ expectInstanceNameOrNumber; '*, '., '[, '{ => EXIT; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawLeftParan => SELECT tokenKind FROM tokenID => CheckCellTypeName[]; ENDCASE => MakeError[]; sawCellTypeName => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM ') => state _ sawInstanceNameOrNumber; ENDCASE => MakeError[]; ENDCASE => MakeError[]; sawInstanceNameOrNumber => SELECT tokenKind FROM tokenSINGLE => SELECT firstChar FROM '/ => state _ expectInstanceNameOrNumber; '*, '., '[, '{ => EXIT; ENDCASE => MakeError[]; ENDCASE => MakeError[]; ENDCASE => MakeError[]; ENDLOOP; IF state=expectInstanceNameOrNumber OR state=sawLeftParan OR state=sawCellTypeName THEN MakeError[]; }; MakeRecord: PROC [cellType: CellType, instance: CellInstance, flatCell: FlatCellTypeRec, cutSet: CutSet] RETURNS [rct: CoreClasses.RecordCellType, newFlatCell: FlatCellTypeRec] = { UNTIL cellType.class=CoreClasses.recordCellClass DO new: CellType _ NIL; CheckRecast[flatCell, instance, cellType, cutSet]; new _ CoreOps.Recast[cellType]; IF new#cellType THEN flatCell.recastCount _ flatCell.recastCount + 1; cellType _ new; ENDLOOP; rct _ NARROW [cellType.data]; newFlatCell _ flatCell }; CheckRecast: PROC [flatCell: FlatCellTypeRec, instance: CellInstance, cellType: CellType, cutSet: CutSet] = { IF cellType.class.recast=NIL THEN MakeError["Attempting to name something inside of a primitive element"]; IF CutSetMemberResolved[flatCell, instance, cellType, cutSet] THEN MakeError["Attempting to name something below the current cutSet"]; }; CheckNoMore: PROC [ts: IO.STREAM, firstChar: CHAR, tokenKind: IO.TokenKind] = { IF tokenKind#tokenEOF THEN MakeError[]; }; ParseToken: PROC [ts: IO.STREAM] RETURNS [token: ROPE, firstChar: CHAR, tokenKind: IO.TokenKind] = { token _ IO.GetTokenRope[ts, Breaks].token; firstChar _ Rope.Fetch[token]; tokenKind _ SELECT TRUE FROM Rope.Length[token]=1 AND Breaks[firstChar]=break => tokenSINGLE, firstChar IN ['0..'9] => tokenDECIMAL, ENDCASE => tokenID; }; Breaks: IO.BreakProc = { RETURN[SELECT char FROM IN [IO.NUL .. IO.SP] => sepr, '{, '}, '/, '., '(, '), '[, '], '* => break, IN ['0..'9], IN ['a..'z], IN ['A..'Z] => other, ENDCASE => ERROR PathError["Illegal character"]]; }; END. CoreFlatImpl.mesa Copyright Σ 1985, 1986, 1987 by Xerox Corporation. All rights reserved. Barth, October 5, 1987 5:37:58 pm PDT Last Edited by: Gasbarro October 21, 1987 12:25:04 pm PDT Last Edited by: Louis Monier January 20, 1987 10:42:41 am PST Last tweaked by Mike Spreitzer on November 2, 1987 3:53:04 pm PST Jean-Marc Frailong December 26, 1987 8:14:36 pm PST Bertrand Serlet September 25, 1987 1:08:03 pm PDT Mike Spreitzer February 27, 1987 3:45:39 pm PST Error Cut Sets Instances oneBits: ARRAY [0..2) OF INT _ LOOPHOLE[one.bits]; otherBits: ARRAY [0..2) OF INT _ LOOPHOLE[other.bits]; equal _ one.length=other.length AND oneBits=otherBits; IF equal THEN FOR bit: NAT IN [0..one.length) DO IF one.bits[bit]#other.bits[bit] THEN { equal _ FALSE; EXIT; }; ENDLOOP; CellTypes Wires WirePath ::= {start} ?((PUBLIC | INTERNAL | ACTUAL ) {sawWireRoot} . {expectWireNameOrNumber} ) (( QuotedName | Name | Number ) {sawWireNameOrNumber} ?( . {expectWireNameOrNumber})) | ( [ {sawLeft} Number {sawNumber} ] {sawRight} ) CanonizeWire: PUBLIC PROC [root: CellType, child: FlatWireRec] RETURNS [parent: FlatWireRec] = { -- this is the old version. Kept if a problem arises with the new (faster) one Search: BoundFlatCellProc = { upBindings _ bindings; NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, Search] }; upBindings: Bindings _ NIL; parentRef: FlatWire _ NIL; Search[cell: root, target: child.flatCell, bindings: InitialBindingTable[root]]; parentRef _ NARROW[RefTab.Fetch[upBindings, child.wire].val]; parent _ IF parentRef=NIL THEN child ELSE parentRef^; }; On return of recursion, transport wire across boundaries. Stop all recursion when unable to proceed (avoids scanning the publics of cells above the canonical wire origin). Enumeration Utilities CellTypePath ::= {start} * {sawAsterisk} ( Name | (Number {sawRecastNumber} ?( ( {sawLeftParan} Name {sawCellClassName} ) ) ) {sawCellClassNameOrRecastNumber} ) InstancePath ::= {start} / {expectInstanceNameOrNumber} ( Name | (Number {sawInstanceNumber} ?( ( {sawLeftParan} Name {sawCellTypeName} ) ) ) {sawInstanceNameOrNumber} ) token: ROPE; IF tokenKind=tokenSINGLE AND firstChar='. THEN [token, firstChar, tokenKind] _ ParseToken[ts ! IO.EndOfStream => {tokenKind _ tokenEOF; CONTINUE}]; Κ'Z– "cedar" style˜codešœ™KšœH™HK™%K™9K™=K™AK™3K™1K™/K™—KšΟk œJœ˜dK˜•StartOfExpansion[]šΠbn œœ˜Kšœ@œ˜WKšœ ˜Kšœœœ ˜—K˜head™š Οn œœœœœœ˜1K˜—šŸ œœœœ˜#Kšœœœ˜!Kšœ˜K˜K˜——™šœœ2˜DK˜—š Ÿœœœ,œœœ˜zJšœF˜FKšœ˜J˜—šŸœœœœœœœ˜oJš œœœœœ7˜RJšœ'˜'Jšœ;˜;J˜ Kšœ˜J˜—š Ÿœœœ(œœœ˜nJšœB˜BKšœ˜J˜—šŸœœœœœœœ˜cJš œœœœœ3˜NJšœ'˜'Jšœ7˜7J˜ Kšœ˜J˜—š Ÿœœœ)œœœ˜qJšœC˜CKšœ˜J˜—šŸœœœœœœœ˜fJš œœœœœ4˜OJšœ'˜'Jšœ8˜8J˜ Kšœ˜J˜—šŸ œœœ-œœœœœœ œœ˜Χšœ œ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜K˜—š Ÿ œœœ=œ œœ˜xK˜K˜K˜KšœC˜CKšœC˜CKšœ˜K˜—š ŸœœœYœ œœ˜œKšœœœ˜Kš œ0œ1œœœ˜wKš œœœœœ˜!šœ2œœ˜Dšœ7œ˜?šœœ$˜AKšœ6œœ˜BKšœœœF˜_Kšœ˜—K˜—Kšœ˜—šœ3œœ˜HKšœ.œœœ˜CKšœ˜—šœ5œœ˜JKšœ.œœœ˜BKšœ˜—šœ œœ˜Kšœ1˜1Kšœœœœ œœœœ˜PK˜—Kšœ)˜)Kšœœœœ œœœœ˜PKš œ œ+œœœ˜PKšœ œœœ œMœœœ˜‰Kš œ œIœœœ˜pKš œ œPœœœ˜wKšœ˜K˜—šŸ œœœœœœœœ˜Kš œœœœœœ˜9š œœœœœœ˜;KšœPœœœ˜dKšœ˜—Kšœ˜—Kšœ˜K˜—šŸ œœœœœ œœœœ˜]Jšœœœ œ ˜)Jšœœœ œ ˜)Jšœœœ œ ˜)Jšœœœ œ ˜)Jšœœœ œ ˜)Jšœœœ œ ˜)Kšœ˜K˜—šŸœœ œœœœœ œœœ˜YKšœ˜š œœœœœœ˜8Jšœ œ˜&Jšœ˜—Kšœ˜K˜—š Ÿ œœœ=œ œœ˜všŸ œ˜%šœœ˜Kšœ*œ˜/KšœBœ˜HKšœi˜p—K˜—Kšœ+˜+K˜K˜——™ š Ÿœœœœœ˜pKšœ˜Kšœ˜Kšœœ˜ Kšœœœ˜Kšœ œ˜Kšœ œ ˜Kšœm˜mKšœ+˜+Kšœ&˜&Kšœ˜K˜—š Ÿœœœ&œ œœ˜eK˜šž œ˜#šœ œœ˜-Kšœœ-˜7šœœœ˜Kšœœ.˜@KšœH˜HKšœœœ/˜GK˜—Kšœ)˜)K˜—Kšœc˜cKšœ˜K˜—Kšœ˜Kšœ˜K˜—š Ÿœœœœ œ˜SKšœ œ˜8Kš œ œœœœ ™2Kš œ œœœœ ™6Kšœ œ™6š œœœœœ™0šœœ™'Kšœœ™Kšœ™K™—Kšœ™—Kšœ˜K˜—š Ÿœœœœœ ˜SKšœ)œ˜Nšœœœ˜Jšœœ˜$Jšœ˜—Kšœ˜K˜—šŸ œœœSœ˜ŽKšœ˜šœ œœ˜Kšœ-˜-Kšœ(œ˜>Kšœœ1˜;Kšœ œœΟc(˜@Kšœ4˜4Kšœ˜—Kšœ˜K˜—š Ÿ œœœ$œ#œ˜„Kšœ œ˜'Kšœ˜šœœœ˜ Kšœ*œ˜EKšœ˜—Kšœ+˜+K˜K˜—šŸ œœœHœ˜„K˜šŸœ˜0Kšœœ˜Kšœ œœœ2˜TKš œ8œœœœ5œ˜ŒKšœ˜K˜—Kšœ+˜+Kšœ[œœ˜hKšœ˜K˜—šŸœœœœ˜`Kšœœœ˜3šœ ˜ Kšœ˜šœœœ˜Kšœ ˜Kšœœ˜.Kšœ˜——Kšœ˜K˜——™ š Ÿœœœœœ ˜wKšœ˜Kšœ˜Kšœœ˜ Kšœœœ˜Kšœ œ˜Kšœ œ ˜Kšœ˜Kšœ{˜{Kšœ=˜=Kšœ&˜&Kšœ˜K˜—š Ÿœœœ-œ œ˜fKšœ1˜1KšœœO˜mKšœ˜K˜—šŸœœœœœœ œ˜NKšœœœ˜YKšœ˜K˜—š Ÿœœœœ œ˜YKšœ0œ#˜VKšœ˜K˜—šŸœœœ œœœœ˜NKšœœ˜Kšœ˜Kšœ˜K˜—šŸœœ˜Kšœ$˜$šœ ˜šœ ˜ Kšœ˜KšœO˜OKšœ ˜ Kšœ˜K˜—šœ ˜ Kšœ˜Kšœ˜K˜—šœ ˜ K˜Kšœ œœ*˜>Kšœ˜Kšœ ˜ Kšœ"˜"Kšœ˜Kšœ"˜"šœ,˜3Kšœ)˜)KšœœC˜WKšœ˜Kšœ˜—KšœG˜GK˜—šœ ˜ Kšœ˜Kšœ˜K˜—Kšœœ˜—K˜K˜—šœœ$˜6K˜—šŸœœœ˜)šœœœ˜Kšœœ ˜-Kšœœ˜1Kšœœ ˜-Kšœ ˜—K˜K˜—Kš"Οb œ‘œ‘œœ‘œœ‘œ*‘œ‘œ ‘œ‘œ‘œ‘œ‘œ‘œ‘œ-‘™θKšœœt˜Kšœ#˜#Kšœ˜Kšœœ˜ Kšœœœ˜Kšœ œ˜Kšœ œ ˜Kšœ˜Kšœœ˜Kšœ#˜#Kšœ„˜„Kšœœ˜š˜šœ˜šœ œ ˜šœœ ˜$Kšœ˜Kšœ˜Kšœ2˜2Kšœ˜—Kšœ˜KšœB˜BKšœ˜—šœœ ˜(šœœ ˜$Kšœ˜Kšœ2˜2Kšœ˜—Kšœ˜KšœB˜BKšœ˜—šœœ ˜$šœœ ˜$Kšœ%˜%Kšœ˜—Kšœ˜—šœœ ˜/šœœ ˜$Kšœ˜Kšœ0˜0Kšœ˜—Kšœ˜KšœB˜BKšœ˜—šœœ ˜,šœœ ˜$Kšœ%˜%Kšœ˜Kšœ˜—Kšœ˜—šœ œ ˜ Kšœ8˜8Kšœ˜—šœ œ ˜"šœœ ˜$Kšœ˜Kšœ˜—Kšœ˜—šœ œ ˜!šœœ ˜$Kšœ%˜%Kšœ˜Kšœ0˜0Kšœ˜—Kšœ˜KšœB˜BKšœ˜—Kšœ˜—Kšœ0œ'œ˜`Kšœ˜—Kš œœœœœ ˜jK˜K˜—š Ÿ œœœ%œ œ˜ZKšœG˜GKšœ˜šœœ˜KšœHœ-˜{Kšœ˜K˜—Kšœ1˜1Kšœœœœ%˜dKš œœœ œ*œœ˜ƒšœ œ˜$Kšœ˜Kšœ œ6˜HKšœ œM˜]Kšœœ˜—šœœ˜K˜Kšœœ˜Kšœœ˜ Kšœœ˜ šœ˜Kšœ œ ˜-Kš œœœ œœœœ˜9šœœœ˜ Kšœ:˜:Kšœ˜—Kšœ˜Kšœœ˜Kšœ˜K˜+Kšœœœ#˜3Kšœœœ%˜GKšœ$˜$Kšœ˜—Kšœ˜—šœ˜Kšœœœ%˜GKšœL˜LK˜—Kšœ˜K˜—šŸ œœœœœœ œ˜JKšœœœ˜MKšœ˜K˜—š Ÿœœœœ œ˜QJšœœ4˜SKšœ˜K˜—šŸ œœœœœœœ˜FKšœœ˜1Kšœ˜K˜—š Ÿœœœœœ˜MJšœ*˜*Jšœœœ˜@Jšœœœ˜AKšœ˜K˜—šŸ œœœ&œi™―K™šŸœ™Kšœ™Kšœf™fK™K™—Kšœœ™Kšœœ™KšœP™PKšœ œ+™=Kš œ œ œœœ ™5Kšœ™K™—šŸ œœœ&œ˜`šŸœ˜K™«Kšœ  ,˜7Kšœœ ˜FKšœœ  ˜RKšœQœ ˜^Kšœ$ ˜=Kšœ, ˜EKš œœœœœ ˜