<> <> <> 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: BOOLEAN _ FALSE] --HashTable.EachPairAction-- = { name: ROPE = NARROW[key]; lexed: LORA = NARROW[value]; [] _ GetLibrary[ec, name, "ERROR"]; }; DefineDesign: PROC [key, value: REF ANY] RETURNS [quit: BOOLEAN _ FALSE] --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: LORA _ NIL; 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: INT _ LAST[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: INT _ LAST[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: INT _ FIRST[INT], max: INT _ LAST[INT]] RETURNS [i: INT] = { WITH ra SELECT FROM x: REF INT => IF (i _ x^) NOT IN [min .. max] THEN Error[bitch]; ENDCASE => Error[bitch]; }; }.