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. 6File MPCParser.Mesa November 1979 by MN Updated: August 25, 1980 5:46 PM Updated by TRS to conform to new parser/interp December 5, 1980 5:19 PM Last Edited by: McCreight, January 28, 1985 6:22:45 pm PST This version is different from the MPC79 version in that calls to interpreter procedures pass pointers to descriptor records for the various objects. Also, the bounding boxes of projects are allowed for in the .mpc document Top level syntax is: Chips: A B C; or Chips: all; (default is all) Layers: diffusion poly; or Layers: all; (default is all) OutputDir: [Ivy]; or OutputDir: [Ivy]; (default is local disk) InputFile: MPC79.mpc; Only "InputFile" is mandatory and must come last lower case keywords are recognized Types and global stuff Top level parameters MPC-level descriptor Wafer level parameters Chip level parameters Project level parameters Scan MPC document on stream s, executing it if requested Read line up to CR ', or '; - CR is discarded, '; and ', are included check whether to process this chip not to be processed - skip to end Ê}˜J˜Jšœ™Jšœ™Jšœ!™!JšœH™HJšœ:™:J˜JšœA™AJšœB™BJšœB™BJšœ™J˜Jšœ™Jšœ0™0Jšœ;™;JšœH™HJšœ™J˜Jšœ0™0Jšœ"™"J˜šÏk ˜ JšœœœV˜rJ˜—šœ œ˜š˜Jšœœœ'˜C—Jšœ˜J˜Jš˜šœ ˜ J˜—Jšœ™Jš œœœœœ˜!Jšœ œ˜Jšœœ˜Jšœœœœ˜-J˜Jš œ œœ œ œ˜8Jšœ œœ œ˜%Jšœœœ˜Jšœœ œ œ ˜-Jšœ œ˜Jšœ œ˜Jšœ œ˜J˜Jšœ™šœœ˜J˜—Jšœ œœ˜Jšœœ˜J˜Jšœ™Jšœœ˜!J˜Jšœ™Jšœœ˜%J˜Jšœ™Jšœœ˜#J˜Jšœ™Jšœœ˜)J˜J˜š Ïnœœœœœ œ˜/Jšœœ˜ Jšœ8™8Jš˜Jšœœ˜J˜ Jšœœ˜ J˜J˜ Jšœœ˜J˜JšœÏc.˜?J˜šœ˜ šœŸ ˜ JšœœB˜O—Jšœ ˜š˜J˜Jšœ œœ˜J˜šœ˜Jšœ7˜?—Jš œœœœœ˜