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
DIRECTORY Basics, BitHacks, Convert, Core, CoreClasses, CoreFlat, CoreOps, HashTable, IO, Rope;
CoreFlatImpl: CEDAR PROGRAM
IMPORTS Basics, BitHacks, Convert, CoreClasses, CoreOps, HashTable, IO, Rope
EXPORTS CoreFlat
= BEGIN OPEN CoreFlat;
PathError: PUBLIC ERROR [msg: ROPENIL] = CODE;
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 BOOLALL [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: ROPENIL] = {
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: INTLOOPHOLE[one.bits];
otherBits: INTLOOPHOLE[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: BOOLFALSE;
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: ROPENIL] = {
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]
};
END.