CoreFlatImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Barth, May 1, 1986 3:52:25 pm PDT
Spreitzer, April 8, 1986 4:31:47 pm PST
Last Edited by: Neil Gunther May 8, 1986 6:12:55 pm PDT
Bertrand Serlet May 16, 1986 11:28:14 am PDT
CoreFlatImpl:
CEDAR
PROGRAM
IMPORTS Basics, BitHacks, Convert, CoreClasses, CoreOps, HashTable, IO, Rope
EXPORTS CoreFlat
= BEGIN OPEN CoreFlat;
Flatten
GetCellType:
PUBLIC
PROC [root: Core.CellType, path: PackedPath]
RETURNS [cellType: Core.CellType ←
NIL] = {
SetCellType: EachUnboundInstanceProc = {
innerCellType ← CoreOps.ToBasic[instance.instance.type]
};
innerCellType: Core.CellType ← root;
VisitUnboundPath[root, path, SetCellType];
cellType ← innerCellType;
};
VisitUnboundPath:
PUBLIC
PROC [root: Core.CellType, path: PackedPath, eachInstance: EachUnboundInstanceProc] = {
currentPath: PackedPath ← NullPath;
UNTIL currentPath.length=path.length
DO
cellType: Core.CellType ← CoreOps.ToBasic[root];
rct: CoreClasses.RecordCellType ← NARROW [cellType.data];
pathBits: NAT ← BitHacks.NBits[rct.size];
instanceBits: PACKED ARRAY [0..16) OF BOOL ← ALL [FALSE];
instance: CoreClasses.CellInstance;
oldPath: PackedPath ← currentPath;
FOR bit:
NAT
IN [0..pathBits)
DO
instanceBits[16-pathBits+bit] ← path.bits[currentPath.length+bit];
currentPath.bits[currentPath.length+bit] ← path.bits[currentPath.length+bit];
ENDLOOP;
currentPath.length ← currentPath.length+pathBits;
instance ← rct[LOOPHOLE[instanceBits]];
root ← instance.type;
eachInstance[[oldPath, instance], cellType];
ENDLOOP;
};
BoundCellType:
PUBLIC
PROC [root: Core.CellType, path: PackedPath]
RETURNS [bindings: HashTable.Table, cellType: Core.CellType] = {
SetInnerCellType: EachBoundInstanceProc = {
innerCellType ← cellType;
};
innerCellType: Core.CellType ← root;
bindings ← VisitBoundPath[root, path, SetInnerCellType];
cellType ← innerCellType;
};
VisitBoundPath:
PUBLIC
PROC [root: Core.CellType, path: PackedPath, eachInstance: EachBoundInstanceProc]
RETURNS [bindings: HashTable.Table] = {
BindCellTypeAndInstance: EachUnboundInstanceProc = {
BindInternal[bindings, instance.path, cellType];
[bindings, innerCellType] ← BindInstance[instance.instance, bindings];
eachInstance[bindings, instance, cellType];
};
innerCellType: Core.CellType;
[bindings, innerCellType] ← InitializeBindings[root];
VisitUnboundPath[root, path, BindCellTypeAndInstance];
BindInternal[bindings, path, innerCellType];
};
EnumerateLeaves:
PUBLIC
PROC [root: Core.CellType, eachInstance: EachInstanceProc, rootCellType, beforeInstances, afterInstances: EachCellTypeProc ←
NIL] = {
VisitCellType:
PROC [bindings: HashTable.Table, path: PackedPath, parent: Core.CellType] = {
parentRCT: CoreClasses.RecordCellType ← NARROW[parent.data];
pathBits: NAT ← BitHacks.NBits[parentRCT.size];
BindInternal[bindings, path, parent];
IF beforeInstances#NIL THEN beforeInstances[bindings, path, parent];
FOR in:
NAT
IN [0..parentRCT.size)
DO
instance: CoreClasses.CellInstance ← parentRCT[in];
IF eachInstance[bindings, path, instance]
THEN {
newBindings: HashTable.Table;
child: Core.CellType;
[newBindings, child] ← BindInstance[instance, bindings];
VisitCellType[newBindings, ExtendPath[path, in, pathBits], child];
};
ENDLOOP;
IF afterInstances#NIL THEN afterInstances[bindings, path, parent];
};
bindings: HashTable.Table;
path: PackedPath ← NullPath;
rootRCT: Core.CellType;
[bindings, rootRCT] ← InitializeBindings[root];
IF rootCellType#NIL THEN rootCellType[bindings, path, rootRCT];
VisitCellType[bindings, path, rootRCT];
EnumerateAtomicWireLeaves:
PUBLIC
PROC [root: Core.CellType, rootWire: Core.Wire, eachInternalWire: EachInternalWireProc ←
NIL, eachWireInstance: EachWireInstanceProc ←
NIL] = {
FilterWire: EachCellTypeProc = {
FindWire: CoreOps.EachWireProc = {
bind: WireBind;
IF wire.size#0 THEN RETURN;
bind ← NARROW [HashTable.Fetch[table: bindings, key: wire].value];
IF (quit ← bind.wire=rootWire) THEN thisWire ← wire;
};
IF NOT CoreOps.VisitWire[NARROW [cellType.data, CoreClasses.RecordCellType].internal, FindWire] THEN ERROR;
IF eachInternalWire#NIL THEN eachInternalWire[bindings: bindings, path: path, cellType: cellType, wire: thisWire]
};
FilterInstance: EachInstanceProc = {
bound: BOOL ← CoreOps.RecursiveMember[wire: instance.actual, candidate: thisWire];
IF eachWireInstance#
NIL
AND bound
THEN flatten ← eachWireInstance[bindings: bindings, path: path, instance: instance, wire: thisWire]
ELSE {
IF bound
THEN {
cellType: Core.CellType ← CoreOps.ToBasic[instance.type];
flatten ← cellType.class#CoreClasses.transistorCellClass AND cellType.class#CoreClasses.unspecifiedCellClass;
}
ELSE flatten ← FALSE;
};
};
thisWire: Core.Wire;
IF rootWire.size#0 THEN ERROR;
EnumerateLeaves[root: root, beforeInstances: FilterWire, eachInstance: FilterInstance];
InitializeBindings:
PROC [root: Core.CellType]
RETURNS [bindings: HashTable.Table, rootRCT: Core.CellType] = {
InsertBindings: CoreOps.EachWireProc = {
[] ← HashTable.Store[
table: bindings, key: wire,
value: NEW [WireBindRec ← [path: NullPath, wire: wire]]
];
};
rootRCT ← CoreOps.ToBasic[root];
bindings ← HashTable.Create[rootRCT.public.size+1];
FOR i:
NAT
IN [0..rootRCT.public.size)
DO
IF CoreOps.VisitWire[wire: rootRCT.public[i], eachWire: InsertBindings] THEN ERROR;
ENDLOOP;
BindInternal:
PROC [bindings: HashTable.Table, path: PackedPath, cellType: Core.CellType] = {
InsertBindings: CoreOps.EachWireProc = {
wireBind: WireBind ← NARROW [HashTable.Fetch[table: bindings, key: wire].value];
IF wireBind=
NIL
THEN [] ← HashTable.Store[
table: bindings, key: wire,
value: NEW [WireBindRec ← [path: path, wire: wire]]
];
};
internal: Core.Wire ← NARROW [cellType.data, CoreClasses.RecordCellType].internal;
FOR i:
NAT
IN [0..internal.size)
DO
IF CoreOps.VisitWire[wire: internal[i], eachWire: InsertBindings] THEN ERROR;
ENDLOOP;
};
BindInstance:
PROC [instance: CoreClasses.CellInstance, bindings: HashTable.Table]
RETURNS [newBindings: HashTable.Table, child: Core.CellType] = {
BindPublicToActual: CoreOps.EachWirePairProc = {
bind: WireBind ← NARROW [HashTable.Fetch[table: bindings, key: actualWire].value];
IF bind=NIL THEN ERROR;
[] ← HashTable.Store[table: newBindings, key: publicWire, value: bind];
};
actual: Core.Wire ← instance.actual;
child ← CoreOps.ToBasic[instance.type];
newBindings ← HashTable.Create[child.public.size+1];
FOR i:
NAT
IN [0..actual.size)
DO
IF CoreOps.VisitBinding[actual: actual[i], public: child.public[i], eachWirePair: BindPublicToActual] THEN ERROR;
ENDLOOP;
};
Paths
FindPath:
PUBLIC
PROC [root: Core.CellType, pathRope:
ROPE]
RETURNS [path: PackedPath] = {
token: ROPE;
ts: IO.STREAM;
firstChar: CHAR;
tokenKind: IO.TokenKind;
within: Core.CellType;
[path, token, ts, firstChar, tokenKind, within] ← ParseFullPath[root, pathRope];
CheckNoMore[ts, firstChar, tokenKind];
};
PathRope:
PUBLIC
PROC [root: Core.CellType, path: PackedPath]
RETURNS [pathRope:
ROPE ←
NIL] = {
AppendName: EachUnboundInstanceProc = {
coreInstance: CoreClasses.CellInstance ← instance.instance;
name: ROPE ← CoreClasses.GetCellInstanceName[coreInstance];
IF name=
NIL
THEN {
cellTypeName: ROPE ← CoreOps.GetCellTypeName[coreInstance.type];
name ← Convert.RopeFromInt[InstanceIndex[cellType, coreInstance]];
IF cellTypeName#NIL THEN name ← Rope.Cat[name, "(", cellTypeName, ")"];
};
pathRope ← Rope.Cat[pathRope, "/", name];
};
VisitUnboundPath[root, path, AppendName];
};
PathEqual:
PUBLIC
PROC [one: PackedPath, other: PackedPath]
RETURNS [equal:
BOOL] = {
oneBits: INT ← LOOPHOLE[one.bits];
otherBits: 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;
};
PathHash:
PUBLIC
PROC [path: PackedPath]
RETURNS [hash:
CARDINAL] =
TRUSTED {
pathAsLN: Basics.LongNumber ← Basics.SwapHalves[LOOPHOLE[path.bits]];
pathAsLN ← Basics.DoubleShiftRight[pathAsLN, 32-path.length];
hash ← Basics.BITXOR[pathAsLN.lowbits, pathAsLN.highbits];
};
ComputePackedPath:
PUBLIC
PROC [root: Core.CellType, instantiationPath: InstantiationPath]
RETURNS [path: PackedPath] = {
path.length ← 0;
instantiationPath ← CoreClasses.ReverseCellInstances[instantiationPath];
FOR instPath: InstantiationPath ← instantiationPath, instPath.rest
UNTIL instPath=
NIL
DO
rc: Core.CellType ← CoreOps.ToBasic[root];
rct: CoreClasses.RecordCellType ← NARROW[rc.data];
FOR in:
NAT
IN [0..rct.size)
DO
IF rct[in]=instPath.first
THEN {
pathBits: NAT ← BitHacks.NBits[rct.size];
path ← ExtendPath[path, in, pathBits];
root ← rct[in].type;
EXIT;
};
REPEAT
FINISHED => ERROR;
ENDLOOP;
ENDLOOP;
};
Instances
FindInstance:
PUBLIC
PROC [root: Core.CellType, instancePathRope:
ROPE]
RETURNS [instance: FlatInstanceRec] = {
within: Core.CellType;
token: ROPE;
ts: IO.STREAM;
firstChar: CHAR;
tokenKind: IO.TokenKind;
[instance.path, instance.instance, within, token, ts, firstChar, tokenKind] ← ParseInstancePath[root, instancePathRope];
CheckNoMore[ts, firstChar, tokenKind];
};
InstancePathRope:
PUBLIC
PROC [root: Core.CellType, instance: FlatInstanceRec]
RETURNS [instancePathRope:
ROPE] = {
pathWithInstance: PackedPath ← AddInstance[instance.path, instance.instance, GetCellType[root, instance.path]];
instancePathRope ← PathRope[root, pathWithInstance];
};
FlatInstanceEqual:
PUBLIC
PROC [one, other:
REF
ANY
-- FlatInstance --]
RETURNS [equal:
BOOL] = {
equal ← FlatInstanceEqualRec[NARROW[one, FlatInstance]^, NARROW[other, FlatInstance]^];
};
FlatInstanceEqualRec:
PUBLIC
PROC [one, other: FlatInstanceRec]
RETURNS [equal:
BOOL] = {
equal ← PathEqual[one.path, other.path] AND one.instance=other.instance;
};
FlatInstanceHash:
PUBLIC
PROC [instance:
REF
ANY
-- FlatInstance --]
RETURNS [hash:
CARDINAL] = {
hash ← FlatInstanceHashRec[NARROW[instance, FlatInstance]^];
};
FlatInstanceHashRec:
PUBLIC
PROC [instance: FlatInstanceRec]
RETURNS [hash:
CARDINAL] = {
hash ← PathHash[instance.path];
hash ← Basics.BITXOR[hash, Basics.LowHalf[LOOPHOLE[instance.instance]]];
hash ← Basics.BITXOR[hash, Basics.HighHalf[LOOPHOLE[instance.instance]]];
};
Wires
FindWire:
PUBLIC
PROC [root: Core.CellType, wirePathRope:
ROPE]
RETURNS [wire: FlatWireRec, wireRoot: WireRoot] = {
AppendNameWire:
PROC = {
state ← sawWireNameOrNumber;
IF RootWire[]#none THEN MakeError["Cannot name a wire actual, internal, or public"];
FOR subWire:
CARDINAL
IN [0..wire.wire.size)
DO
IF Rope.Equal[token, CoreOps.GetShortWireName[wire.wire[subWire]]]
THEN {
wire.wire ← wire.wire[subWire];
EXIT;
};
REPEAT FINISHED => MakeError["Can't find wire"];
ENDLOOP;
};
AppendNumberWire:
PROC = {
parent: Core.Wire ← IF wire.wire=NIL THEN NARROW[CoreOps.ToBasic[within].data, CoreClasses.RecordCellType].internal ELSE wire.wire;
subWire: CARDINAL ← Convert.CardFromRope[token];
IF subWire>=parent.size THEN MakeError["No such wire"];
wire.wire ← parent[subWire];
};
PossibleRootWire:
PROC = {
wireType: RootWireType ← RootWire[];
SELECT wireType
FROM
public => {
state ← sawWireRoot;
wire.wire ← within.public;
wireRoot ← public;
};
internal => {
rct: CoreClasses.RecordCellType ← NARROW[CoreOps.ToBasic[within].data];
state ← sawWireRoot;
wire.wire ← rct.internal;
wireRoot ← internal;
};
actual => {
MakeError["Visiting actual not implemented"];
};
none => {
wire.wire ← NARROW[CoreOps.ToBasic[within].data, CoreClasses.RecordCellType].internal;
AppendNameWire[];
wireRoot ← internal;
};
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];
};
WirePath ::= {start} ?((PUBLIC | INTERNAL | ACTUAL ) {sawWireRoot} . {expectWireNameOrNumber} ) (( Name | Number ) {sawWireNameOrNumber} ?( . {expectWireNameOrNumber})) | ( [ {sawLeft} Number {sawNumber} ] {sawRight} )
WirePathParseStates: TYPE = {start, expectMaybeRoot, sawWireRoot, expectWireNameOrNumber, sawWireNameOrNumber, sawLeft, sawNumber, sawRight};
token: ROPE;
ts: IO.STREAM;
firstChar: CHAR;
tokenKind: IO.TokenKind;
within: Core.CellType;
state: WirePathParseStates ← start;
[wire.path, token, ts, firstChar, tokenKind, within] ← ParseFullPath[root, wirePathRope];
DO
SELECT state
FROM
start =>
SELECT tokenKind
FROM
tokenSINGLE =>
SELECT firstChar
FROM
'[ => state ← sawLeft;
'. => state ← expectMaybeRoot;
ENDCASE => MakeError[];
tokenID => PossibleRootWire[];
tokenDECIMAL => {AppendNumberWire[]; state ← sawWireNameOrNumber};
ENDCASE => MakeError[];
expectMaybeRoot =>
SELECT tokenKind
FROM
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;
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 ← sawLeft;
ENDCASE => MakeError[];
tokenID => AppendNameWire[];
tokenDECIMAL => {AppendNumberWire[]; state ← sawWireNameOrNumber};
ENDCASE => MakeError[];
ENDCASE => MakeError[];
[token, firstChar, tokenKind] ← ParseToken[ts ! IO.EndOfStream => EXIT];
ENDLOOP;
IF state=sawWireRoot OR state=expectWireNameOrNumber OR state=sawLeft OR state=sawNumber THEN MakeError[];
};
WirePathRope:
PUBLIC
PROC [root: Core.CellType, wire: FlatWireRec, wireRoot: WireRoot ← internal]
RETURNS [wirePathRope:
ROPE] = {
rootWire: Core.Wire;
pathRope: ROPE;
SELECT wireRoot
FROM
public => {
SetContainerCell: EachUnboundInstanceProc = {
containerCell ← instance.instance.type;
};
containerCell: Core.CellType ← root;
VisitUnboundPath[root, wire.path, SetContainerCell];
rootWire ← containerCell.public;
};
internal => rootWire ← NARROW[CoreOps.ToBasic[GetCellType[root, wire.path]].data, CoreClasses.RecordCellType].internal;
actual => ERROR; -- not implemented
ENDCASE => ERROR;
pathRope ← PathRope[root, wire.path];
IF NOT Rope.IsEmpty[pathRope] THEN pathRope ← Rope.Cat[pathRope, "."];
wirePathRope ← Rope.Cat[pathRope, SELECT wireRoot FROM public => "public.", internal => "internal.", actual => "actual.", ENDCASE => ERROR, CoreOps.GetFullWireNames[rootWire, wire.wire].first];
};
FlatWireEqual:
PUBLIC
PROC [one, other:
REF
ANY
-- FlatWire --]
RETURNS [equal:
BOOL] = {
equal ← FlatWireEqualRec[NARROW[one, FlatWire]^, NARROW[other, FlatWire]^];
};
FlatWireEqualRec:
PUBLIC
PROC [one, other: FlatWireRec]
RETURNS [equal:
BOOL] = {
equal ← PathEqual[one.path, other.path] AND one.wire=other.wire;
};
FlatWireHash:
PUBLIC
PROC [wire:
REF
ANY
-- FlatWire --]
RETURNS [hash:
CARDINAL] = {
hash ← FlatWireHashRec[NARROW[wire, FlatWire]^];
};
FlatWireHashRec:
PUBLIC
PROC [wire: FlatWireRec]
RETURNS [hash:
CARDINAL] =
TRUSTED {
hash ← PathHash[wire.path];
hash ← Basics.BITXOR[hash, Basics.LowHalf[LOOPHOLE[wire.wire]]];
hash ← Basics.BITXOR[hash, Basics.HighHalf[LOOPHOLE[wire.wire]]];
};
Utilities
InstanceIndex:
PROC [within: Core.CellType, instance: CoreClasses.CellInstance]
RETURNS [index:
NAT] = {
withinCT: Core.CellType ← CoreOps.ToBasic[within];
withinRCT: CoreClasses.RecordCellType ← NARROW[withinCT.data];
FOR index
IN [0..withinRCT.size)
DO
IF withinRCT[index]=instance THEN EXIT;
REPEAT FINISHED => ERROR;
ENDLOOP;
};
ParseFullPath:
PUBLIC
PROC [root: Core.CellType, pathRope:
ROPE]
RETURNS [path: PackedPath, token:
ROPE, ts:
IO.
STREAM, firstChar:
CHAR, tokenKind:
IO.TokenKind, within: Core.CellType] = {
instance: CoreClasses.CellInstance;
[path, instance, within, token, ts, firstChar, tokenKind] ← ParseInstancePath[root, pathRope];
path ← AddInstance[path, instance, within];
IF instance#NIL THEN within ← instance.type;
};
ParseInstancePath:
PROC [root: Core.CellType, pathRope:
ROPE]
RETURNS [path: PackedPath ← CoreFlat.NullPath, instance: CoreClasses.CellInstance ←
NIL, within: Core.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 ← NARROW[CoreOps.ToBasic[within].data];
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 ← NARROW[CoreOps.ToBasic[within].data];
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.GetCellTypeName[instance.type]] THEN MakeError[Rope.Cat["Incorrect cell type name ", token]];
state ← sawCellTypeName;
};
InstancePath ::= {start} / {expectInstanceNameOrNumber} ( Name | (Number {sawInstanceNumber} ?( ( {sawLeftParan} Name {sawCellTypeName} ) ) ) {sawInstanceNameOrNumber} )
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[];
};
AddInstance:
PUBLIC
PROC [currentPath: PackedPath, instance: CoreClasses.CellInstance, within: Core.CellType]
RETURNS [newPath: PackedPath] = {
newPath ← currentPath;
IF instance#
NIL
THEN {
withinCT: Core.CellType ← CoreOps.ToBasic[within];
withinRCT: CoreClasses.RecordCellType ← NARROW[withinCT.data];
index: NAT ← InstanceIndex[within, instance];
pathBits: NAT ← BitHacks.NBits[withinRCT.size];
newPath ← ExtendPath[currentPath, index, pathBits];
};
};
ExtendPath:
PROC [currentPath: PackedPath, index:
NAT, pathBits:
NAT]
RETURNS [newPath: PackedPath] = {
newPath ← currentPath;
FOR bit:
NAT
IN [0..pathBits)
DO
newPath.bits[newPath.length+bit] ← BitHacks.XthBitOfN[pathBits-bit-1, index];
ENDLOOP;
newPath.length ← newPath.length + pathBits;
};
CheckNoMore:
PROC [ts:
IO.
STREAM, firstChar:
CHAR, tokenKind:
IO.TokenKind] = {
token: ROPE;
IF tokenKind=tokenSINGLE AND firstChar='. THEN [token, firstChar, tokenKind] ← ParseToken[ts ! IO.EndOfStream => {tokenKind ← tokenEOF; CONTINUE}];
IF tokenKind#tokenEOF THEN MakeError[];
};
MakeError:
PROC [m:
ROPE ←
NIL] = {
IF m=NIL THEN m ← "parse failed";
ERROR PathError[m];
};
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,
ENDCASE => other]
};