MPCParser:
CEDAR
PROGRAM
IMPORTS
Ascii, Atom, Convert, FS, IO, IODefs, List, MPCDefs, RefText, Rope
EXPORTS MPCParserDefs =
BEGIN
Types and global stuff
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;
Top level parameters
OutputDirectory: Rope.
ROPE;
InStream: IO.STREAM;
InStreamCreated: BOOL;
MPC-level descriptor
mpcDescriptor: REF MPCDescriptor;
Wafer level parameters
waferDescriptor: REF WaferDescriptor;
Chip level parameters
chipDescriptor: REF ChipDescriptor;
Project level parameters
projectDescriptor: REF ProjectDescriptor;
Scan:
PUBLIC
PROC [s:
IO.
STREAM, execute:
BOOL]
RETURNS [errorCount: CARDINAL] =
Scan MPC document on stream s, executing it if requested
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
Read line up to CR ', or '; - CR is discarded, '; and ', are included
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;
check whether to process this chip
IF mpcDescriptor.chips =
NIL
OR List.Memb[Atom.MakeAtom[chipDescriptor.chipName], mpcDescriptor.chips]
OR List.Memb[$all, mpcDescriptor.chips] THEN RETURN;
not to be processed - skip to end
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.