%{
static char *SccsId = "@(#)parse.y 3.1 (TU-Delft) 04/16/87";
/**********************************************************

Name/Version      : sldm/3.1

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

Author(s)         : N. van der Meijs
Creation date     : 17-Oct-1984
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) 1984 , All rights reserved
**********************************************************/
# include "sldm.h"

# define HUGE (017777777777)     /* 32 bits, two's complement */
# define ABS(x) ((x)>0?(x):(-x))
# ifndef YYLMAX 
# define YYLMAX 200
# endif

extern FILE *yyout;
extern char  yytext[];
extern int   yylineno;
extern  int  xval[];
extern  int  yval[];

extern void tModifier ();
extern void pModifier ();
extern void mModifier ();
extern void nmcopy    ();
extern void yyerror   ();
extern void free      ();
extern void doMc      ();
extern void doTerm    ();
extern void doBox     ();
extern void doMs      ();
extern char * strcpy  ();
extern STRETCH * install ();

static STRETCH *sp;
static int tx, ty;
static int dx, nx, dy, ny;
static char nameBuf [MAXNAME + 1];
static char instBuf [MAXNAME + 1];
static char commentBuf [YYLMAX];
%}

%token MS_TOKEN MC_TOKEN BOX_TOKEN TERM_TOKEN ME_TOKEN  EOL
%token CX CY MIRX MIRY ROT3 ROT6 ROT9 TRANS 
%token WORD INT 
%token COMMENT 
%token SX SY
%start stats 

%%

stats           : /* EMPTY */
                | stats ms_stat stretch_stats other_stats me_stat
                | stats comment EOL {
		    doComment (commentBuf);
		}
                | error EOL {
			yyerrok;
                        if (sp)
                            free((char *) sp);
                };

ms_stat         : MS_TOKEN name comment EOL {
		    doMs (nameBuf, commentBuf);
		};

me_stat         : ME_TOKEN comment EOL {
		    doMe (commentBuf);
		};

other_stats     : /* EMPTY */
                | other_stats other_stat
                ;

other_stat      : BOX_TOKEN layer int int int int cx cy comment EOL {
		    doBox
		    ($2, $3, $4, $5, $6, dx, nx, dy, ny, commentBuf);
		}
                | TERM_TOKEN layer int int int int name cx cy comment EOL {
		    doTerm
		    ($2, $3, $4, $5, $6, nameBuf, dx, nx, dy, ny, commentBuf);
		}
                | MC_TOKEN inst name mir rot tr cx cy comment EOL {
		    doMc (instBuf, nameBuf, $4, $5, tx, ty,
			dx, nx, dy, ny, commentBuf);
		}
                | comment EOL {
		    doComment (commentBuf);
		}
                | error EOL {
		    yyerrok;
                };

stretch_stats   : /* EMPTY */
                | stretch_stats str_stat
                ;

str_stat        : s_key opt_layer int maxval int hilo modifiers comment EOL {
                    sp->line = yylineno;
                    sp->dir   = $1;
                    sp->layer = $2;
                    if (ABS($3) >= 1)
                    sp->label = ABS($3);
                    else {
			yyerror("bad label: %d",$3);
			YYERROR;
                    }
		    sp->val   = $4;
		    sp->pos   = $5;
		    if (sp->dir == XDIR){
			if (xval[ABS($3)] > sp->val){
			    yyerror("maxval for sx, label %d = %d",
				 $3, xval[$3]);
			}
			else if (ABS($3) <= xval[0]) {
			    sp->val = ($3>0?xval[$3]:-xval[-$3]);
			}
			else
			    sp->val = 0;
		    }
		    else if (sp->dir == YDIR){
			if (yval[ABS($3)] > sp->val){
			    yyerror("maxval for sx, label %d = %d",
                                     $3, xval[$3]);
			}
			else if (ABS($3) <= yval[0]) {
			    sp->val = ($3>0?yval[$3]:-yval[-$3]);
			}
			else
			    sp->val = 0;
		    }
		    else
			PANIC ("bad direction: %d",sp->dir);
		    (void) install(sp);
#ifdef DEBUG
		    if (DEBUG) {
			dumpStretch(stderr,sp);
		    }
#endif DEBUG
		    sp = NULL;
                };

s_key           : SX {
                    if ((sp = alloc (STRETCH)) == NULL)
                        die ("no more core");
                    sp -> p_mod[0] = sp -> m_mod[0] = sp -> t_mod[0] = '\0';
                    $$ = XDIR;
                }
                | SY {
                    if ((sp = alloc (STRETCH)) == NULL)
                        die ("no more core");
                    sp -> p_mod[0] = sp -> m_mod[0] = sp -> t_mod[0] = '\0';
                    $$ = YDIR; 
                };

maxval          : /* EMPTY */           { $$ = HUGE; }
                | '<' int '>'           { $$ = $2;   }
                ;

hilo            : /* EMPTY */           { sp->lo = -HUGE; sp->hi = HUGE; }
                | int int               { sp->lo = $1;    sp->hi = $2;   }
                ;

modifiers       : /* EMPTY */
                | modifiers plus_mod
                | modifiers min_mod
                | modifiers touch_mod
                ;

plus_mod        : '+'  layer            { pModifier ($2); }
                | plus_mod layer        { pModifier ($2); }
                
min_mod         : '-'  layer            { mModifier ($2); }
                | min_mod layer         { mModifier ($2); }
                ;

touch_mod       : '=' layer             { tModifier ($2); }
                | touch_mod layer       { tModifier ($2); }
                ;

opt_layer       : /* EMPTY */           { $$ = 0; }
                | layer 
                ;

layer           : WORD                  { $$ = islayer (yytext); }
                ;

int             : INT                   { $$ = atoi (yytext); }
                ;

inst            : /* EMPTY */           { nmcopy (instBuf, "");      }
                | '<' name '>'          { nmcopy (instBuf, nameBuf); }
                ;

name            : WORD                  { nmcopy(nameBuf, yytext);   }
                ;

mir             : /* EMPTY */           { $$ = 0;   }
                | MIRX                  { $$ = 'x'; }
                | MIRY                  { $$ = 'y'; }
                ;

rot             : /* EMPTY */           { $$ = 0;   }
                | ROT3                  { $$ = 90;  }
                | ROT6                  { $$ = 180; }
                | ROT9                  { $$ = 270; }
                ;

tr              : /* EMPTY */           { tx = 0;  ty = 0;  }
                | TRANS int int         { tx = $2; ty = $3; }
                ;

cx              : /* EMPTY */           { dx = 0; nx = 0;   }
                | CX  int  int          { dx = $2; nx = $3; }
                ;

cy              : /* EMPTY */           { dy = 0; ny = 0;   }
                | CY  int int           { dy = $2; ny = $3; }
                ;

comment         : /* EMPTY */           { strcpy (commentBuf, "");     }
                | COMMENT               { strcpy (commentBuf, yytext); }
                ;
%%

/* VARARGS1 */
void yyerror (s1, s2, s3)
char   *s1;
char   *s2;
{
    int     l;
    extern char infile [];
    if (yychar == EOL)
        l = yylineno - 1;
    else 
        l = yylineno;           /* if the lookahead token (yychar) is EOL,
                                   yylineno is incremented by yylex */
    fprintf (stderr, "sldm: %s, line %d: ", infile, l);
    fprintf (stderr, s1, s2, s3);
    fprintf (stderr, "\n");
}

static int islayer (s)
char   *s;
{
    int layer = '?';

    switch (s[1]) {
        case 'p': 
        case 'd': 
        case 'm': 
        case 'i': 
        case 'b': 
        case 'c': 
        case 'x': 
        case 'g': 
            if (s[0] == 'n' && s[2] == '\0')
                layer = s[1];
        default: 
            break;
    }

    if (layer == '?')
        yyerror ("bad layer '%s'", s);

    return (layer);
}

static void pModifier (layer)
int     layer;
{
    static int     i = 0;

    if (sp -> p_mod [0] == EOS)
        i = 0;

    if (i == NMFS + 1) {
        yyerror ("number of plus_modifiers exeeds %d", NMFS);
        i++;
    }
    else  if (i <= NMFS) {
        sp -> p_mod[i] = layer;
        sp -> p_mod[++i] = '\0';
    }
}

static void mModifier (layer)
int     layer;
{
    static int     i = 0;

    if (sp -> m_mod [0] == EOS)
        i = 0;

    if (i == NMFS + 1) {
        yyerror ("number of min_modifiers exeeds %d", NMFS);
        i++;
    }
    else  if (i <= NMFS) {
        sp -> m_mod[i] = layer;
        sp -> m_mod[++i] = '\0';
    }
}

static void tModifier (layer)
int layer;
{
    static int     i = 0;

    if (sp -> t_mod [0] == EOS)
        i = 0;

    if (i == NMFS + 1) {
        yyerror ("number of touch_modifiers exeeds %d", NMFS);
        i++;
    }
    else  if (i <= NMFS) {
        sp -> t_mod[i] = layer;
        sp -> t_mod[++i] = '\0';
    }
}

static void nmcopy (s1, s2)
char s1[], s2[];
{
    int i = 0;

    do {
        s1[i] = s2[i];
    } while (s2[i] && ++i <= MAXNAME);

    if (i > MAXNAME) {
        yyerror ("WARNING: name '%s' too long, truncated.", s2);
        s1 [MAXNAME] = EOS;
    }
}
