EDIFParsing.Mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Spreitzer, January 30, 1986 5:06:09 pm PST
DIRECTORY Atom, BasicTime, Convert, CoreOps2, EDIFAndCore, EDIFAndCorePrivate, HashTable, IO, Rope;
EDIFParsing: CEDAR PROGRAM
IMPORTS Atom, BasicTime, CoreOps2, EDIFAndCorePrivate, HashTable, IO, Rope
EXPORTS EDIFAndCore, EDIFAndCorePrivate
= {OPEN CO2: CoreOps2, EDIFAndCore, EDIFAndCorePrivate;
Error: PUBLIC ERROR [msg: ROPE] = CODE;
Warning: PUBLIC SIGNAL [msg: ROPE] = CODE;
EDIFFromStream: PUBLIC PROC [from: IO.STREAM] RETURNS [ew: EDIFWhole] = {
me: ROPE = "EDIF file";
lexed: LORA = LexEDIF[from];
stdTail: StdTail ← [];
ec: EDIFConversion = NEW [EDIFConversionPrivate ← [
rawDesigns: HashTable.Create[equal: HashTable.RopeEqualModCase, hash: HashTable.HashRopeModCase],
rawLibraries: HashTable.Create[equal: HashTable.RopeEqualModCase, hash: HashTable.HashRopeModCase],
ew: NIL]];
AddRaw: PROC [table: HashTable.Table, part: LORA, kind: ATOM] = {
me: ROPE = IO.PutFR["%g in EDIF file", [atom[kind]]];
atom: ATOM;
CheckLength[part, me, 2];
CheckHead[part, kind, me];
atom ← ToATOM[part.rest.first, me.Concat[" has bad name"]];
[] ← table.Insert[Atom.GetPName[atom], part];
};
DefineLibrary: PROC [key, value: REF ANY] RETURNS [quit: BOOLEANFALSE] --HashTable.EachPairAction-- = {
name: ROPE = NARROW[key];
lexed: LORA = NARROW[value];
[] ← GetLibrary[ec, name, "ERROR"];
};
DefineDesign: PROC [key, value: REF ANY] RETURNS [quit: BOOLEANFALSE] --HashTable.EachPairAction-- = {
name: ROPE = NARROW[key];
lexed: LORA = NARROW[value];
[] ← GetDesign[ec, name, "ERROR"];
};
CheckLength[lexed, me, 3];
CheckHead[lexed, $edif, me];
ec.ew ← ew ← NEW [EDIFWholePrivate ← [
name: [Atom.GetPName[ToATOM[lexed.rest.first, "Bad EDIFFileName"]]],
status: ParseStatus[lexed.rest.rest.first, me],
designs: HashTable.Create[equal: HashTable.RopeEqualModCase, hash: HashTable.HashRopeModCase],
libraries: HashTable.Create[equal: HashTable.RopeEqualModCase, hash: HashTable.HashRopeModCase],
externalLibraries: HashTable.Create[equal: HashTable.RopeEqualModCase, hash: HashTable.HashRopeModCase]
]];
IF ew.status.version # unspecifiedVersion AND ew.status.version # [1, 0, 0] THEN Warning[IO.PutFR["Seeing version %g.%g.%g stuff when version 1.0.0 expected", [integer[ew.status.version.major]], [integer[ew.status.version.medium]], [integer[ew.status.version.minor]] ]];
FOR rest: LORA ← lexed.rest.rest.rest, rest.rest WHILE rest # NIL DO
innerMe: ROPE = Rope.Cat["statement in ", me];
part: LORA = ToLORA[lexed.first, me.Cat[" contains a non-statement"]];
key: ATOM;
CheckLength[part, innerMe, 1];
key ← ToATOM[part.first, innerMe.Cat[" doesn't begin with a keyword"]];
SELECT LcA[key] FROM
$design => AddRaw[ec.rawDesigns, part, $design];
$library => AddRaw[ec.rawLibraries, part, $library];
$external => {
FOR pr: LORA ← part.rest, pr.rest WHILE pr # NIL DO
libName: ATOM = ToATOM[pr.first, "bad external library"];
[] ← ew.externalLibraries.Insert[Atom.GetPName[libName], $T];
ENDLOOP;
};
$comment => {
c: Comment = ParseComment[part, me];
[ew.comments, stdTail.c] ← CAppend[ew.comments, stdTail.c, c];
};
$userdata => {
ue: UserExtension = ParseUserExtension[part, me];
[ew.ues, stdTail.ues] ← UEAppend[ew.ues, stdTail.ues, ue];
};
ENDCASE => Error[IO.PutFR["%g statement found in %g", [atom[key]], [rope[me]] ]];
ENDLOOP;
[] ← ec.rawLibraries.Pairs[DefineLibrary];
[] ← ec.rawDesigns.Pairs[DefineDesign];
};
GetLibrary: PROC [ec: EDIFConversion, name, bitch: ROPE] RETURNS [l: Library] = {
raw: LORA;
l ← NARROW[ec.ew.libraries.Fetch[name].value];
IF l # NIL THEN RETURN;
raw ← NARROW[ec.rawLibraries.Fetch[name].value];
IF raw = NIL THEN Error[bitch];
l ← ParseLibrary[ec, name, raw];
IF NOT ec.ew.libraries.Insert[name, l] THEN ERROR;
};
GetDesign: PROC [ec: EDIFConversion, name, bitch: ROPE] RETURNS [d: Design] = {
raw: LORA;
d ← NARROW[ec.ew.designs.Fetch[name].value];
IF d # NIL THEN RETURN;
raw ← NARROW[ec.rawDesigns.Fetch[name].value];
IF raw = NIL THEN Error[bitch];
d ← ParseDesign[ec, name, raw];
IF NOT ec.ew.designs.Insert[name, d] THEN ERROR;
};
ParseLibrary: PROC [ec: EDIFConversion, name: ROPE, lexed: LORA] RETURNS [l: Library] = {
me: ROPE = Rope.Cat["Library ", name];
stdTail: StdTail ← [];
CheckLength[lexed, me, 2];
CheckHead[lexed, $library, me];
l ← NEW[LibraryPrivate ← [
name: [name],
cells: HashTable.Create[equal: HashTable.RopeEqualModCase, hash: HashTable.HashRopeModCase]
]];
FOR lexed ← lexed.rest.rest, lexed.rest WHILE lexed # NIL DO
innerMe: ROPE = Rope.Cat["statement in ", me];
part: LORA = ToLORA[lexed.first, me.Cat[" contains a non-statement"]];
key: ATOM;
CheckLength[part, innerMe, 1];
key ← ToATOM[part.first, innerMe.Cat[" doesn't begin with a keyword"]];
SELECT LcA[key] FROM
$status => {
IF l.status # NIL THEN Error[Rope.Cat["Multiple status specifications in ", me]];
l.status ← ParseStatus[part, me];
};
$technology => {
IF l.technology # NIL THEN Error[Rope.Cat["Multiple technologies in ", me]];
l.technology ← ParseTechnology[ec, part, me];
};
$cell => {
ct: CoreCellType = ParseCell[ec, part, me];
cellTypeName: ROPE = CO2.GetCellTypeName[ct];
IF NOT l.cells.Insert[cellTypeName, ct]
THEN Error[IO.PutFR["Multiple definitions of cell %g in library %g", [rope[cellTypeName]], [rope[name]] ]]
};
$comment => {
c: Comment = ParseComment[part, me];
[l.comments, stdTail.c] ← CAppend[l.comments, stdTail.c, c];
};
$userdata => {
ue: UserExtension = ParseUserExtension[part, me];
[l.ues, stdTail.ues] ← UEAppend[l.ues, stdTail.ues, ue];
};
ENDCASE => Error[IO.PutFR["%g statement found in %g", [atom[key]], [rope[me]] ]];
ENDLOOP;
ec ← ec;
};
ParseDesign: PROC [ec: EDIFConversion, name: ROPE, lexed: LORA] RETURNS [d: Design] = {
me: ROPE = Rope.Cat["design ", name];
stdTail: StdTail ← [];
q: Qual;
lib: Library;
root: CellType;
CheckLength[lexed, me, 3];
CheckHead[lexed, $design, me];
q ← ToQual[lexed.rest.rest.first, me.Concat[" has bad root cell"]];
lib ← GetLibrary[ec, q.outer, me.Cat[" wants non-existant library ", q.outer]];
root ← NARROW[lib.cells.Fetch[q.inner].value];
IF root = NIL THEN Error[IO.PutFR["%g wants non-existant cell %g from library %g", [rope[me]], [rope[q.inner]], [rope[q.outer]] ]];
d ← NEW[DesignPrivate ← [
name: [name],
rootCellType: root]];
FOR lexed ← lexed.rest.rest.rest, lexed.rest WHILE lexed # NIL DO
innerMe: ROPE = Rope.Cat["statement in ", me];
part: LORA = ToLORA[lexed.first, me.Cat[" contains a non-statement"]];
key: ATOM;
CheckLength[part, innerMe, 1];
key ← ToATOM[part.first, innerMe.Cat[" doesn't begin with a keyword"]];
SELECT LcA[key] FROM
$comment => {
c: Comment = ParseComment[part, me];
[d.comments, stdTail.c] ← CAppend[d.comments, stdTail.c, c];
};
$userdata => {
ue: UserExtension = ParseUserExtension[part, me];
[d.ues, stdTail.ues] ← UEAppend[d.ues, stdTail.ues, ue];
};
ENDCASE => Error[IO.PutFR["%g statement found in %g", [atom[key]], [rope[me]] ]];
ENDLOOP;
ec ← ec;
};
ParseStatus: PUBLIC PROC [lexedRA: REF ANY, context: ROPE] RETURNS [status: Status] = {
me: ROPE = Rope.Cat["Status block for ", context];
lexed: LORA ← ToLORA[lexedRA, me.Concat[" not a statement"]];
writtenTail: WrittenList ← NIL;
stdTail: StdTail ← [];
CheckLength[lexed, me, 1];
CheckHead[lexed, $status, me];
status ← NEW[StatusPrivate ← []];
FOR lexed ← lexed.rest, lexed.rest WHILE lexed # NIL DO
innerMe: ROPE = Rope.Cat["statement in ", me];
part: LORA = ToLORA[lexed.first, me.Cat[" contains a non-statement"]];
key: ATOM;
CheckLength[part, innerMe, 1];
key ← ToATOM[part.first, innerMe.Cat[" doesn't begin with a keyword"]];
SELECT LcA[key] FROM
$edifversion => {
IF status.version # unspecifiedVersion THEN Error[Rope.Cat["Multiple version specifications in ", me]];
status.version ← ParseVersion[part, me];
};
$ediflevel => {
IF status.level # unspecifiedLevel THEN Error[Rope.Cat["Multiple level specifications in ", me]];
status.level ← ParseLevel[part, me];
};
$written => {
w: Written = ParseWritten[part, me];
[status.writtens, writtenTail] ← WAppend[status.writtens, writtenTail, w];
};
$comment => {
c: Comment = ParseComment[part, me];
[status.comments, stdTail.c] ← CAppend[status.comments, stdTail.c, c];
};
$userdata => {
ue: UserExtension = ParseUserExtension[part, me];
[status.ues, stdTail.ues] ← UEAppend[status.ues, stdTail.ues, ue];
};
ENDCASE => Error[IO.PutFR["%g statement found in %g", [atom[key]], [rope[me]] ]];
ENDLOOP;
lexedRA ← lexedRA;
};
ParseVersion: PROC [lexedRA: REF ANY, context: ROPE] RETURNS [v: Version] = {
me: ROPE = Rope.Cat["version in ", context];
lexed: LORA ← ToLORA[lexedRA, me.Concat[" not a statement"]];
CheckLength[lexed, me, 4, 4];
CheckHead[lexed, $edifversion, me];
v.major ← ToINT[LFetch[lexed, 1], me.Concat[" contains bad major version"]];
v.medium ← ToINT[LFetch[lexed, 2], me.Concat[" contains bad medium version"]];
v.minor ← ToINT[LFetch[lexed, 3], me.Concat[" contains bad minor version"]];
lexedRA ← lexedRA;
};
ParseLevel: PROC [lexedRA: REF ANY, context: ROPE] RETURNS [l: Level] = {
me: ROPE = Rope.Cat["level in ", context];
lexed: LORA ← ToLORA[lexedRA, me.Concat[" not a statement"]];
CheckLength[lexed, me, 2, 2];
CheckHead[lexed, $ediflevel, me];
l ← ToINT[LFetch[lexed, 1], me.Concat[" contains bad number"], 0, 2];
lexedRA ← lexedRA;
};
WAppend: PROC [oldHead, oldTail: WrittenList, x: Written] RETURNS [newHead, newTail: WrittenList] = {
this: WrittenList = LIST[x];
IF oldHead = NIL
THEN newHead ← newTail ← this
ELSE {newHead ← oldHead; oldTail.rest ← newTail ← this};
};
ParseWritten: PROC [lexedRA: REF ANY, context: ROPE] RETURNS [w: Written] = {
me: ROPE = Rope.Cat["written in ", context];
lexed: LORA ← ToLORA[lexedRA, me.Concat[" not a statement"]];
accTail: AccountingList ← NIL;
stdTail: StdTail ← [];
CheckLength[lexed, me, 1];
CheckHead[lexed, $written, me];
w ← NEW[WrittenPrivate ← []];
FOR lexed ← lexed.rest, lexed.rest WHILE lexed # NIL DO
innerMe: ROPE = Rope.Cat["statement in ", me];
part: LORA = ToLORA[lexed.first, me.Cat[" contains a non-statement"]];
key: ATOM;
CheckLength[part, innerMe, 1];
key ← ToATOM[part.first, innerMe.Cat[" doesn't begin with a keyword"]];
SELECT LcA[key] FROM
$timestamp => {
IF w.time # BasicTime.nullGMT THEN Error[Rope.Cat["Multiple timestamps in ", me]];
w.time ← ParseTime[part, me];
};
$accounting => {
a: Accounting = ParseAccounting[part, me];
[w.accountings, accTail] ← AccAppend[w.accountings, accTail, a];
};
$comment => {
c: Comment = ParseComment[part, me];
[w.comments, stdTail.c] ← CAppend[w.comments, stdTail.c, c];
};
$userdata => {
ue: UserExtension = ParseUserExtension[part, me];
[w.ues, stdTail.ues] ← UEAppend[w.ues, stdTail.ues, ue];
};
ENDCASE => Error[IO.PutFR["%g statement found in %g", [atom[key]], [rope[me]] ]];
ENDLOOP;
lexedRA ← lexedRA;
};
ParseTime: PROC [lexedRA: REF ANY, context: ROPE] RETURNS [time: BasicTime.GMT] = {
me: ROPE = Rope.Cat["timestamp in ", context];
lexed: LORA ← ToLORA[lexedRA, me.Concat[" not a statement"]];
ut: BasicTime.Unpacked ← [zone: 0, dst: no];
CheckLength[lexed, me, 7, 7];
CheckHead[lexed, $timestamp, me];
ut.year ← ToINT[LFetch[lexed, 1], me.Concat[" contains bad year"], 1900, 2000];
ut.month ← VAL[CARDINAL[ToINT[LFetch[lexed, 2], me.Concat[" contains bad month"], 1, 12]-1]];
ut.day ← ToINT[LFetch[lexed, 3], me.Concat[" contains bad day"], 1, 31];
ut.hour ← ToINT[LFetch[lexed, 4], me.Concat[" contains bad hour"], 0, 23];
ut.minute ← ToINT[LFetch[lexed, 5], me.Concat[" contains bad minute"], 0, 59];
ut.second ← ToINT[LFetch[lexed, 6], me.Concat[" contains bad second"], 0, 59];
time ← BasicTime.Pack[ut];
lexedRA ← lexedRA;
};
AccAppend: PROC [oldHead, oldTail: AccountingList, x: Accounting] RETURNS [newHead, newTail: AccountingList] = {
this: AccountingList = LIST[x];
IF oldHead = NIL
THEN newHead ← newTail ← this
ELSE {newHead ← oldHead; oldTail.rest ← newTail ← this};
};
ParseAccounting: PROC [lexedRA: REF ANY, context: ROPE] RETURNS [a: Accounting] = {
me: ROPE = Rope.Cat["accounting in ", context];
lexed: LORA ← ToLORA[lexedRA, me.Concat[" not a statement"]];
CheckLength[lexed, me, 1, 2];
CheckHead[lexed, $accounting, me];
a ← NEW[AccountingPrivate ← [
name: ToATOM[lexed.rest.first, me.Concat[" has malformed name"]]
]];
FOR lexed ← lexed.rest.rest, lexed.rest WHILE lexed # NIL DO
part: ROPE = ToROPE[lexed.first, me.Cat[" contains a non-string"]];
a.data ← part;
ENDLOOP;
lexedRA ← lexedRA;
};
CAppend: PUBLIC PROC [oldHead, oldTail: Comments, x: Comment] RETURNS [newHead, newTail: Comments] = {
this: Comments = LIST[x];
IF oldHead = NIL
THEN newHead ← newTail ← this
ELSE {newHead ← oldHead; oldTail.rest ← newTail ← this};
};
ParseComment: PUBLIC PROC [lexedRA: REF ANY, context: ROPE] RETURNS [comment: Comment] = {
me: ROPE = Rope.Cat["comment in ", context];
lexed: LORA ← ToLORA[lexedRA, me.Concat[" not a statement"]];
tail: RopeList ← NIL;
CheckLength[lexed, me, 1];
CheckHead[lexed, $comment, me];
FOR lexed ← lexed, lexed.rest WHILE lexed # NIL DO
innerMe: ROPE = Rope.Cat["form in ", me];
c: ROPE = ToROPE[lexed.first, me.Cat[" contains a non-string"]];
[comment, tail] ← RAppend[comment, tail, c];
ENDLOOP;
lexedRA ← lexedRA;
};
RAppend: PROC [oldHead, oldTail: RopeList, x: ROPE] RETURNS [newHead, newTail: RopeList] = {
this: RopeList = LIST[x];
IF oldHead = NIL
THEN newHead ← newTail ← this
ELSE {newHead ← oldHead; oldTail.rest ← newTail ← this};
};
UEAppend: PUBLIC PROC [oldHead, oldTail: LIST OF UserExtension, x: UserExtension] RETURNS [newHead, newTail: LIST OF UserExtension] = {
this: LIST OF UserExtension = LIST[x];
IF oldHead = NIL
THEN newHead ← newTail ← this
ELSE {newHead ← oldHead; oldTail.rest ← newTail ← this};
};
ParseUserExtension: PUBLIC PROC [lexedRA: REF ANY, context: ROPE] RETURNS [ue: UserExtension] = {
me: ROPE = Rope.Cat["user extension in ", context];
lexed: LORA ← ToLORA[lexedRA, me.Concat[" not a statement"]];
name: ATOM;
tail: LORANIL;
CheckLength[lexed, me, 2];
CheckHead[lexed, $userdata, me];
name ← ToATOM[lexed.rest.first, me.Concat[" doesn't have a proper name"]];
ue ← [name: [Atom.GetPName[name]], stuff: lexed.rest.rest];
};
CheckLength: PUBLIC PROC [lora: LORA, context: ROPE, min: INT ← 0, max: INTLAST[INT]] = {
lim: INT = IF max = LAST[INT] THEN min ELSE (max+1);
SELECT Length[lora, lim] FROM
< min => Error[IO.PutFR["Too few forms in %g", [rope[context]] ]];
> max => Error[IO.PutFR["Too many forms in %g", [rope[context]] ]];
ENDCASE => NULL;
};
CheckHead: PUBLIC PROC [lexed: LORA, keyword: ATOM, context: ROPE] = {
msg: ROPE = IO.PutFR["%g does not begin with %g", [rope[context]], [atom[keyword]]];
IF LcA[ToATOM[lexed.first, msg]] # keyword THEN Error[msg];
};
Length: PUBLIC PROC [lora: LORA, max: INTLAST[INT]] RETURNS [length: INT] = {
length ← 0;
FOR lora ← lora, lora.rest WHILE lora # NIL AND length < max DO
length ← length + 1;
ENDLOOP;
length ← length;
};
LFetch: PUBLIC PROC [lora: LORA, index: NAT] RETURNS [ra: REF ANY] = {
WHILE index # 0 DO
lora ← lora.rest;
index ← index - 1;
ENDLOOP;
ra ← lora.first;
};
ToQual: PUBLIC PROC [ra: REF ANY, bitch: ROPE] RETURNS [q: Qual] = {
WITH ra SELECT FROM
lexed: LORA => {
CheckLength[lexed, bitch, 3, 3];
CheckHead[lexed, $qualify, bitch];
q.outer ← ToROPE[lexed.rest.first, bitch];
q.inner ← ToROPE[lexed.rest.rest.first, bitch];
};
ENDCASE => Error[bitch];
};
ToATOM: PUBLIC PROC [ra: REF ANY, bitch: ROPE] RETURNS [a: ATOM] = {
WITH ra SELECT FROM
x: ATOM => a ← x;
ENDCASE => Error[bitch];
};
ToLORA: PUBLIC PROC [ra: REF ANY, bitch: ROPE] RETURNS [lora: LORA] = {
WITH ra SELECT FROM
x: LORA => lora ← x;
ENDCASE => Error[bitch];
};
ToROPE: PUBLIC PROC [ra: REF ANY, bitch: ROPE] RETURNS [r: ROPE] = {
WITH ra SELECT FROM
x: ROPE => r ← x;
ENDCASE => Error[bitch];
};
ToINT: PUBLIC PROC [ra: REF ANY, bitch: ROPE, min: INTFIRST[INT], max: INTLAST[INT]] RETURNS [i: INT] = {
WITH ra SELECT FROM
x: REF INT => IF (i ← x^) NOT IN [min .. max] THEN Error[bitch];
ENDCASE => Error[bitch];
};
}.