%{
/* -----------------------------------------------------------------------------
* COPYRIGHT  (c)  1997 
* THE REGENTS OF THE UNIVERSITY OF MICHIGAN
* ALL RIGHTS RESERVED
* 
* PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS 
* AND REDISTRIBUTE THIS SOFTWARE AND SUCH DERIVATIVE WORKS FOR 
* ANY PURPOSE, SO LONG AS NO FEE IS CHARGED, AND SO LONG AS 
* THE COPYRIGHT NOTICE ABOVE, THIS GRANT OF PERMISSION, AND 
* THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND SO LONG 
* AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED IN ANY 
* ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR 
* DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC, WRITTEN 
* PRIOR AUTHORIZATION.
* 
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION 
* FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS 
* FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE 
* UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR 
* IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES 
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 
* REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE 
* FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR 
* CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT 
* HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH 
* DAMAGES.
----------------------------------------------------------------------------- */

/**************************************************************************************
 * File: spice.y
 *
 * Purpose: parser for spicedeck, intended to gnu bison.
 *
 * Author: Michael A Riepe
 *	   Stephen T. Frezza (STF)
 *
 * RCS Version:
 *     $Id: spice.y,v 1.1.1.1 2002/05/01 14:23:27 mguthaus Exp $
 **************************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <strings.h>
#include <stream.h>
#include <stl>		// Modified to support g++-3 instalations
#include "defs.hh"
#include "utils.hh"
#include "macros.hh"
#include "argument.hh"
#include "circuit.hh"
#include "hspice_parser.hh"
    
// externs
extern FILE *yyin;

// forward declarations
double adjust_number (double arg, char *unit);
void yyerror(char *s);
int yywrap();
extern int yylex();
extern int yy_flex_debug; 

// global variables
static unsigned currentFile;
static vector<char*> *fileList;
static unsigned nFiles;
static circuit *yyCircuit;

%}

%union {
    int dval;
    double rval;
    char *sval;
    char cval;
    Argument *aval;
    ArgumentVec *av_val;
}

%left '+' '-'
%left '*' '/'

%token <sval> TITLE COMMENT
%token <sval> CAPACITOR DIODE ISOURCE JFET INDUCTOR MOSFET BJT COUPLING
%token <sval> RESISTOR VSOURCE SUBCKTINST
%token SUBCKT
%token ALTER CONTROL DATA DCVOLT DELLIB END ENDDATA ENDL ENDS
%token GLOBAL ICVOLT LIB MODEL NODESET OPTIONS PARAM PC
%token PROTECT SYSTEM UNPROTECT WIDTH
%token ACSWEEP DCSWEEP FOURIER NET DISTORTION NOISE OPPOINT
%token POLEZERO SAMPLE SENS TEMP TRANSFER TRAN
%token MEASURE GRAPH PLOT PRINT
%token <sval> ARGIDENT ARGINT ARGDECIMAL ARGFLOAT ARGUNIT
%token ARGSEND OPENQUOTE CLOSEQUOTE
%token <sval> QUOTESTRING

%type <av_val> argument_list
%type <av_val> simple_argument_list
%type <av_val> parameter_list
%type <aval> argument
%type <aval> simple_arg
%type <aval> complex_arg
%type <aval> function
%type <aval> parameter
%type <aval> node_assignment
%type <aval> quoted_string
%type <av_val> param_list
%type <aval> param_val
%type <aval> ends_arg
%%

statement_list: statement
    | statement_list statement
    ;

statement: device
    | subcircuit
    | control_card
    | analysis_card
    | output_card
    | other
    ;

device: bjt
    | capacitor
    | diode
    | inductor
    | isource
    | jfet
    | mosfet
    | resistor
    | subcktinst
    | vsource
    | coupling
    ;

subcircuit: subckt
    ;

control_card: alter
    | control
    | data
    | dcvolt
    | dellib
    | end
    | endl
    | ends
    | global
    | icvolt
    | lib
    | model
    | nodeset
    | options
    | param
    | pc
    | protect
    | system
    | unprotect
    | width
    ;

analysis_card: acsweep
    | dcsweep
    | fourier
    | net
    | distortion
    | noise
    | oppoint
    | polezero
    | sample
    | sens
    | temp
    | transfer
    | tran
    ;

output_card: measure
    | graph
    | plot
    | print
    ;

other: title
    | comment
    ;

/*
 * devices
 */

bjt: BJT argument_list ARGSEND
        {
            yyCircuit->add_bjt($1,$2);
            DBG1(printf("seen BJT: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
capacitor: CAPACITOR argument_list ARGSEND
        {
            yyCircuit->add_capacitor($1,$2);
            DBG1(printf("seen CAPACITOR: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
diode: DIODE argument_list ARGSEND
        {
            yyCircuit->add_diode($1,$2);
            DBG1(printf("seen DIODE: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
inductor: INDUCTOR argument_list ARGSEND
        {
            yyCircuit->add_inductor($1,$2);
            DBG1(printf("seen INDUCTOR: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
;
coupling: COUPLING argument_list ARGSEND
        {
            yyCircuit->add_coupling($1,$2);
            DBG1(printf("seen COUPLING: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
isource: ISOURCE argument_list ARGSEND
        {
            yyCircuit->add_isource($1,$2);
            DBG1(printf("seen ISOURCE: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
jfet: JFET argument_list ARGSEND
        {
            yyCircuit->add_jfet($1,$2);
            DBG1(printf("seen JFET: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
mosfet: MOSFET argument_list ARGSEND
        {
            yyCircuit->add_mosfet($1,$2);
            DBG1(printf("seen MOSFET: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)
            
            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
resistor: RESISTOR argument_list ARGSEND
        {
            yyCircuit->add_resistor($1,$2);
            DBG1(printf("seen RESISTOR: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
subcktinst: SUBCKTINST argument_list ARGSEND
        {
            yyCircuit->add_subcktinst($1,$2);
            DBG1(printf("seen SUBCKTINST: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
vsource: VSOURCE argument_list ARGSEND
        {
            yyCircuit->add_vsource($1,$2);
            DBG1(printf("seen VSOURCE: %s ",$1);
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            free($1);
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;

/*
 * subcircuits
 */

subckt: SUBCKT argument_list ARGSEND
        {
            yyCircuit->begin_subckt($2);
            DBG1(printf("seen SUBCKT: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;

/*
 * control cards
 */

alter: ALTER
        {
            /* unimplemented */
            DBG1(printf("seen .ALTER\n");)
        }
    ;
control: CONTROL argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .CONTROL: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
data: DATA argument_list ENDDATA
        {
            /* unimplemented */
            DBG1(printf("seen .DATA: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
dcvolt: DCVOLT argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .DCVOLT: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
dellib: DELLIB argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .DELLIB: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
end: END argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .END: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    | END ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .END\n");)
        }
    ;
endl: ENDL argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .ENDL: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
ends: ENDS ends_arg ARGSEND
        {
            yyCircuit->end_subckt($2);
            DBG1(printf("seen .ENDS\n");)

            /* delete the arguments */
            delete $2;
        }
    ;
global: GLOBAL argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .GLOBAL: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
icvolt: ICVOLT argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .ICVOLT: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
lib:  LIB argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .LIB: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
model: MODEL simple_arg simple_arg ARGSEND
        {
            yyCircuit->add_model($2,$3,NULL);
            DBG1(printf("seen .MODEL: ");
            $2->dump(cout); cout<<" "; $3->dump(cout); cout<<" ";);
            
            /* delete the arguments */
            delete $2;
            delete $3;
        }
    | MODEL simple_arg simple_arg parameter_list ARGSEND
        {
            yyCircuit->add_model($2,$3,$4);
            DBG1(printf("seen .MODEL: ");
            $2->dump(cout); cout<<" "; $3->dump(cout); cout<<" ";
            for_each($4->begin(), $4->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            delete $2;
            delete $3;
            for(int i=0; i<$4->size(); i++)
                delete (*$4)[i];
            delete $4;
        }
    | MODEL simple_arg simple_arg '(' parameter_list ')' ARGSEND
        {
            yyCircuit->add_model($2,$3,$5);
            DBG1(printf("seen .MODEL: ");
            $2->dump(cout); cout<<" "; $3->dump(cout); cout<<" ";
            cout<<"(";
            for_each($5->begin(), $5->end(), G_dump<Argument *>(cout));
            cout<<")";
            cout<<endl;)
            
            /* delete the arguments */
            delete $2;
            delete $3;
            for(int i=0; i<$5->size(); i++)
                delete (*$5)[i];
            delete $5;
        }
    ;
nodeset: NODESET argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .NODESET: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
options: OPTIONS argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .OPTIONS: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
param: PARAM argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .PARAM: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
pc: PC argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .PC: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
protect: PROTECT
        {
            /* unimplemented */
            DBG1(printf("seen .PROTECT\n");)
        }
    ;
system: SYSTEM argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .SYSTEM: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
unprotect: UNPROTECT
        {
            /* unimplemented */
            DBG1(printf("seen .UNPROTECT\n");)
        } 
    ;
width: WIDTH argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .WIDTH: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;

/*
 * Analysis Cards
 */

acsweep: ACSWEEP argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .ACSWEEP: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
dcsweep: DCSWEEP argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .DCSWEEP: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
fourier: FOURIER argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .FOURIER: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
net: NET argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .NET: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
distortion: DISTORTION argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .DISTORTION: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
noise: NOISE argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .NOISE: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
oppoint: OPPOINT ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .OPPOINT: ");
            cout<<endl;)
        }
    | OPPOINT argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .OPPOINT: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
polezero: POLEZERO argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .POLEZERO: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
sample: SAMPLE argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .SAMPLE: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
sens: SENS argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .SENSE: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
temp: TEMP argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .TEMP: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
transfer: TRANSFER argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .TRANSFER: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
tran: TRAN argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .TRAN: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
 
/*
 * Output Cards
 */

measure: MEASURE argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .MEASURE: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
graph: GRAPH argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .GRAPH: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
plot: PLOT argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .plot: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;
print: PRINT argument_list ARGSEND
        {
            /* unimplemented */
            DBG1(printf("seen .PRINT: ");
            for_each($2->begin(), $2->end(), G_dump<Argument *>(cout));
            cout<<endl;)

            /* delete the arguments */
            for(int i=0; i<$2->size(); i++)
                delete (*$2)[i];
            delete $2;
        }
    ;

/*
 * Other
 */

title: TITLE
        {
            /* title */
            yyCircuit->name() = strdup($1);
            DBG1(cout<<"title: "<<$1<<endl;)

            /* delete the arguments */
            free($1);
        }
    ; 
comment: COMMENT
        {
            /* comment */
            StringArgument *temp = new StringArgument($1);
            yyCircuit->process_comment((StringArgument *)temp);
            DBG1(cout<<endl<<"comment: "; temp->dump(cout); cout<<endl<<endl;);

            /* delete the arguments */
            delete temp;
        }
;
/*
 * Arguments
 */

argument_list: argument
        {
            /* argument_list #1 */
            ArgumentVec *the_list = new ArgumentVec;
            the_list->push_back($1);
            $$ = the_list;
        }
    | argument_list argument
        {
            /* argument_list #2 */
            $1->push_back($2);
        }
    ;

simple_argument_list: simple_arg
        {
            /* simple_argument_list #1 */
            ArgumentVec *the_list = new ArgumentVec;
            the_list->push_back($1);
            $$ = the_list;
        }
    | simple_argument_list simple_arg
        {
            /* simple_argument_list #2 */
            $1->push_back($2);
        }
    | simple_argument_list ',' simple_arg
        {
            /* simple_argument_list #3 */
            $1->push_back($3);
        }
    ;

parameter_list: parameter
        {
            /* parameter_list #1 */
            ArgumentVec *the_list = new ArgumentVec;
            the_list->push_back($1);
            $$ = the_list;
        }
    | parameter_list parameter
        {
            /* parameter_list #2 */
            $1->push_back($2);
        }
    ;

argument: simple_arg
        {
            /* argument #1 */
            $$ = $1;
        }
    | complex_arg
        {
            /* argument #2 */
            $$ = $1;
        }
    ;

simple_arg: ARGIDENT
        {
            /* simple_arg #1 */
            $$ = new StringArgument($1);
        }
    | ARGINT ARGUNIT
        {
            /* simple_arg #2 */
            double num = atof($1);
            num = adjust_number(num,$2);
            $$ = new DoubleArgument(num);
            free ($1);
            free ($2);
        }
    | ARGINT
        {
            /* simple_arg #3 */
            int num = atoi($1);
            $$ = new IntegerArgument(num);
            free ($1);
        }
    | ARGINT ':'
        {
            /* simple_arg #4 */
            int num = atoi($1);
            $$ = new IntegerArgument(num);
            free ($1);
        }
    | ARGDECIMAL ARGUNIT
        {
            /* simple_arg #5 */
            double num = atof($1);
            num = adjust_number(num,$2);
            $$ = new DoubleArgument(num);
            free ($1);
            free ($2);
        }
    | ARGDECIMAL
        {
            /* simple_arg #6 */
            double num = atof($1);
            $$ = new DoubleArgument(num);
            free ($1);
        }
    | ARGFLOAT
        { 
            /* simple_arg #7 */
            double num = atof($1);
            $$ = new DoubleArgument(num);
            free ($1);
        }
    | quoted_string
        {
            /* simple_arg #8 */
            $$ = $1;
        }
    ;

complex_arg: function
        {
            /* complex_arg #1 */
            $$ = $1;
        }
    | parameter
        {
            /* complex_arg #2 */
            $$ = $1;
        }
    | node_assignment
        {
            /* complex_arg #3 */
            $$ = $1;
        }
    ;

function: ARGIDENT '(' simple_argument_list ')'
        {
            /* function */
            $$ = new FunctionArgument($1,$3);
        } 
    ;

parameter: ARGIDENT '=' param_list
        {
            /* parameter */
            $$ = new ParameterArgument($1,$3);
        } 
    ;

node_assignment: function '=' param_list
        {
            /* node_assignment */
            $$ = new NodeAssignmentArgument($1,$3);
        }
    ;

quoted_string: OPENQUOTE QUOTESTRING CLOSEQUOTE
        {
            /* quoted_string */
            $$ = new StringArgument($2);
        }
;

param_list: param_val
        {
            /* param_list #1 */
            ArgumentVec *the_list = new ArgumentVec;
            the_list->push_back($1);
            $$ = the_list;
        }
    | param_list ',' param_val
        {
            /* param_list #2 */
            $1->push_back($3);
        }
    ;

param_val: simple_arg {$$ = $1;}
    ;

ends_arg:
        {
            /* ends_arg #1 */
            $$ = NULL;
            DBG1(printf("Ending current subckt definition\n");)
        }
    | ARGIDENT
        {
            /* ends_arg #2 */
            $$ = new StringArgument($1);
            DBG1(printf("Ending subckt %s definition\n",$1);)
        }
    ;
%%

//
// global functions for yacc and flex generated code
//

// takes a double number and multiplies it by an appropriate
// scaling factor specified by the "unit" sting
double adjust_number (double num, char *unit) {

    if (!strncmp("MEG",unit,3)) {
        num *= pow(10.0,6.0);
    }
    else if (!strncmp("MI",unit,2)) {
        num *= (25.40 * pow(10,6.0));
    }
    else {
        switch(unit[0]) {
            case 'F':
            case 'f':
                num *= pow(10.0,-15.0);
                break;
            case 'P':
            case 'p':
                num *= pow(10.0,-12.0);
                break;
            case 'N':
            case 'n':
                num *= pow(10.0,-9.0);
                break;
            case 'U':
            case 'u':
                num *= pow(10.0,-6.0);
                break;
            case 'M':
            case 'm':
                num *= pow(10.0,-3.0);
                break;
            case 'K':
            case 'k':
                num *= pow(10.0,3.0);
                break;
            case 'G':
            case 'g':
                num *= pow(10.0,9.0);
                break;
            default:
                break;
        }
    }
    return num;
}        

// override default error reporting
void yyerror(char *msg) {
    extern int lineno;   // from flex lexer
    extern char *yytext; // from flex lexer

    fprintf(stderr, "line #%d: %s at '%s'\n",lineno,msg,yytext);
}

// override default yyin file
int yywrap() {

    FILE *file = 0;

    if ((currentFile != 0) && (nFiles > 1) && (currentFile < nFiles))
        fclose(yyin);

    while (currentFile < nFiles){
        file = fopen((*fileList)[currentFile++], "r");
        if (file != NULL) {
            yyin = file;
            break;
        }
        sprintf(error_msg, "could not open %s\n",(*fileList)[currentFile-1]);
        Abort(error_msg);
    }
    return (file ? 0 : 1);
}

// class method that calls the yacc parser
int hspice_parser::parse (vector<char*> *files) {

    currentFile = 0;
    fileList = files;
    nFiles = fileList->size();

    yyCircuit = &_circuit;
    
    // debugging
    yy_flex_debug = 0;   // enables debugging in flex when called with -d  flag
    yydebug = 0;         // enables debugging in yacc when called with -t flag
           
    if (nFiles < 1)
        return 0;

    yywrap();
    while (!feof(yyin)) {
        yyparse();
    }
    return 1;
}
