<> <> <> <> <> <> <> <> <> <> <> <> <; or OutputDir: [Ivy]; (default is local disk)>> <> <> <> DIRECTORY Ascii, Atom, Convert, FS, IO, IODefs, List, MPCDefs, ParserErrorDefs, PartitionDefs, RefText, MPCParserDefs, Rope; MPCParser: CEDAR PROGRAM IMPORTS Ascii, Atom, Convert, FS, IO, IODefs, List, MPCDefs, RefText, Rope EXPORTS MPCParserDefs = BEGIN OPEN MPCDefs; <> Line: REF TEXT _ NEW[TEXT[1000]]; LineCount: CARDINAL; Index: CARDINAL; Token: TYPE = RECORD [left, right: CARDINAL]; nullToken: Token = [1, 0]; DictEntry: TYPE = RECORD [name: Rope.ROPE, value: PROC]; CurrentDict: LIST OF DictEntry _ NIL; End: BOOL _ FALSE; Params: ARRAY [0..10) OF Token _ ALL[[0, 0]]; NParams: CARDINAL _ 0; ErrorCount: CARDINAL; Execute: BOOL; <> OutputDirectory: Rope.ROPE; InStream: IO.STREAM; InStreamCreated: BOOL; <> mpcDescriptor: REF MPCDescriptor; <> waferDescriptor: REF WaferDescriptor; <> chipDescriptor: REF ChipDescriptor; <> projectDescriptor: REF ProjectDescriptor; Scan: PUBLIC PROC [s: IO.STREAM, execute: BOOL] RETURNS [errorCount: CARDINAL] = <> BEGIN gotone, known: BOOL; token: Token; proc: PROC; InStream _ s; InStreamCreated _ FALSE; Execute _ execute; ErrorCount _ 0; --do it here because initscanner called at end InitScanner[]; UNTIL End DO IF InStream.EndOf[] --force END THEN BEGIN Line.length _ Index _ 0; Line _ RefText.AppendRope[Line, "end"]; END ELSE ReadLine[]; DO [gotone, token] _ ReadToken[]; IF ~gotone THEN EXIT; [known, proc] _ LookUp[token]; IF ~known THEN BEGIN Error["Unknown keyword", token]; Index _ Line.length; END ELSE BEGIN IF proc # Comment THEN ScanParams[]; proc[]; END; ENDLOOP; ENDLOOP; IF InStreamCreated THEN InStream.Close[]; RETURN[ErrorCount]; END; InitScanner: PROC = BEGIN LineCount _ 0; Line.length _ 0; Index _ 0; mpcDescriptor _ NEW[MPCDescriptor]; waferDescriptor _ NIL; chipDescriptor _ NIL; projectDescriptor _ NIL; CurrentDict _ TopDict; End _ FALSE; END; ReadLine: PROC = BEGIN <> ch: CHARACTER; Line.length _ Index _ 0; UNTIL InStream.EndOf[] DO ch _ InStream.GetChar[]; SELECT ch FROM Ascii.CR => BEGIN LineCount _ LineCount + 1; EXIT; END; Ascii.ESC => LOOP; Ascii.ControlZ => BEGIN UNTIL InStream.EndOf[] OR InStream.GetChar[] = Ascii.CR DO ENDLOOP; LineCount _ LineCount + 1; EXIT; END; ENDCASE => BEGIN IF Line.length < Line.maxLength THEN BEGIN Line _ RefText.AppendChar[Line, ch]; IF ch = '; OR ch = ', THEN EXIT; END ELSE BEGIN Error["Line too long", nullToken]; --boo UNTIL InStream.EndOf[] OR (ch _ InStream.GetChar[]) = '; DO IF ch = Ascii.CR THEN BEGIN LineCount _ LineCount + 1; EXIT; END; ENDLOOP; END; END; ENDLOOP; END; Error: PROC [s: Rope.ROPE, t: Token] = BEGIN IODefs.WriteString["*** Error in line "]; IODefs.WriteDecimal[LineCount]; IODefs.WriteString[" - "]; IODefs.WriteLine[s]; IODefs.WriteLine[Rope.FromRefText[Line]]; IF t.left <= t.right THEN BEGIN i: CARDINAL; FOR i IN [0..t.left) DO IODefs.WriteChar[IF Line[i] = Ascii.TAB THEN Ascii.TAB ELSE Ascii.SP]; ENDLOOP; IODefs.WriteLine["^"]; END; ErrorCount _ ErrorCount + 1; END; ReadToken: PROC RETURNS [GotOne: BOOL, t: Token] = BEGIN left: CARDINAL; IF Index >= Line.length THEN RETURN[FALSE, nullToken]; UNTIL ~Delim[Line[Index]] DO Index _ Index + 1; IF Index >= Line.length THEN RETURN[FALSE, nullToken]; ENDLOOP; left _ Index; DO Index _ Index + 1; IF Index >= Line.length OR Delim[Line[Index]] THEN RETURN[TRUE, [left, Index - 1]]; ENDLOOP; END; Delim: PROC [ch: CHARACTER] RETURNS [BOOL] = BEGIN RETURN[ch = Ascii.SP OR ch = Ascii.TAB OR ch = '; OR ch = ': OR ch = '= OR ch = ',]; END; LookUp: PROC [t: Token] RETURNS [known: BOOL, value: PROC] = BEGIN FOR d: LIST OF DictEntry _ CurrentDict, d.rest WHILE d#NIL DO IF d.first.name.Length = t.right-t.left+1 THEN FOR i: NAT IN [t.left..t.right] DO IF d.first.name.Fetch[i-t.left] # Ascii.Lower[Line[i]] THEN EXIT; REPEAT FINISHED => RETURN[TRUE, d.first.value]; ENDLOOP; ENDLOOP; RETURN[FALSE, NullProc]; END; TopDict: LIST OF DictEntry _ LIST [ ["chips", TChips], ["layers", TLayers], ["outputdir", TOutputDir], [ "inputfile", TInputFile], ["title", TTitle], ["date", TDate], ["account", TAccount], [ "maskset", TWafer], ["end", TEnd], ["comment", Comment]]; WaferDict: LIST OF DictEntry _ LIST [ ["resolution", WResolution], ["size", WSize], ["layers", WLayers], [ "chip", WChip], ["maskset", WWafer], ["end", WEnd], ["comment", Comment]]; ChipDict: LIST OF DictEntry _ LIST [ ["dimensions", CDimensions], ["positions", CPositions], ["project", CProject], ["chip", CChip], ["maskset", CWafer], ["end", CEnd], ["comment", Comment]]; ProjectDict: LIST OF DictEntry _ LIST [ ["rotation", PRotation], ["translation", PTranslation], [ "boundingbox", PBoundingBox], ["layers", PLayers], ["file", PFile], [ "project", PProject], ["chip", PChip], ["maskset", PWafer], ["end", PEnd], [ "comment", Comment]]; TChips: PROC = BEGIN DO IF NParams # 0 THEN BEGIN IF NParams = 1 THEN BEGIN mpcDescriptor.chips _ List.Union[LIST[Atom.MakeAtom[TokenToString[Params[0]]]], mpcDescriptor.chips]; END ELSE Error["ChipName expected", nullToken]; END; IF Line.length # 0 AND Line[Line.length - 1] = '; THEN EXIT; ReadLine[]; ScanParams[]; ENDLOOP; END; TLayers: PROC = BEGIN DO IF NParams # 0 THEN BEGIN IF NParams = 1 THEN BEGIN mpcDescriptor.layers _ List.Union[LIST[Atom.MakeAtom[TokenToString[Params[0]]]], mpcDescriptor.layers]; END ELSE Error["LayerName expected", nullToken]; END; IF Line.length # 0 AND Line[Line.length - 1] = '; THEN EXIT; ReadLine[]; ScanParams[]; ENDLOOP; END; TOutputDir: PROC = BEGIN OutputDirectory _ GetOneString["OutputDirectory"]; END; TInputFile: PROC = BEGIN IF NParams = 1 THEN BEGIN fileName: Rope.ROPE _ TokenToString[Params[0]]; BEGIN InStream _ FS.StreamOpen[fileName, $read ! FS.Error => GOTO ContinueThisFile]; InStreamCreated _ TRUE; LineCount _ 0; Line.length _ 0; EXITS ContinueThisFile => Error["Unknown file", Params[0]]; END; END ELSE Error["FileName expected", nullToken]; END; TTitle: PROC = BEGIN mpcDescriptor.title _ GetOneString["Title"]; END; TDate: PROC = BEGIN IF NParams = 1 THEN BEGIN IF TLength[Params[0]] = 6 THEN mpcDescriptor.date _ TokenToString[Params[0]] ELSE Error["Date must have 6 chars", Params[0]]; END ELSE Error["Date(6 chars) expected", nullToken]; END; TAccount: PROC = BEGIN mpcDescriptor.account _ GetOneString["AccountName"]; END; TWafer: PROC = BEGIN WWafer[]; IF Execute THEN IF ~InitMPC[mpcDescriptor] THEN Error["Error in call to InitMPC", nullToken]; END; TEnd: PROC = BEGIN InitScanner[]; --to clean up End _ TRUE; END; WResolution: PROC = BEGIN IF NParams = 1 THEN waferDescriptor.outputUnitsPerMicron _ TokenToDecimal[ Params[0] ! Convert.Error => BEGIN Error["Invalid number", Params[0]]; CONTINUE; END] ELSE Error["Number expected", nullToken]; END; WSize: PROC = BEGIN [waferDescriptor.waferSizeX, waferDescriptor.waferSizeY] _ GetTwoLongNumbers[]; END; WLayers: PROC = BEGIN DO IF NParams # 0 THEN BEGIN IF NParams = 3 AND TLength[Params[1]] = 2 AND TLength[Params[2]] = 2 THEN BEGIN AddLayerDef[TokenToString[Params[0]], TokenToString[Params[1]], TokenToString[Params[2]]]; END ELSE Error[ "IntermediateName LayerNumber(2 chars) LayerName(2 chars) expected", nullToken]; END; IF Line.length # 0 AND Line[Line.length - 1] = '; THEN EXIT; ReadLine[]; ScanParams[]; ENDLOOP; END; WChip: PROC = BEGIN CChip[]; IF Execute THEN IF ~InitWafer[waferDescriptor] THEN Error["Error in call to InitWafer", nullToken]; END; nextLayerNumber: PartitionDefs.layerNumber; WWafer: PROC = BEGIN waferDescriptor _ NEW[WaferDescriptor _ [inMPC: mpcDescriptor]]; nextLayerNumber _ 0; IF NParams = 1 THEN waferDescriptor.waferName _ TokenToString[Params[0]] ELSE Error["WaferName expected", nullToken]; CurrentDict _ WaferDict; END; WEnd: PROC = BEGIN IF Execute AND ~FinishMPC[] THEN Error["Error in FinishMPC", nullToken]; TEnd[]; END; CDimensions: PROC = BEGIN [chipDescriptor.chipSizeX, chipDescriptor.chipSizeY] _ GetTwoNumbers[]; END; CPositions: PROC = BEGIN DO IF NParams # 0 THEN BEGIN x, y: INT; [x, y] _ GetTwoLongNumbers[]; chipDescriptor.chipPositionList _ CONS[[x: x, y: y], chipDescriptor.chipPositionList]; END; IF Line.length # 0 AND Line[Line.length - 1] = '; THEN EXIT; --might be nice to reverse list ReadLine[]; ScanParams[]; ENDLOOP; END; CProject: PROC = BEGIN projectDescriptor _ NEW[ProjectDescriptor _ [inChip: chipDescriptor]]; IF NParams = 1 THEN projectDescriptor.projectID _ TokenToString[Params[0]] ELSE Error["ProjectName expected", nullToken]; IF Execute THEN IF ~InitChip[chipDescriptor] THEN Error["Error in call to InitChip", nullToken]; CurrentDict _ ProjectDict; END; CChip: PROC = BEGIN chipDescriptor _ NEW[ChipDescriptor _ [chipName: GetOneString["ChipName"], inWafer: waferDescriptor]]; CurrentDict _ ChipDict; <> IF mpcDescriptor.chips = NIL OR List.Memb[Atom.MakeAtom[chipDescriptor.chipName], mpcDescriptor.chips] OR List.Memb[$all, mpcDescriptor.chips] THEN RETURN; <> UNTIL InStream.EndOf[] DO gotone: BOOL; token: Token; ReadLine[]; [gotone, token] _ ReadToken[]; IF ~gotone THEN LOOP; IF TokenEqualsString[token, "chip"] OR TokenEqualsString[token, "maskset"] OR TokenEqualsString[token, "end"] THEN BEGIN Index _ 0; EXIT; END; ENDLOOP; END; CWafer: PROC = BEGIN IF Execute AND ~FinishWafer[] THEN Error["Error in FinishWafer", nullToken]; WWafer[]; END; CEnd: PROC = BEGIN IF Execute AND ~FinishWafer[] THEN Error["Error in FinishWafer", nullToken]; WEnd[]; END; PRotation: PROC = {[projectDescriptor.rotateX, projectDescriptor.rotateY] _ GetTwoLongNumbers[]}; PTranslation: PROC = {[projectDescriptor.translateX, projectDescriptor.translateY] _ GetTwoLongNumbers[]}; PBoundingBox: PROC = BEGIN [projectDescriptor.centerX, projectDescriptor.centerY, projectDescriptor.width, projectDescriptor.height] _ GetFourLongNumbers[]; END; PLayers: PROC = BEGIN DO IF NParams # 0 THEN BEGIN IF NParams = 3 AND TLength[Params[0]] <= 4 THEN BEGIN AddLayerUse[TokenToString[Params[0]], TokenToString[Params[1]], TokenToReal[Params[2]]]; END ELSE Error["CIFName IntermediateName Stretch expected", nullToken]; END; IF Line.length # 0 AND Line[Line.length - 1] = '; THEN EXIT; ReadLine[]; ScanParams[]; ENDLOOP; END; PFile: PROC = BEGIN IF NParams = 1 THEN projectDescriptor.cifFileName _ TokenToString[Params[0]] ELSE Error["FileName expected", nullToken]; END; PProject: PROC = BEGIN DoProject[]; projectDescriptor _ NEW[ProjectDescriptor _ [inChip: chipDescriptor]]; IF NParams = 1 THEN projectDescriptor.projectID _ TokenToString[Params[0]] ELSE Error["ProjectName expected", nullToken]; END; DoProject: PROC = BEGIN IF Execute THEN BEGIN ok: BOOL; errorSummary: ARRAY ParserErrorDefs.ErrorType OF CARDINAL; [ok, errorSummary] _ ConvertProject[projectDescriptor]; IF ~ok THEN Error["Error in call to ConvertProject", nullToken]; END; END; PChip: PROC = BEGIN EndChip[]; CChip[]; END; PWafer: PROC = BEGIN EndChip[]; CWafer[]; END; PEnd: PROC = BEGIN EndChip[]; CEnd[]; END; EndChip: PROC = BEGIN DoProject[]; IF Execute THEN WriteLayerFiles[]; IF Execute AND ~FinishChip[] THEN Error["Error in FinishChip", nullToken]; END; NullProc: PROC = BEGIN END; Comment: PROC = BEGIN --search for a '; UNTIL InStream.EndOf[] OR (Line.length # 0 AND Line[Line.length - 1] = ';) DO ReadLine[]; ENDLOOP; Index _ Line.length; END; ScanParams: PROC = BEGIN gotone: BOOL; token: Token; NParams _ 0; DO [gotone, token] _ ReadToken[]; IF gotone THEN BEGIN Params[NParams] _ token; NParams _ NParams + 1; END ELSE EXIT; ENDLOOP; END; TokenEqualsString: PROC [t: Token, s: Rope.ROPE] RETURNS [BOOL] = BEGIN RETURN[Rope.Equal[s1: TokenToString[t], s2: s, case: FALSE]]; END; TokenToString: PROC [t: Token] RETURNS [s: Rope.ROPE] = BEGIN tr: REF TEXT _ RefText.ObtainScratch[1000]; tr.length _ 0; tr _ RefText.Append[to: tr, from: Line, start: t.left, len: TLength[t]]; s _ Rope.FromRefText[tr]; RefText.ReleaseScratch[tr]; END; TLength: PROC [t: Token] RETURNS [CARDINAL] = BEGIN RETURN[t.right - t.left + 1]; END; TokenToDecimal: PROC [t: Token] RETURNS [INT] = { RETURN[Convert.IntFromRope[TokenToString[t]]] }; TokenToReal: PROC [t: Token] RETURNS [REAL] = BEGIN r: Rope.ROPE = TokenToString[t]; BEGIN ENABLE Convert.Error => GOTO TryIntegerStupid; RETURN[Convert.RealFromRope[r]]; EXITS TryIntegerStupid => RETURN[Convert.IntFromRope[r]]; END; END; GetTwoNumbers: PROC RETURNS [n1, n2: CARDINAL] = BEGIN n1 _ n2 _ 0; IF NParams = 2 THEN BEGIN n1 _ TokenToDecimal[ Params[0] ! Convert.Error => BEGIN Error["Invalid number", Params[0]]; CONTINUE; END]; n2 _ TokenToDecimal[ Params[1] ! Convert.Error => BEGIN Error["Invalid number", Params[1]]; CONTINUE; END]; END ELSE Error["Two Numbers expected", nullToken]; END; GetTwoLongNumbers: PROC RETURNS [n1, n2: INT] = BEGIN n1 _ n2 _ 0; IF NParams = 2 THEN BEGIN n1 _ TokenToDecimal[ Params[0] ! Convert.Error => BEGIN Error["Invalid number", Params[0]]; CONTINUE; END]; n2 _ TokenToDecimal[ Params[1] ! Convert.Error => BEGIN Error["Invalid number", Params[1]]; CONTINUE; END]; END ELSE Error["Two Numbers expected", nullToken]; END; GetFourLongNumbers: PROC RETURNS [n1, n2, n3, n4: INT] = BEGIN numbers: ARRAY [0..4) OF INT _ ALL[0]; i: CARDINAL; IF NParams = 4 THEN BEGIN FOR i IN [0..4) DO numbers[i] _ TokenToDecimal[Params[i] ! Convert.Error => BEGIN Error["Invalid number", Params[i]]; CONTINUE; END]; ENDLOOP; END ELSE Error["Four Numbers expected", nullToken]; RETURN[numbers[0], numbers[1], numbers[2], numbers[3]]; END; GetOneString: PROC [error: Rope.ROPE] RETURNS [into: Rope.ROPE] = BEGIN IF NParams = 1 THEN into _ TokenToString[Params[0]] ELSE Error[IO.PutFR["%g expected", IO.rope[error]], nullToken]; END; AddLayerDef: PROC [intname, layerNumber, layerName: Rope.ROPE] = BEGIN intAtom: ATOM _ Atom.MakeAtom[intname]; IF waferDescriptor.layerFileList.GetPropFromList[intAtom] # NIL THEN Error["Layer redefined - overwritten", nullToken]; waferDescriptor.layerFileList _ waferDescriptor.layerFileList.PutPropOnList[intAtom, NEW[LayerFileItemRec _ [ intName: intAtom, layerNumber: layerNumber, layerName: layerName, pFileLayer: nextLayerNumber, include: mpcDescriptor.layers=NIL OR List.Memb[intAtom, mpcDescriptor.layers] OR List.Memb[$all, mpcDescriptor.layers]]]]; nextLayerNumber _ nextLayerNumber+1; END; AddLayerUse: PROC [cifname, intname: Rope.ROPE, stretch: REAL] = BEGIN cifNameAtom: ATOM = Atom.MakeAtom[cifname]; intNameAtom: ATOM = Atom.MakeAtom[intname]; r: REF ANY; IF (r _ waferDescriptor.layerFileList.GetPropFromList[intNameAtom]) # NIL THEN BEGIN q: REF ANY; group: LayerGroup; WHILE (q _ NARROW[projectDescriptor.layerMap.GetPropFromList[cifNameAtom]]) = NIL DO projectDescriptor.layerMap _ projectDescriptor.layerMap.PutPropOnList[ prop: cifNameAtom, val: NEW[LayerGroupRec _ [cifName: cifNameAtom, maskLayers: NIL]]]; ENDLOOP; group _ NARROW[q]; group.maskLayers _ group.maskLayers.PutPropOnList[ prop: intNameAtom, val: NEW[LayerAssocRec _ [ fromLayer: cifNameAtom, toLayer: NARROW[r], stretch: stretch]]]; END ELSE Error["Unspecified layername", Params[1]]; END; WriteLayerFiles: PROC = BEGIN --Write included layers for this project FOR pl: Atom.PropList _ waferDescriptor.layerFileList, pl.rest WHILE pl#NIL DO WITH pl.first.val SELECT FROM lfi: LayerFileItem => IF lfi.include THEN [] _ WriteLayerFile[lfi, chipDescriptor]; ENDCASE => ERROR; ENDLOOP; END; END.