%{
/* SccsId = "@(#)parse.y 4.4 (TU-Delft) 03/02/93" */
/**********************************************************

Name/Version      : tecc/4.4

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Author            : A.J. van Genderen
Creation date     : 15-Mar-1988
Modified by       :
Modification date :


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1988. All rights reserved.
**********************************************************/

#include <stdio.h>
#include <dmincl.h>
#include "define.h"
#include "type.h"
#include "extern.h"

#define MAXMINTERM  32

char *nameTab[MAXTOR + MAXCAP + MAXCON + MAXRES];
int name_cnt = 0;

char namebuf1[132];
char namebuf2[132];
int nmBufToggle = 0;
struct layCondRef *condStack[MAXMINTERM];

int minTermCnt;

char ressort[80];
char capsort[80];
char consort[80];

struct contact *curr_con;
struct contact *other_con;
struct transistor *curr_tor;
struct transistor *other_tor;
struct capacitance *curr_cap;
struct capacitance *other_cap;
struct resistance *curr_res;
struct resistance *other_res;
struct vdimension *curr_vdim;
struct vdimension *other_vdim;
struct shape *curr_shape;
struct shape *other_shape;

struct maskRef *last_mask_list;
struct layerRef *last_layer_list;
struct layCondRef *last_cond_list;

char shapetype;
int val_cnt;
double retval[4];

char mesbuf[200];

static double res_unit = 1.0;          /* default values */
static double c_res_unit = 1.0;
static double cap_unit = 1.0;
static double a_cap_unit = 1.0;
static double e_cap_unit = 1.0;
static double vdim_unit = 1.0;
static double shape_unit = 1.0;

%}

%union		{
		    int ival;
		    double dval;
                    char *sval;
		    struct layer *layp;
		    struct layerCond *layCp;
		    struct maskRef *maskr;
		    struct layerRef *layr;
		    struct layCondRef *layCr;
		}

%token 		MAXKEYS MINUS EQUAL MULT DIV COLON POWER NOT LPS RPS 
%token		KEYS CONTACTS TRANSISTORS CAPACITANCES CONDUCTORS BAR
%token		VDIMENSIONS ESHAPES CSHAPES UNIT RESISTANCE C_RESISTANCE
%token		CAPACITANCE A_CAPACITANCE E_CAPACITANCE VDIMENSION SHAPE
%token <ival> 	INTEGER 
%token <sval>	IDENTIFIER 
%token <dval>	DOUBLE 

%type  <sval>	name
%type  <dval>   val
%type  <ival>   mask
%type  <layp>	layer
%type  <layCp>	cond
%type  <layr>	layer_list
%type  <layCr>	cond_list

%left MULT DIV
%left POWER

%%

tech_descr	: key_info unit_descr conduc_descr tor_descr contact_descr 
		  cap_descr vdim_descr eshape_descr cshape_descr
		;

key_info	: KEYS COLON layer_list
		{
		    keylist = $3;

		    maxNbrKeys = -1; /* no maximum for nbrKeys */
		}
		| MAXKEYS INTEGER
		{
		    keylist = NULL;

		    maxNbrKeys = $2;
		}
		| /* empty */
		{
		    keylist = NULL;

		    maxNbrKeys = 10; /* default */
		}
		;

layer_list	: layer
		{
		    ALLOC ($$, 1, struct layerRef);
		    $$ -> lay = $1;
		    $$ -> next = NULL;
		    last_layer_list = $$;
		}
		| layer_list layer
		{
		    ALLOC (last_layer_list -> next, 1, struct layerRef);
		    last_layer_list = last_layer_list -> next;
		    last_layer_list -> lay = $2;
		    last_layer_list -> next = NULL;
		    $$ = $1;
		}
		;

conduc_descr	: /* empty */
		| conduc_descr conduc_group
		;

conduc_group    : CONDUCTORS name COLON
		{
		    strcpy (ressort, $2);
		}
		  conduc_list
		| CONDUCTORS COLON 
		{
		    strcpy (ressort, "res");
		}
		  conduc_list
		;

conduc_list	: /* empty */
		| conduc_list conduc
		;

conduc		: name COLON 
		{
		    checkElemName ($1);

		    curr_res = &ress[ newres () ];
		    strcpy (curr_res -> name, $1);
		    curr_res -> id = name_cnt - 1;
		    strcpy (curr_res -> sort, ressort);
		}
		  min_terms COLON mask COLON val
		{
		    curr_res -> mask = $6;
		    curr_res -> val = res_unit * $8;

		    curr_res -> cond = condStack[--minTermCnt];
		    while (minTermCnt > 0) {
		        other_res = &ress[ newres () ];
		        other_res -> cond = condStack[--minTermCnt];
			strcpy (other_res -> name, curr_res -> name);
			other_res -> id = curr_res -> id;
			strcpy (other_res -> sort, curr_res -> sort);
			other_res -> mask = curr_res -> mask;
			other_res -> val = curr_res -> val;
		    }
		}
		;

tor_descr	: /* empty */
		| tor_group
		;

tor_group 	: TRANSISTORS COLON tor_list
		;

tor_list	: /* empty */
		| tor_list tor
		;

tor		: name COLON 
		{
		    checkElemName ($1);

		    curr_tor = &tors[ newtor () ];
		    strcpy (curr_tor -> name, $1);
		    curr_tor -> id = name_cnt - 1;
		}
		  min_terms COLON mask mask
		{
		    curr_tor -> g = $6;
		    curr_tor -> ds = $7;

		    curr_tor -> cond = condStack[--minTermCnt];
		    while (minTermCnt > 0) {
		        other_tor = &tors[ newtor () ];
		        other_tor -> cond = condStack[--minTermCnt];
			strcpy (other_tor -> name, curr_tor -> name);
			other_tor -> id = curr_tor -> id;
			other_tor -> g = curr_tor -> g;
			other_tor -> ds = curr_tor -> ds;
		    }
		}
		;

contact_descr	: /* empty */
		| contact_descr contact_group

contact_group	: CONTACTS name COLON
		{
		    strcpy (consort, $2);
		}
		  contact_list
		| CONTACTS COLON 
		{
		    strcpy (consort, "res");
		}
		  contact_list
		;

contact_list	: /* empty */
		| contact_list contact
		;

contact		: name COLON 
		{
		    checkElemName ($1);

		    curr_con = &cons[ newcon () ];
		    strcpy (curr_con -> name, $1);
		    curr_con -> id = name_cnt - 1;
		    strcpy (curr_con -> sort, consort);
		}
		  min_terms COLON mask mask COLON val
		{
		    curr_con -> mask1 = $6;
		    curr_con -> mask2 = $7;
		    curr_con -> val = c_res_unit * $9;

		    curr_con -> cond = condStack[--minTermCnt];
		    while (minTermCnt > 0) {
		        other_con = &cons[ newcon () ];
		        other_con -> cond = condStack[--minTermCnt];
			strcpy (other_con -> name, curr_con -> name);
			other_con -> id = curr_con -> id;
			strcpy (other_con -> sort, curr_con -> sort);
			other_con -> mask1 = curr_con -> mask1;
			other_con -> mask2 = curr_con -> mask2;
			other_con -> val = curr_con -> val;
		    }
		}
		;

cap_descr	: /* empty */
		| cap_descr cap_group
		;

cap_group	: CAPACITANCES name COLON
		{
		    strcpy (capsort, $2);
		}
		  cap_list
		| CAPACITANCES COLON 
		{
		    strcpy (capsort, "cap");
		}
		  cap_list
		;

cap_list	: /* empty */
		| cap_list cap
		;

cap		: name COLON
		{
		    checkElemName ($1);

		    curr_cap = &caps[ newcap () ];
		    strcpy (curr_cap -> name, $1);
		    curr_cap -> id = name_cnt - 1;
		    strcpy (curr_cap -> sort, capsort);
		}
		  min_terms COLON cap_con COLON val
		{
		    if (curr_cap -> nLay -> mask >= 0
		    && curr_cap -> nLay -> occurrence == OTHEREDGE) {
			curr_cap -> val = cap_unit * $8;
		    }
		    else if (curr_cap -> pLay -> occurrence == EDGE
		    || (curr_cap -> nLay -> mask >= 0
			&& curr_cap -> nLay -> occurrence == EDGE)) {
			curr_cap -> val = e_cap_unit * $8;
		    }
		    else {
			curr_cap -> val = a_cap_unit * $8;
		    }

		    curr_cap -> cond = condStack[--minTermCnt];
		    while (minTermCnt > 0) {
		        other_cap = &caps[ newcap () ];
		        other_cap -> cond = condStack[--minTermCnt];
			strcpy (other_cap -> name, curr_cap -> name);
			other_cap -> id = curr_cap -> id;
			strcpy (other_cap -> sort, curr_cap -> sort);
			other_cap -> pLay = curr_cap -> pLay;
			other_cap -> nLay = curr_cap -> nLay;
			other_cap -> val = curr_cap -> val;
		    }
		}
		;

cap_con		: layer
		{
		    if ($1 -> occurrence == OTHEREDGE)
			fatalErr ("Incorrect pin layer specification for", 
				  curr_cap -> name);

		    curr_cap -> pLay = $1;
		    ALLOC (curr_cap -> nLay, 1, struct layer);
		    curr_cap -> nLay -> mask = -1;
		}
		| layer layer
		{
		    if ($1 -> occurrence == OTHEREDGE
		        && $2 -> occurrence == OTHEREDGE)
			fatalErr ("Incorrect pin layer specification for", 
				  curr_cap -> name);

		    if (($1 -> occurrence == OTHEREDGE
		         && $2 -> occurrence == SURFACE)
			|| ($1 -> occurrence == SURFACE
		            && $2 -> occurrence == OTHEREDGE))
			fatalErr ("Incorrect pin layer specification for", 
				  curr_cap -> name);

		    if ($1 -> occurrence == OTHEREDGE
		    || ($1 -> occurrence == EDGE
			&& $2 -> occurrence == SURFACE)) {
			curr_cap -> pLay = $2;
			curr_cap -> nLay = $1;     /* swap them */
		    }
		    else {
			curr_cap -> pLay = $1;
			curr_cap -> nLay = $2;
		    }
		}
		;

vdim_descr	: /* empty */
		| VDIMENSIONS COLON vdim_list
		;

vdim_list	: /* empty */
		| vdim_list vdim
		;

vdim		: name COLON
		{
		    checkElemName ($1);

		    curr_vdim = &vdms[ newvdim () ];
		    strcpy (curr_vdim -> name, $1);
		    curr_vdim -> id = name_cnt - 1;
		}
		  min_terms COLON mask COLON val val
		{
		    curr_vdim -> mask = $6;
		    curr_vdim -> height = vdim_unit * $8;
		    curr_vdim -> thickness = vdim_unit * $9;

		    curr_vdim -> cond = condStack[--minTermCnt];
		    while (minTermCnt > 0) {
		        other_vdim = &vdms[ newvdim () ];
		        other_vdim -> cond = condStack[--minTermCnt];
			strcpy (other_vdim -> name, curr_vdim -> name);
			other_vdim -> id = curr_vdim -> id;
			other_vdim -> mask = curr_vdim -> mask;
			other_vdim -> height = curr_vdim -> height;
			other_vdim -> thickness = curr_vdim -> thickness;
		    }
		}
		;

eshape_descr	: /* empty */
		| ESHAPES 
		{
		    shapetype = 'e';
		}
		  COLON shape_list
		;

cshape_descr	: /* empty */
		| CSHAPES 
		{
		    shapetype = 'c';
		}
		  COLON shape_list
		;

shape_list	: /* empty */
		| shape_list shape
		;

shape		: name COLON
		{
		    checkElemName ($1);

		    curr_shape = &shps[ newshape () ];
		    strcpy (curr_shape -> name, $1);
		    curr_shape -> id = name_cnt - 1;
		}
		  min_terms COLON mask COLON vals_1_2_or_4
		{
		    switch (shapetype) {
			case 'e':
			    curr_shape -> type = ESHAPE;
			    break;
			case 'c':
			    curr_shape -> type = CSHAPE;
			    break;
		    }
		    curr_shape -> mask = $6;
		    if (curr_shape -> type == ESHAPE) {
			if (val_cnt == 1) {
			    curr_shape -> xb1 = shape_unit * retval[0];
			    curr_shape -> xt1 = curr_shape -> xb1;
			}
			else if (val_cnt == 2) {
			    curr_shape -> xb1 = shape_unit * retval[0];
			    curr_shape -> xt1 = shape_unit * retval[1];
			}
			else {
			    sprintf (mesbuf, 
			   "Illegal number of values for eshape element '%s'\n",
			     curr_shape -> name);
			    fatalErr (mesbuf, NULL);
			}
			curr_shape -> xb2 = -1.0;  /* random number */
			curr_shape -> xt2 = -1.0;  /* random number */
		    }
		    else if (curr_shape -> type == CSHAPE) {
			if (val_cnt == 2) {
			    curr_shape -> xb1 = shape_unit * retval[0];
			    curr_shape -> xt1 = curr_shape -> xb1;
			    curr_shape -> xb2 = shape_unit * retval[1];
			    curr_shape -> xt2 = curr_shape -> xb2;
			}
			else if (val_cnt == 4) {
			    curr_shape -> xb1 = shape_unit * retval[0];
			    curr_shape -> xt1 = shape_unit * retval[1];
			    curr_shape -> xb2 = shape_unit * retval[2];
			    curr_shape -> xt2 = shape_unit * retval[3];
			}
			else {
			    sprintf (mesbuf, 
			   "Illegal number of values for cshape element '%s'\n",
			     curr_shape -> name);
			    fatalErr (mesbuf, NULL);
			}
		    }

		    curr_shape -> cond = condStack[--minTermCnt];
		    while (minTermCnt > 0) {
			other_shape = &shps[ newshape () ];
			other_shape -> cond = condStack[--minTermCnt];
			strcpy (other_shape -> name, curr_shape -> name);
			other_shape -> id = name_cnt - 1;
			other_shape -> type = curr_shape -> type;
			other_shape -> mask = curr_shape -> mask;
			other_shape -> xb1 = curr_shape -> xb1;
			other_shape -> xt1 = curr_shape -> xt1;
			other_shape -> xb2 = curr_shape -> xb2;
			other_shape -> xt2 = curr_shape -> xt2;
		    }
		}
		;

unit_descr	: /* empty */
		| unit_descr unit
		;

unit		: UNIT RESISTANCE val
                {
		    res_unit = $3;
		}
		| UNIT C_RESISTANCE val
                {
		    c_res_unit = $3;
		}
		| UNIT CAPACITANCE val
                {
		    cap_unit = $3;
		}
		| UNIT A_CAPACITANCE val
                {
		    a_cap_unit = $3;
		}
		| UNIT E_CAPACITANCE val
                {
		    e_cap_unit = $3;
		}
		| UNIT VDIMENSION val
                {
		    vdim_unit = $3;
		}
		| UNIT SHAPE val
                {
		    shape_unit = $3;
		}
		;

min_terms	: cond_list
		{
		    minTermCnt = 0;
		    condStack[minTermCnt++] = $1;
		}
		| min_terms BAR cond_list
		{
		    if (minTermCnt >= MAXMINTERM)
			fatalErr ("Too many minterms", NULL);

		    condStack[minTermCnt++] = $3;
		}
		;

cond_list	: cond
		{
		    ALLOC ($$, 1, struct layCondRef);
		    $$ -> layC = $1;
		    $$ -> next = NULL;
		    last_cond_list = $$;
		}
		| cond_list cond
		{
		    ALLOC (last_cond_list -> next, 1, struct layCondRef);
		    last_cond_list = last_cond_list -> next;
		    last_cond_list -> layC = $2;
		    last_cond_list -> next = NULL;
		    $$ = $1;
		}
		;

cond		: layer
		{
		    ALLOC ($$, 1, struct layerCond);
		    $$ -> lay = $1;
		    $$ -> present = 1;
		}
		| NOT layer
		{
		    ALLOC ($$, 1, struct layerCond);
		    $$ -> lay = $2;
		    $$ -> present = 0;
		}
		;

layer		: mask
		{
		    ALLOC ($$, 1, struct layer);
		    $$ -> mask = $1;
		    $$ -> occurrence = SURFACE;
		}
		| MINUS mask
		{
		    ALLOC ($$, 1, struct layer);
		    $$ -> mask = $2;
		    $$ -> occurrence = EDGE;
		}
		| EQUAL mask
		{
		    ALLOC ($$, 1, struct layer);
		    $$ -> mask = $2;
		    $$ -> occurrence = OTHEREDGE;
		}
		;

mask		: name
		{
		    $$ = maskno ($1);

		    if ($$ < 0)
			fatalErr ("Unknown mask:", $1);
		}
		;

name		: IDENTIFIER
		{
                    if (nmBufToggle) {
			strcpy (namebuf1, $1);
			$$ = namebuf1;
			nmBufToggle = 0;
		    }
		    else {
			strcpy (namebuf2, $1);
			$$ = namebuf2;
			nmBufToggle = 1;
		    }
		}
		;

vals_1_2_or_4	: val
		{
		    retval[0] = $1;

		    val_cnt = 1;
		}
		| val val
		{
		    retval[0] = $1;
		    retval[1] = $2;

		    val_cnt = 2;
		}
		| val val val val
		{
		    retval[0] = $1;
		    retval[1] = $2;
		    retval[2] = $3;
		    retval[3] = $4;

		    val_cnt = 4;
		}
		;

val		: INTEGER
		{
		    $$ = (double)$1;
		}
		| DOUBLE
		{
		    $$ = $1;
		}
		;

%%

#include "lex.c"

yyerror (s)
char *s;
{
    sprintf (mesbuf, "%s at line %d\n", s, yylineno);
    fatalErr (mesbuf, NULL);
}

int newres ()
{
    if (res_cnt + 1 > MAXRES)
	fatalErr ("Too many conductors", NULL);

    return (res_cnt++);
}

int newtor ()
{
    if (tor_cnt + 1 > MAXTOR)
	fatalErr ("Too many transistors", NULL);

    return (tor_cnt++);
}

int newcon ()
{
    if (con_cnt + 1 > MAXCON)
	fatalErr ("Too many contacts", NULL);

    return (con_cnt++);
}

int newcap ()
{
    if (cap_cnt + 1 > MAXCAP)
	fatalErr ("Too many capacitances", NULL);

    return (cap_cnt++);
}

int newvdim ()
{
    if (vdim_cnt + 1 > MAXVDIM)
        fatalErr ("Too many vdimension elements", NULL);

    return (vdim_cnt++);
}

int newshape ()
{
    if (shape_cnt + 1 > MAXSHAPE)
        fatalErr ("Too many shape elements", NULL);

    return (shape_cnt++);
}

int maskno (name)
char *name;
{
    int i;

    for (i = 0; i < procdata -> nomasks; i++) {
	if (strcmp (name, procdata -> mask_name[i]) == 0)
	    return (i);
    }

    return (-1);
}

checkElemName (name)
char *name;
{
    int i;

    for (i = 0; i < name_cnt; i++) {
	if (strcmp (name, nameTab[i]) == 0) {
	    fatalErr ("Multiple use of element name", name);
	}
    }
    ALLOC (nameTab[name_cnt], strlen (name) + 1, char);
    strcpy (nameTab[name_cnt], name);
    name_cnt++;
}

