<> <> <> <> <<>> <> <> <<>> DIRECTORY CIFParser USING [Point, Path, Transformation, Registration, TMatrix], Convert USING [IntFromRope, CardFromRope], IO USING [STREAM, GetTokenRope, CharClass], Real USING [Round, SqRt], Rope USING [ROPE, Cat, Concat, Length, Fetch, FromChar]; CIFParserImpl: CEDAR PROGRAM IMPORTS Convert, IO, Real, Rope EXPORTS CIFParser ~ BEGIN OPEN CIFParser; <> <> defaultInt: INT=LAST[INT]; defaultCard: CARD=LAST[CARD]; noPoint: Point = [defaultInt, defaultInt]; <> <> ROPE: TYPE ~ Rope.ROPE; <> CmdType: TYPE ~ {emptyCmd, endCmd, defDeleteCmd, defStartCmd, defFinishCmd, primCmd}; PrimCmdType: TYPE ~ {polygonCmd, boxCmd, roundFlashCmd, wireCmd, layerCmd, callCmd, userExtensionCmd, commentCmd, error}; Cmd: TYPE ~ RECORD[ type: CmdType _ primCmd, token: ROPE _ NIL ]; PrimCmd: TYPE ~ RECORD[ type: PrimCmdType _ error, token: ROPE _ NIL ]; State: TYPE ~ REF StateRec; StateRec: TYPE ~ RECORD[ layer: ROPE _ NIL, inSymbol: BOOLEAN _ FALSE ]; Stream: TYPE ~ REF StreamRec; StreamRec: TYPE ~ RECORD[lastToken: ROPE, s: IO.STREAM]; TokenKind: TYPE ~ {upperChar, digit, semicolon, leftPar, rightPar, blank}; <> emptyCmdNotOK: BOOLEAN _ FALSE; --it looks as if it was forbidden AND used... <> Error: PUBLIC ERROR [msg: ROPE, cifFile: IO.STREAM] ~ CODE; ClientError: PUBLIC ERROR [clientMsg: ROPE] ~ CODE; Parse: PUBLIC PROC [cifStream: IO.STREAM, reg: Registration] ~ { <> <> ENABLE ClientError => Error[Rope.Concat["client error: ", clientMsg], cifStream]; cifFile: Stream _ NEW[StreamRec _ [NIL, cifStream]]; cmd: Cmd; state: BOOLEAN _ FALSE; DO cmd _ GetCmd[cifFile]; SELECT cmd.type FROM endCmd => {CheckEnd[cifFile, state]; RETURN}; defDeleteCmd => state _ DefDelete[cifFile, reg, state]; defStartCmd => state _ DefStart[cifFile, reg, state]; defFinishCmd => state _ DefFinish[cifFile, reg, state]; primCmd => ParsePrim[cmd.token, cifFile, reg]; emptyCmd => IF emptyCmdNotOK THEN Error["empty cmd", cifFile.s]; ENDCASE => ERROR; -- CmdType def is not in sync with Parse GoToNextCmd[cifFile]; ENDLOOP; }; <<>> GetCmd: PROC [cifFile: Stream] RETURNS [cmd: Cmd] ~ { c: CHAR; c _ GetChar[cifFile]; cmd.token _ Rope.FromChar[c]; SELECT c FROM 'E => cmd.type _ endCmd; '; => cmd.type _ emptyCmd; 'D => { c _ GetChar[cifFile]; cmd.token _ Rope.Concat[cmd.token, Rope.FromChar[c]]; SELECT c FROM 'D => cmd.type _ defDeleteCmd; 'S => cmd.type _ defStartCmd; 'F => cmd.type _ defFinishCmd; ENDCASE => Error[Rope.Concat[cmd.token, " : invalid cmd "], cifFile.s]; }; ENDCASE => cmd.type _ primCmd; }; GoToNextCmd: PROC [cifFile: Stream] ~ { IF GetTokenKind[cifFile.lastToken]#semicolon THEN { cifFile.lastToken _ GetToken[cifFile]; IF GetTokenKind[cifFile.lastToken]#semicolon THEN Error["wrong cmd syntax", cifFile.s]; }; }; <> CheckEnd: PROC[cifFile: Stream, state: BOOLEAN] ~ { <> IF state THEN Error["E inside symbol def ", cifFile.s]; }; DefDelete: PROC[cifFile: Stream, reg: Registration, state: BOOLEAN] RETURNS[newState: BOOLEAN _ FALSE] ~ { <> index: CARD; IF state THEN Error["DD inside symbol def ", cifFile.s]; index _ GetCard[cifFile]; reg.defDelete[index, reg.data]; }; DefStart: PROC[cifFile: Stream, reg: Registration, state: BOOLEAN] RETURNS[newState: BOOLEAN _ TRUE] ~ { <> index, a, b: CARD; IF state THEN Error["DS inside symbol def ", cifFile.s]; index _ GetCard[cifFile]; a _ GetCardAfterSep[cifFile, TRUE]; b _ GetCardAfterSep[cifFile, TRUE]; reg.defStart[index, a, b, reg.data]; }; DefFinish: PROC[cifFile: Stream, reg: Registration, state: BOOLEAN] RETURNS[newState: BOOLEAN _ FALSE] ~ { <> IF NOT state THEN Error["DF outside symbol def ", cifFile.s]; reg.defFinish[reg.data]; }; ParsePrim: PROC [token: ROPE, cifFile: Stream, reg: Registration] ~ { <> type: PrimCmdType _ GetPrimType[token]; SELECT type FROM polygonCmd => Polygon[cifFile, reg]; boxCmd => Box[cifFile, reg]; roundFlashCmd => RoundFlash[cifFile, reg]; wireCmd => Wire[cifFile, reg]; layerCmd => Layer[cifFile, reg]; callCmd => Call[cifFile, reg]; userExtensionCmd => UserExtension[token, cifFile, reg]; commentCmd => Comment[token, cifFile, reg]; error => Error[Rope.Cat[token," is not a CIF cmd"], cifFile.s]; ENDCASE => ERROR; -- PrimCmdType def is not in sync with ParsePrim }; <<>> GetPrimType: PROC [token: ROPE] RETURNS [type: PrimCmdType] ~ { type _ SELECT Rope.Fetch[token] FROM 'P => polygonCmd, 'B => boxCmd, 'R => roundFlashCmd, 'W => wireCmd, 'L => layerCmd, 'C => callCmd, IN ['0..'9] => userExtensionCmd, '( => commentCmd, ENDCASE => error; }; <> Polygon: PROC[cifFile: Stream, reg: Registration] ~ { <> path: Path; path _ GetPath[cifFile]; reg.polygon[path, reg.data] }; Box: PROC[cifFile: Stream, reg: Registration] ~ { <> length, width: CARD; center, direction: Point; length _ GetCard[cifFile]; width _ GetCardAfterSep[cifFile]; center _ GetPointAfterSep[cifFile]; direction _ GetPointAfterSep[cifFile, TRUE]; IF direction=noPoint THEN direction _ [1, 0]; reg.box[length, width, center, direction, reg.data] }; RoundFlash: PROC[cifFile: Stream, reg: Registration] ~ { <> diameter: CARD; center: Point; diameter _ GetCard[cifFile]; center _ GetPointAfterSep[cifFile]; reg.roundFlash[diameter, center, reg.data] }; Wire: PROC[cifFile: Stream, reg: Registration] ~ { <> width: CARD; path: Path; width _ GetCard[cifFile]; path _ GetPathAfterSep[cifFile]; reg.wire[width, path, reg.data] }; Layer: PROC[cifFile: Stream, reg: Registration] ~ { <> shortname: ROPE; shortname _ GetShortName[cifFile]; reg.layer[shortname, reg.data] }; Call: PROC[cifFile: Stream, reg: Registration] ~ { <> symbol: CARD; transformation: Transformation; symbol _ GetCard[cifFile]; transformation _ GetTransformation[cifFile]; reg.call[symbol, transformation, reg.data] }; UserExtension: PROC[token: ROPE, cifFile: Stream, reg: Registration] ~ { <> digit: CARD; userText: ROPE; digit _ Convert.IntFromRope[token]; userText _ GetUserText[cifFile]; reg.userExtension[digit, userText, reg.data] }; Comment: PROC[token: ROPE, cifFile: Stream, reg: Registration] ~ { <> comment: ROPE; comment _ Rope.Cat[token, GetCommentText[cifFile]]; reg.comment[comment, reg.data] }; <> GetTransformation: PROC [cifFile: Stream] RETURNS [t: Transformation] ~ { <> transf: Transformation; t _ transf _ LIST[[translation, [0, 0]]]; DO SELECT GetChar[cifFile] FROM '; => RETURN[IF t.rest=NIL THEN t ELSE t.rest]; 'T => transf.rest _ LIST[[translation, GetPoint[cifFile]]]; 'R => transf.rest _ LIST[[rotation, GetPoint[cifFile]]]; 'M => SELECT GetChar[cifFile] FROM 'X => transf.rest _ LIST[[xSym, noPoint]]; 'Y => transf.rest _ LIST[[ySym, noPoint]]; ENDCASE => Error["incorrect Mirror Transformation", cifFile.s]; ENDCASE => Error["incorrect Transformation", cifFile.s]; transf _ transf.rest; ENDLOOP; }; <<>> GetPath: PROC [cifFile: Stream] RETURNS [path: Path] ~ { <> p: Path; p _ path _ LIST[GetPoint[cifFile]]; DO point: Point; point _ GetPointAfterSep[cifFile, TRUE]; IF point=noPoint THEN RETURN; p.rest _ LIST[point]; p _ p.rest; ENDLOOP; }; <<>> GetPathAfterSep: PROC [cifFile: Stream] RETURNS [path: Path] ~ { <> p: Path; p _ path _ LIST[GetPointAfterSep[cifFile]]; DO point: Point; point _ GetPointAfterSep[cifFile, TRUE]; IF point=noPoint THEN RETURN; p.rest _ LIST[point]; p _ p.rest; ENDLOOP; }; <<>> GetPoint: PROC [cifFile: Stream, mayBeDefaulted: BOOLEAN _ FALSE] RETURNS [point: Point] ~ { <> point.x _ GetInt[cifFile, mayBeDefaulted]; IF point.x=defaultInt THEN RETURN[noPoint]; point.y _ GetIntAfterSep[cifFile]; }; <<>> GetPointAfterSep: PROC [cifFile: Stream, mayBeDefaulted: BOOLEAN _ FALSE] RETURNS [point: Point] ~ { point.x _ GetIntAfterSep[cifFile, mayBeDefaulted]; IF point.x=defaultInt THEN RETURN[noPoint]; point.y _ GetIntAfterSep[cifFile]; }; <<>> GetInt: PROC [cifFile: Stream, mayBeDefaulted: BOOLEAN _ FALSE] RETURNS [i: INT _ defaultInt] ~ { <> <> token: ROPE; tokenKind: TokenKind _ GetTokenKind[cifFile.lastToken]; IF tokenKind=semicolon THEN IF mayBeDefaulted THEN RETURN ELSE Error["missing INT", cifFile.s]; token _ GetToken[cifFile]; tokenKind _ GetTokenKind[token]; SELECT tokenKind FROM digit => i _ Convert.IntFromRope[token]; upperChar => i _ Convert.IntFromRope[GetToken[cifFile]]; semicolon => IF mayBeDefaulted THEN RETURN ELSE Error["missing INT", cifFile.s]; ENDCASE => Error["wrong INT value", cifFile.s]; }; <<>> GetIntAfterSep: PROC [cifFile: Stream, mayBeDefaulted: BOOLEAN _ FALSE] RETURNS [i: INT _ defaultInt] ~ { <> <> token: ROPE; tokenKind: TokenKind _ GetTokenKind[cifFile.lastToken]; IF tokenKind=semicolon THEN IF mayBeDefaulted THEN RETURN ELSE Error["missing INT", cifFile.s]; token _ GetToken[cifFile]; tokenKind _ GetTokenKind[token]; SELECT tokenKind FROM digit => i _ Convert.IntFromRope[token]; upperChar => i _ GetInt[cifFile, mayBeDefaulted]; semicolon => IF mayBeDefaulted THEN RETURN ELSE Error["missing INT", cifFile.s]; ENDCASE => Error["wrong INT value", cifFile.s]; }; <<>> GetCard: PROC [cifFile: Stream, mayBeDefaulted: BOOLEAN _ FALSE] RETURNS [c: CARD _ defaultCard] ~ { <> <> token: ROPE; tokenKind: TokenKind _ GetTokenKind[cifFile.lastToken]; IF tokenKind=semicolon THEN IF mayBeDefaulted THEN RETURN ELSE Error["missing CARD", cifFile.s]; token _ GetToken[cifFile]; tokenKind _ GetTokenKind[token]; SELECT tokenKind FROM digit => c _ Convert.CardFromRope[token]; upperChar => c _ Convert.CardFromRope[GetToken[cifFile]]; semicolon => IF mayBeDefaulted THEN RETURN ELSE Error["missing CARD", cifFile.s]; ENDCASE => Error["wrong CARD value", cifFile.s]; }; <<>> GetCardAfterSep: PROC [cifFile: Stream, mayBeDefaulted: BOOLEAN _ FALSE] RETURNS [c: CARD _ defaultCard] ~ { <> <> token: ROPE; tokenKind: TokenKind _ GetTokenKind[cifFile.lastToken]; IF tokenKind=semicolon THEN IF mayBeDefaulted THEN RETURN ELSE Error["missing CARD", cifFile.s]; token _ GetToken[cifFile]; tokenKind _ GetTokenKind[token]; SELECT tokenKind FROM digit => c _ Convert.CardFromRope[token]; upperChar => c _ GetCard[cifFile, mayBeDefaulted]; semicolon => IF mayBeDefaulted THEN RETURN ELSE Error["missing CARD", cifFile.s]; ENDCASE => Error["wrong CARD value", cifFile.s]; }; <<>> GetShortName: PROC [cifFile: Stream] RETURNS [shortname: ROPE] ~ { <> <> shortname _ GetToken[cifFile]; IF Rope.Length[shortname]>4 THEN Error[Rope.Cat[shortname, "is a too long name"], cifFile.s]; }; <<>> GetUserText: PROC [cifFile: Stream] RETURNS [userText: ROPE] ~ { <> <> userText _ IO.GetTokenRope[cifFile.s, UserTextBreakProc].token; cifFile.lastToken _ userText; }; <<>> GetCommentText: PROC [cifFile: Stream] RETURNS [userText: ROPE _ NIL] ~ { <> <> token: ROPE; tokenKind: TokenKind _ blank; level: NAT _ 1; token _ IO.GetTokenRope[cifFile.s, CommentTextBreakProc].token; tokenKind _ GetTokenKind[token]; UNTIL level=0 AND tokenKind=semicolon DO userText _ Rope.Concat[userText, token]; IF tokenKind=leftPar THEN level _ level+1; IF tokenKind=rightPar THEN level _ level-1; token _ IO.GetTokenRope[cifFile.s, CommentTextBreakProc].token; tokenKind _ GetTokenKind[token]; ENDLOOP; cifFile.lastToken _ token; }; <<>> <> GetTokenKind: PROC [token: ROPE] RETURNS [tokenKind: TokenKind] ~ { <