%{
/* SccsId = "@(#)cif_parse.y 4.9 (TU-Delft) 04/14/92" */
/*
 *      Copyright 1990 by Delft University of Technology (DUT),
 *                      Delft, The Netherlands.
 * 
 *                        All Rights Reserved
 * 
 * Permission to use, copy, modify, and distribute this software and
 * its  documentation  without  fee,  is  hereby  granted  for  non-
 * commercial purposes  only,  provided  that  the  above  copyright
 * notice  appear  in all copies and that both that copyright notice
 * and this permission notice appear  in  supporting  documentation,
 * and  that the name of DUT not be used in advertising or publicity
 * pertaining to distribution  of  the  software  without  specific,
 * written prior permission.
 * 
 * THE DUT DISCLAIMS ALL WARRANTIES WITH REGARD  TO  THIS  SOFTWARE,
 * INCLUDING  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 * IN NO EVENT SHALL THE DUT BE LIABLE FOR ANY SPECIAL, INDIRECT  OR
 * CONSEQUENTIAL  DAMAGES  OR  ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION  OF  CONTRACT,
 * NEGLIGENCE  OR  OTHER  TORTIOUS  ACTION,  ARISING  OUT  OF  OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 * 
 * 
 * Author(s)         : T.G.R. van Leuken
 * Creation date     : 15-Sep-1988
 * Modified by       : S. de Graaf
 * Modification date : 20-Sep-1988
 * Modification date : 02-Aug-1990
 * Modification date : 18-Jan-1991
 * Modification date : 10-Dec-1991 (4.8)
 * 
 * 
 * Contact address:
 * 
 * 
 * Dimes Design and Test Centre     phone: + 31 (15) 78 1459
 * Delft University of Technology   fax:   + 31 (15) 62 3271
 * P.O. Box 5053 		    email: nelsis@dutentb.tudelft.nl
 * Feldmannweg 17, 2600 GB Delft    The Netherlands
 */
#include "extern.h"
#include "ctype.h"

#if NCF_RELEASE < 400
#undef CREATE
#define CREATE	UPDATE
#endif

	extern char userChar[];
	char AltCellname [1024];
	char Termname [1024];
	int Termx, Termy;
	char Termlayer [32];
	int Points[1024];
	int PointsIndex;
	int i;
	int mx,my;
	int rx,ry;
	int CurrentTransform[3][2];
	double resolution;
	double xval;
	int  doUserStartFlag = 0;
	char * find_alias ();
%}
%token INTEGER
%token SEMI
%token POLYGON
%token BOX
%token ROTATE
%token WIRE
%token LAYER
%token START
%token FINISH
%token DELETE
%token CALL
%token END
%token TRANS
%token MX
%token MY
%token SHORTNAME
%token ROUNDFLASH
%token USER
%%
program		: stats END
		;
stats		: /* E */ | stats stat
		;
stat		: wire    semi
		| start semi
		| finish semi
		| polygon semi
		| box semi
		| round semi
		| delete semi
		|  user semi
		| layer semi
		| call semi
		| error semi
		{ yyerrok; }
		| semi
		;
start		: START cellid
		{
			doStart($2,1,1);
		}
		| START cellid scale scale
		{
			doStart($2,$3,$4);
		}
		;
finish		: FINISH
		{
		    strcpy (AltCellname, "");
		    if (err_flag) {
			pr_exit (0204, 26, ms_name);
		    }

		    if (mod_key) {

			if (err_flag) {
			    append_tree (ms_name, &mod_tree);
			    tree_ptr -> errflag = 1;
			    close_files ();
			    dmCheckIn (mod_key, QUIT);
			}
			else {
			    write_info ();
			    close_files ();
			    dmCheckIn (mod_key, COMPLETE);
			}

			mod_key = NULL;
		        ini_mcbbox = ini_bbbox = 0;
		    }
		    rm_tree (tnam_tree);
		    rm_tree (inst_tree);
		    tnam_tree = inst_tree = NULL;
		}
		;
layer		: LAYER SHORTNAME
		{
			dolayer(yytext);
		}
		;
wire		: WIRE integer points
		{
		    w_width = $2;
		    w_x = 2 * Points[0];
		    w_y = 2 * Points[1];
		    for(int_ind = 2; int_ind <PointsIndex; int_ind++)
		       int_val[int_ind-2] = 2 * (Points[int_ind] - Points[int_ind-2]);
		    int_ind -= 2;
		    if (!err_flag && !s_mode)
		        proc_swire ();
		}
		;
polygon		: POLYGON points
		{
		    for(int_ind = 0 ; int_ind <PointsIndex;int_ind++)
		       int_val[int_ind] = 4 * Points[int_ind];
		    int_val[int_ind++] = 4 * Points[0];
		    int_val[int_ind++] = 4 * Points[1];
		    if (int_ind >= NOINTS)
			pr_exit (0137, 8, 0);

		    if (!err_flag && !s_mode)
		        proc_poly ();
		}
		;
call		: CALL cellid transforms
		{
			doCifCall ($2);
		}
		;
transforms	: /* E */ | transforms transform
		;
transform	: translate 
		| mirrorx 
		| mirrory 
		| rotate
		;
translate	: TRANS integer integer
		{
			TTranslate ($2, $3);
		}
		;
mirrorx		: MX
		{
			TMX ();
		}
		;
mirrory		: MY
		{
			TMY ();
		}
		;
rotate		: ROTATE integer integer
		{
			TRotate ($2, $3);
		}
		;
points		: /* E */ | points point
		;
point		: integer integer
		{
			Points[PointsIndex++]=$1;
			Points[PointsIndex++]=$2;
		}
		;
box 		: BOX integer integer integer integer
		{
			doBox ($2,$3,$4,$5,1,0);
		}
		| BOX integer integer integer integer integer integer
		{
			doBox ($2,$3,$4,$5,$6,$7);
		}
		;
round 		: ROUNDFLASH integer integer integer
		{
		    if ($4 <= 0)
			pr_exit (0214, 48, itoa ($4));

		    if (!err_flag && !s_mode)
		        proc_circ ($2, $3, $4 / 2, 0, 0, 360000, 32);
		}
		;
delete 		: DELETE cellid
		{
			deletecell ($2);
		}
		;
user 		: USER
		{
		    if (yylval == 9  && userChar[0] == ' ') {
			sscanf (userChar,"%s;",AltCellname);
			for (i=0;AltCellname[i] != '\0';i++)
			{
				if( !(
				(AltCellname[i] >= 'A' && AltCellname[i] <= 'Z') ||
				(AltCellname[i] >= 'a' && AltCellname[i] <= 'z') ||
				(AltCellname[i] >= '0' && AltCellname[i] <= '9') ||
				(AltCellname[i] >= '_' && AltCellname[i] <= '_')
				))
				{
					AltCellname[i] = '\0';
					break;
				}
			}
			doUserStart (AltCellname);
		    }
		    else if (yylval == 9  && userChar[0] == '4') {
			sscanf (userChar,"4%s%d%d%s;",Termname,&Termx,&Termy,Termlayer);
			doUserTerm (Termname,Termx,Termy,Termlayer);
		    }
		    else
			P_E "%s: %d: USER: NOT YET IMPLEMENTED (%d%s)\n",
			    argv0, yylineno, yylval, userChar);
		}
		;
cellid		: INTEGER
		{
		    $$ = yylval;
		}
		;
integer		: INTEGER
		{
		    xval = yylval * resolution;
		    $$ = i = xval;
		    if ((double)i != xval)
			P_E "%s: %d: warning: integer truncation: %g => %d\n",
			    argv0, yylineno, xval, i);
		}
		;
scale		: INTEGER
		{
		    $$ = yylval;
		}
		;
semi		: SEMI
		{
		    PointsIndex = 0;
		    tx = 0; ty = 0;
		    mx = 0; my = 0;
		    rx = 0; ry = 0;
		    dx = 0; nx = 0;
		    dy = 0; ny = 0;
		    TIdentity ();
		}
		;
%%
#include "ciflex.src"

yyerror (cs)
char   *cs;
{
    int     c = yytext[0];
    yytext[16] = '\0';
    if (c >= '\0' && c <= ' ' || c > '\176') {
	switch (c) {
	    case '\n': 
		sprintf (yytext, "eol");
		break;
	    case '\0': 
		sprintf (yytext, "eof");
		break;
	    default: 
		sprintf (yytext, "\\%03o", c);
	}
    }
    pr_exit (074, 0, cs);
}

doStart (s, a, b)
int     s,
        a,
        b;
{
    int     tmp;
    resolution = (double) a / ((double) b * cifunit * dmproject -> lambda);
    tmp = 100000 * resolution + 0.1;
    resolution = (double) tmp / 100000;
    if (v_mode)
	P_E "ds %d %d %d; lambda = %g; symbol resolution = %g; cifunit = %d\n",
	    s, a, b, dmproject -> lambda, resolution, cifunit);
    if (mod_key) {
	close_files ();
	dmCheckIn (mod_key, QUIT);
	mod_key = NULL;
    }

    err_flag = 0;		/* no errors */

    sprintf (ms_name, "symbol%d", s);

    if (!s_mode) {
	if (check_tree (ms_name, mod_tree)) {
	    if (f_mode && !tree_ptr -> bbox) {
		pr_exit (0604, 42, ms_name);
	    }
	    else { /* already defined or used */
		tree_ptr -> errflag = 1;
		if (!f_mode)
		    pr_exit (0214, 9, ms_name);
		else
		    pr_exit (0214, 37, ms_name);
	    }
	}
	if (!err_flag) {
	    mod_key = dmCheckOut (dmproject, ms_name,
		    WORKING, DONTCARE, LAYOUT, CREATE);
	    open_files ();
	    ini_mcbbox = ini_bbbox = 1;
	}
    }
    doUserStartFlag = 1;
}

doUserStart (s)
char   *s;
{
    if (doUserStartFlag) {
	if (v_mode)
	    P_E "-- 9 %s\n", s);

	if (mod_key) {
	    close_files ();
	    dmCheckIn (mod_key, QUIT);
	    mod_key = NULL;
	}

	if (!s_mode) {
	    if (check_tree (s, mod_tree)) {
		tree_ptr -> errflag = 1;
		pr_exit (0214, 9, s);/* already defined */
	    }
	    else {
		mod_key = dmCheckOut (dmproject, s, WORKING,
						DONTCARE, LAYOUT, CREATE);
		open_files ();
		ini_mcbbox = ini_bbbox = 1;
	    }
	}
/* store alias name s and ms_name in alias tree */
	store_alias (ms_name, s);
/* */
	strcpy (ms_name, s);
    }
    doUserStartFlag = 0;
}

doBox (l, w, a, b, x, y)
int     l,
        w,
        a,
        b,
        x,
        y;
{
    int     xl,
            xr,
            yb,
            yt;

    if (y == 0) {
	xl = a - l / 2;
	xr = a + l / 2;
	yb = b - w / 2;
	yt = b + w / 2;
    }
    else
	if (x == 0) {
	    xl = a - w / 2;
	    xr = a + w / 2;
	    yb = b - l / 2;
	    yt = b + l / 2;
	}
	else {
	    return (ABox (l, w, a, b, x, y));
	}

    if (!err_flag && !s_mode) {
	proc_box (xl, xr, yb, yt);
    }
}

doCifCall (s)
int     s;
{
    char   *alias;
/* look for alias name for symbol%d and if exists use it */
    sprintf (mc_name, "symbol%d", s);
    alias = find_alias (mc_name);
    if (alias != 0)
	strcpy (mc_name, alias);

    MapTrans ();

    if (!err_flag && !s_mode) {
	if (mod_key != NULL)
	    proc_cif_mc (0, CurrentTransform[0][0], CurrentTransform[1][0],
		    CurrentTransform[2][0], CurrentTransform[0][1],
		    CurrentTransform[1][1], CurrentTransform[2][1]);
	else
	    P_E "%s: %d: warning: no valid context present; statement skipped (C %d)\n", argv0, yylineno, s);
    }
}

ABox (Length, Width, X, Y, XDirection, YDirection)
int     Length,
        Width,
        X,
        Y,
        XDirection,
        YDirection;
{
    double  C;
    double  sqrt ();
    int     Left,
            Bottom,
            Right,
            Top;
    int     i;

    Left = X - (Length >> 1);
    Right = X + (Length >> 1);
    Bottom = Y - (Width >> 1);
    Top = Y + (Width >> 1);
    C = sqrt ((double) (XDirection * XDirection + YDirection * YDirection));
    i = 0;

    Points[i++] = (Left * XDirection - Bottom * YDirection -
	    XDirection * X + YDirection * Y) / C + X;
    Points[i++] = (Left * YDirection + Bottom * XDirection -
	    YDirection * X - XDirection * Y) / C + Y;

    Points[i++] = (Left * XDirection - Top * YDirection -
	    XDirection * X + YDirection * Y) / C + X;
    Points[i++] = (Left * YDirection + Top * XDirection -
	    YDirection * X - XDirection * Y) / C + Y;

    Points[i++] = (Right * XDirection - Top * YDirection -
	    XDirection * X + YDirection * Y) / C + X;
    Points[i++] = (Right * YDirection + Top * XDirection -
	    YDirection * X - XDirection * Y) / C + Y;

    Points[i++] = (Right * XDirection - Bottom * YDirection -
	    XDirection * X + YDirection * Y) / C + X;
    Points[i++] = (Right * YDirection + Bottom * XDirection -
	    YDirection * X - XDirection * Y) / C + Y;

    for (int_ind = 0; int_ind < i; int_ind++)
	int_val[int_ind] = 4 * Points[int_ind];
    int_val[int_ind++] = 4 * Points[0];
    int_val[int_ind++] = 4 * Points[1];
    if (int_ind >= NOINTS)
	pr_exit (0137, 8, 0);

    if (!err_flag && !s_mode)
	proc_poly ();
}

TTranslate (X, Y)
int     X,
        Y;
{
    CurrentTransform[2][0] = CurrentTransform[2][0] + X;
    CurrentTransform[2][1] = CurrentTransform[2][1] + Y;
}

TMY () {
/* MY in cif means mirror in y direction, i.e. y = -y */
/* AND NOT like in ldm over y axis */
    CurrentTransform[0][1] = -CurrentTransform[0][1];
    CurrentTransform[1][1] = -CurrentTransform[1][1];
    CurrentTransform[2][1] = -CurrentTransform[2][1];
}

TMX () {
/* MX in cif means mirror in x direction, i.e. x = -x */
/* AND NOT like in ldm over x axis */
    CurrentTransform[0][0] = -CurrentTransform[0][0];
    CurrentTransform[1][0] = -CurrentTransform[1][0];
    CurrentTransform[2][0] = -CurrentTransform[2][0];
}

TRotate (XDirection, YDirection)
int     XDirection,
        YDirection;
 /* 
  Rotation angle is expressed as a CIF-style direction vector.
  */
{
    int     Int1;

    if (XDirection == 0) {
	if (abs (YDirection) > 1)
	    if (YDirection < 0)
		YDirection = -1;
	    else
		YDirection = 1;
    }
    else
	if (YDirection == 0) {
	    if (abs (XDirection) > 1)
		if (XDirection < 0)
		    XDirection = -1;
		else
		    XDirection = 1;
	}
    if (XDirection == 1 && YDirection == 0)/* Don't rotate at all.  */
	return;
    else
	if (XDirection == 0 && YDirection == -1) {
	/* 
	 Rotate ccw by 270 degrees.
	 */
	    Int1 = CurrentTransform[0][0];
	    CurrentTransform[0][0] = CurrentTransform[0][1];
	    CurrentTransform[0][1] = -Int1;
	    Int1 = CurrentTransform[1][0];
	    CurrentTransform[1][0] = CurrentTransform[1][1];
	    CurrentTransform[1][1] = -Int1;
	    Int1 = CurrentTransform[2][0];
	    CurrentTransform[2][0] = CurrentTransform[2][1];
	    CurrentTransform[2][1] = -Int1;
	}
	else
	    if (XDirection == 0 && YDirection == 1) {
	    /* 
	     Rotate ccw by 90 degrees.
	     */
		Int1 = CurrentTransform[0][0];
		CurrentTransform[0][0] = -CurrentTransform[0][1];
		CurrentTransform[0][1] = Int1;
		Int1 = CurrentTransform[1][0];
		CurrentTransform[1][0] = -CurrentTransform[1][1];
		CurrentTransform[1][1] = Int1;
		Int1 = CurrentTransform[2][0];
		CurrentTransform[2][0] = -CurrentTransform[2][1];
		CurrentTransform[2][1] = Int1;
	    }
	    else
		if (XDirection == -1 && YDirection == 0) {
		/* 
		 Rotate ccw by 180 degrees.
		 */
		    int     Int1,
		            Int2;

		    for (Int1 = 0; Int1 < 3; ++Int1) {
			for (Int2 = 0; Int2 < 2; ++Int2) {
			    CurrentTransform[Int1][Int2]
				= -CurrentTransform[Int1][Int2];
			}
		    }
		}
}

TIdentity () {
    CurrentTransform[0][0] = CurrentTransform[1][1] = 1;
    CurrentTransform[0][1] = CurrentTransform[1][0] = 0;
    CurrentTransform[2][0] = CurrentTransform[2][1] = 0;
}

MapTrans () {
    int     pos;
/* Maps anti clock and clock wise, i.e. R 90 -> R 270 and R 270 -> R 90 */

    if (CurrentTransform[0][0] == 1 && CurrentTransform[0][1] == 0 &&
	    CurrentTransform[1][0] == 0 && CurrentTransform[1][1] == 1)
	pos = 0;
    else
	if (CurrentTransform[0][0] == 0 && CurrentTransform[0][1] == -1 &&
		CurrentTransform[1][0] == 1 && CurrentTransform[1][1] == 0)
	    pos = 1;
	else
	    if (CurrentTransform[0][0] == -1 && CurrentTransform[0][1] == 0 &&
		    CurrentTransform[1][0] == 0 && CurrentTransform[1][1] == -1)
		pos = 2;
	    else
		if (CurrentTransform[0][0] == 0 && CurrentTransform[0][1] == 1 &&
			CurrentTransform[1][0] == -1 && CurrentTransform[1][1] == 0)
		    pos = 3;

/* mx my */
		else
		    if (CurrentTransform[0][0] == 1 && CurrentTransform[0][1] == 0 &&
			    CurrentTransform[1][0] == 0 && CurrentTransform[1][1] == -1)
			pos = 4;

		    else
			if (CurrentTransform[0][0] == -1 && CurrentTransform[0][1] == 0 &&
				CurrentTransform[1][0] == 0 && CurrentTransform[1][1] == 1)
			    pos = 5;

/* mx r90 mx r270 */
			else
			    if (CurrentTransform[0][0] == 0 && CurrentTransform[0][1] == 1 &&
				    CurrentTransform[1][0] == 1 && CurrentTransform[1][1] == 0)
				pos = 6;

			    else
				if (CurrentTransform[0][0] == 0 && CurrentTransform[0][1] == -1 &&
					CurrentTransform[1][0] == -1 && CurrentTransform[1][1] == 0)
				    pos = 7;

    switch (pos) {
	case 0: 
	    CurrentTransform[0][0] = 1, CurrentTransform[0][1] = 0;
	    CurrentTransform[1][0] = 0, CurrentTransform[1][1] = 1;
	    break;
	case 1: 
	    CurrentTransform[0][0] = 0, CurrentTransform[0][1] = 1;
	    CurrentTransform[1][0] = -1, CurrentTransform[1][1] = 0;
	    break;
	case 2: 
	    CurrentTransform[0][0] = -1, CurrentTransform[0][1] = 0;
	    CurrentTransform[1][0] = 0, CurrentTransform[1][1] = -1;
	    break;
	case 3: 
	    CurrentTransform[0][0] = 0, CurrentTransform[0][1] = -1;
	    CurrentTransform[1][0] = 1, CurrentTransform[1][1] = 0;
	    break;

	case 5: 
	    CurrentTransform[0][0] = -1, CurrentTransform[0][1] = 0;
	    CurrentTransform[1][0] = 0, CurrentTransform[1][1] = 1;
	    break;
	case 4: 
	    CurrentTransform[0][0] = 1, CurrentTransform[0][1] = 0;
	    CurrentTransform[1][0] = 0, CurrentTransform[1][1] = -1;
	    break;

	case 7: 
	    CurrentTransform[0][0] = 0, CurrentTransform[0][1] = -1;
	    CurrentTransform[1][0] = -1, CurrentTransform[1][1] = 0;
	    break;
	case 6: 
	    CurrentTransform[0][0] = 0, CurrentTransform[0][1] = 1;
	    CurrentTransform[1][0] = 1, CurrentTransform[1][1] = 0;
	    break;
    }
}

deletecell (s)
int     s;
{
    char    name[DM_MAXNAME];

    if (v_mode)
	P_E "-- dd %d\n", s);

    sprintf (name, "symbol%d", s);

    if (!s_mode) {
	if (check_tree (name, mod_tree)) {
	    dmRemoveCell (dmproject, name, WORKING, DONTCARE, LAYOUT);
	}
	else {
	    P_E "%s: %s: Symbol not defined\n", argv0, name);
	}
    }
}

dumpT (s)
char   *s;
{
    P_E "Trans Matrix: (%s)\n", s);
    P_E "%d %d\n%d %d\n%d%d\n\n",
	CurrentTransform[0][0], CurrentTransform[0][1],
	CurrentTransform[1][0], CurrentTransform[1][1],
	CurrentTransform[2][0], CurrentTransform[2][1]);
}

doUserTerm (Termname, Termx, Termy, Termlayer)
char   *Termname;
int     Termx,
        Termy;
char   *Termlayer;
{
    if (v_mode)
	P_E "-- 94 %s %d %d %s\n", Termname, Termx, Termy, Termlayer);
    dolayer (Termlayer);
    if (strlen (Termname) > DM_MAXNAME) {
	pr_exit (0634, 18, Termname);
	sprintf (name_len, "%d", DM_MAXNAME);
	pr_exit (0600, 19, name_len);
	Termname[DM_MAXNAME] = '\0';
    }
    strcpy (terminal, Termname);
    if (append_tree (terminal, &tnam_tree)) {
	pr_exit (034, 12, terminal);/* already used */
    }
    Termx = Termx * resolution;
    Termy = Termy * resolution;
    if (!err_flag && !s_mode)
	proc_term (Termx, Termx, Termy, Termy);
}

dolayer (s)
char   *s;
{
    int     i;
    for (i = 0;; ++i) {
	if (i > DM_MAXLAY) {
	    pr_exit (0634, 15, s);
	    sprintf (name_len, "%d", DM_MAXLAY);
	    pr_exit (0600, 19, name_len);
	    layer[DM_MAXLAY] = '\0';
	    break;
	}
	if (isupper (s[i]))
	    layer[i] = tolower (s[i]);
	else
	    layer[i] = s[i];
	if (layer[i] == '\0')
	    break;
    }

    if (!s_mode) {
	for (lay_code = 0;
		lay_code < process -> nomasks; ++lay_code)
	    if (!strcmp (layer, process -> mask_name[lay_code]))
		goto label1;

	pr_exit (034, 20, layer);/* unrecogn. laycode */
    }
label1: ;
}

static int  aliascount = 0;

static struct aliasptr {
    char   *alias;
    char   *name;
    struct aliasptr *next;
} *rootpnt, *currpnt;

/*
static struct aliasptr *rootpnt,
                       *currpnt;
*/

char   *find_alias (name)
char   *name;
{
    struct aliasptr *cellptr;
    int     i;

    cellptr = rootpnt;

    for (i = 0; i < aliascount; i++) {
	if (strcmp (cellptr -> name, name) == 0) {
	    return (cellptr -> alias);
	}
	cellptr = cellptr -> next;
    }
    return ((char *) 0);
}

store_alias (name, alias)
char   *name;
char   *alias;
{
    struct aliasptr *cellptr;
    char   *_dmStrSave ();

    ALLOC (cellptr, aliasptr);

    cellptr -> name = _dmStrSave (name);
    cellptr -> alias = _dmStrSave (alias);
    cellptr -> next = 0;

    if (aliascount == 0) {
	rootpnt = cellptr;
	currpnt = cellptr;
    }
    else {
	currpnt -> next = cellptr;
	currpnt = cellptr;
    }
    aliascount++;
}
