diff --git a/src/include/ngspice/mifparse.h b/src/include/ngspice/mifparse.h index fcd5e98e1..b82ef98d5 100644 --- a/src/include/ngspice/mifparse.h +++ b/src/include/ngspice/mifparse.h @@ -101,8 +101,8 @@ struct Mif_Param_Info { char *name; /* Name of this parameter */ char *description; /* Description of this parameter */ Mif_Data_Type_t type; /* Is this a real, boolean, string, ... */ - Mif_Boolean_t has_default; /* True if there is a default value */ - Mif_Parse_Value_t default_value; /* The default value */ + int default_value_siz;/* Size of default_values array. */ + Mif_Parse_Value_t *default_values; /* The default values (array). */ Mif_Boolean_t has_lower_limit; /* True if there is a lower limit */ Mif_Parse_Value_t lower_limit; /* The lower limit for this parameter */ Mif_Boolean_t has_upper_limit; /* True if there is a upper limit */ diff --git a/src/xspice/cmpp/cmpp.h b/src/xspice/cmpp/cmpp.h index ab93f9ce4..ff5bd45c2 100644 --- a/src/xspice/cmpp/cmpp.h +++ b/src/xspice/cmpp/cmpp.h @@ -208,8 +208,8 @@ typedef struct { char *name; /* Name of this parameter */ char *description; /* Description of this parameter */ Data_Type_t type; /* Data type, e.g. REAL, INTEGER, ... */ - bool has_default; /* True if there is a default value */ - Value_t default_value; /* The default value */ + int default_value_idx;/* Start of default_values.. */ + int default_value_cnt;/* Number of default_values.. */ bool has_lower_limit; /* True if there is a lower limit */ Value_t lower_limit; /* The lower limit for this parameter */ bool has_upper_limit; /* True if there is a upper limit */ @@ -239,7 +239,14 @@ typedef struct { } Inst_Var_Info_t; +/* Structure used when parsing default values from the IFS file, used below. */ +typedef struct { + bool has_value; + bool advance; // Used for vector default values. + Data_Type_t kind; + Value_t u; // Union holding the value. +} My_Value_t; /* * The all encompassing structure for the ifs table information @@ -254,7 +261,8 @@ typedef struct { Param_Info_t *param; /* Array of parameter info structs */ int num_inst_var; /* Number of entries in the instance var table(s) */ Inst_Var_Info_t *inst_var; /* Array of instance variable info structs */ - + int num_default_values; + My_Value_t *defaults_var; /* Array of annotated values. */ } Ifs_Table_t; diff --git a/src/xspice/cmpp/ifs_yacc.y b/src/xspice/cmpp/ifs_yacc.y index 6bc55a3a7..a0a97512d 100644 --- a/src/xspice/cmpp/ifs_yacc.y +++ b/src/xspice/cmpp/ifs_yacc.y @@ -115,16 +115,14 @@ Ifs_Table_t *parser_ifs_table; int ifs_num_errors; -static size_t alloced_size [4]; +/* Allocated and initial sizes of tables for parse results. */ -/* - * !!!!! Make sure these are large enough so that they never get realloced - * !!!!! since that will cause garbage uninitialized data... - * !!!!! (FIX THIS!) - */ -#define DEFAULT_SIZE_CONN 100 -#define DEFAULT_SIZE_PARAM 100 -#define DEFAULT_SIZE_INST_VAR 100 +static size_t alloced_size [5]; + +#define DEFAULT_SIZE_CONN 10 +#define DEFAULT_SIZE_PARAM 10 +#define DEFAULT_SIZE_INST_VAR 10 +#define DEFAULT_SIZE_DEFAULTS 100 #define GROW_SIZE 10 typedef enum { @@ -132,6 +130,7 @@ typedef enum { TBL_PORT, TBL_PARAMETER, TBL_STATIC_VAR, + TBL_DEFAULTS, } Table_t; typedef struct { @@ -368,15 +367,19 @@ assign_limits (Data_Type_t type, Param_Info_t *param, Range_t range) } /*---------------------------------------------------------------------------*/ +/* Advance the item variable, checking for table overflow. */ + static void check_item_num (void) { + item++; if (item-item_offset >= ITEM_BUFFER_SIZE) { - fatal ("Too many items in table - split into sub-tables"); + fatal("Too many items in table - split into sub-tables"); } - if (item > (int) alloced_size [context.table] ) { + if (item >= (int) alloced_size [context.table] ) { switch (context.table) { - case TBL_NAME: + case TBL_NAME: // Fixed size. + case TBL_DEFAULTS: // Handled in store_default_value(). break; case TBL_PORT: alloced_size[context.table] += GROW_SIZE; @@ -407,7 +410,6 @@ check_item_num (void) break; } } - item++; } /*---------------------------------------------------------------------------*/ @@ -429,6 +431,7 @@ check_end_item_num (void) num_items_fixed = true; switch (context.table) { case TBL_NAME: + case TBL_DEFAULTS: break; case TBL_PORT: TBL->num_conn = num_items; @@ -445,11 +448,38 @@ check_end_item_num (void) } #define INIT(n) item = (n); item_offset = (n); num_items = (n); num_items_fixed = false -#define ITEM check_item_num() -#define END check_end_item_num() +#define ITEM check_item_num() // Advances the item_buffer index. +#define END check_end_item_num() // Check for excessive values in later row. +/* Store a default value for a parameter. */ + +static void store_default_value(My_Value_t *vp) +{ + if (TBL->num_default_values >= alloced_size[TBL_DEFAULTS]) { + /* Expand table. */ + + alloced_size [TBL_DEFAULTS] += GROW_SIZE * 5; + TBL->defaults_var = (My_Value_t *) realloc(TBL->defaults_var, + alloced_size[TBL_DEFAULTS] * sizeof (My_Value_t)); + if (!TBL->defaults_var) { + fatal ("Error allocating memory for default parameter values"); + } + } + TBL->defaults_var[TBL->num_default_values++] = *vp; + if (vp->advance) + ITEM; // Count another parameter sub-table. +} + %} +/* The parser perfoms a double scan for each row (labelled line), with the + * row spanning multiple sub-tables (individual connection definitions etc.). + * Values and other information are copied into the item_buffer[] + * array as they are recognised and then moved to their destination stucture + * TBL->xxxx[index] when the whole row has been parsed. Default parameter + * values are hndled differently and copied directly to TBL->defaults_var. + */ + %token TOK_ALLOWED_TYPES %token TOK_ARRAY %token TOK_ARRAY_BOUNDS @@ -501,6 +531,10 @@ check_end_item_num (void) %token TOK_SPICE_MODEL_NAME %token TOK_STRING_LITERAL + /* This declares the type of Bison's "semantic values" (the value associated + * with an instance of a symbol of the grammer, $$), defining YYSTYPE. + */ + %union { Ctype_List_t *ctype_list; Dir_t dir; @@ -549,6 +583,7 @@ YYSTYPE item_buffer [ITEM_BUFFER_SIZE]; ifs_file : {TBL->num_conn = 0; TBL->num_param = 0; TBL->num_inst_var = 0; + TBL->num_default_values = 0; saw_function_name = false; saw_model_name = false; @@ -556,14 +591,18 @@ ifs_file : {TBL->num_conn = 0; alloced_size [TBL_PORT] = DEFAULT_SIZE_CONN; alloced_size [TBL_PARAMETER] = DEFAULT_SIZE_PARAM; alloced_size [TBL_STATIC_VAR] = DEFAULT_SIZE_INST_VAR; + alloced_size [TBL_DEFAULTS] = DEFAULT_SIZE_DEFAULTS; TBL->conn = (Conn_Info_t*) calloc(DEFAULT_SIZE_CONN, sizeof (Conn_Info_t)); TBL->param = (Param_Info_t*) - calloc (DEFAULT_SIZE_PARAM, sizeof (Param_Info_t)); + calloc (DEFAULT_SIZE_PARAM, sizeof (Param_Info_t)); TBL->inst_var = (Inst_Var_Info_t*) - calloc (DEFAULT_SIZE_INST_VAR, sizeof (Inst_Var_Info_t)); - if (! (TBL->conn && TBL->param && TBL->inst_var) ) { + calloc (DEFAULT_SIZE_INST_VAR, sizeof (Inst_Var_Info_t)); + TBL->defaults_var = (My_Value_t *) + calloc(DEFAULT_SIZE_DEFAULTS, sizeof (My_Value_t)); + if (! (TBL->conn && TBL->param && + TBL->inst_var && TBL->defaults_var) ) { fatal ("Could not allocate enough memory"); } } @@ -701,18 +740,8 @@ parameter_table_item : TOK_PARAMETER_NAME list_of_ids check_dtype_not_pointer (ITEM_BUF(i).dtype); TBL->param[i].type = ITEM_BUF(i).dtype; }} - | TOK_DEFAULT_VALUE list_of_values - {int i; - END; - FOR_ITEM (i) { - TBL->param[i].has_default = - ITEM_BUF(i).value.has_value; - if (TBL->param[i].has_default) { - assign_value (TBL->param[i].type, - &TBL->param[i].default_value, - ITEM_BUF(i).value); - } - }} + | TOK_DEFAULT_VALUE list_of_default_values + {END; } // Check against current sub-table count. | TOK_LIMITS list_of_ranges {int i; END; @@ -870,15 +899,22 @@ number_or_dash : TOK_DASH {$$.has_bound = false;} $$.bound = $1;} ; -list_of_values : /* empty */ - | list_of_values value_or_dash {ITEM; BUF.value = $2;} +list_of_pure_values : value { $1.advance = 1; store_default_value(&$1); } + | list_of_pure_values value + { $2.advance = 0; store_default_value(&$2); } ; +list_of_default_values : /* empty */ + | list_of_default_values value_or_dash + { $2.advance = 1; store_default_value(&$2); } + | list_of_default_values + TOK_LBRACKET list_of_pure_values TOK_RBRACKET + value_or_dash : TOK_DASH {$$.has_value = false;} | value ; -value : string {$$.has_value = true; +value : string {$$.has_value = true; $$.kind = CMPP_STRING; $$.u.svalue = $1;} | btype {$$.has_value = true; diff --git a/src/xspice/cmpp/ifs_yacc_y.h b/src/xspice/cmpp/ifs_yacc_y.h index 745e06cd0..88083fcdc 100644 --- a/src/xspice/cmpp/ifs_yacc_y.h +++ b/src/xspice/cmpp/ifs_yacc_y.h @@ -39,18 +39,6 @@ NON-STANDARD FEATURES #include "cmpp.h" -typedef struct { - bool has_value; - Data_Type_t kind; - union { - bool bvalue; - int ivalue; - double rvalue; - Complex_t cvalue; - char *svalue; - } u; -} My_Value_t; - typedef struct { bool has_bound; My_Value_t bound; diff --git a/src/xspice/cmpp/writ_ifs.c b/src/xspice/cmpp/writ_ifs.c index 21b46f8af..9a9718a59 100644 --- a/src/xspice/cmpp/writ_ifs.c +++ b/src/xspice/cmpp/writ_ifs.c @@ -42,6 +42,10 @@ NON-STANDARD FEATURES #include #include #include +#ifndef _MSC_VER +#include +#endif + #include "cmpp.h" /* Local function prototypes */ @@ -183,6 +187,8 @@ EXITPOINT: filename, strerror(errno)); xrc = -1; } + if (xrc < 0 && filename) + unlink(filename); // So "make" will not see it. } if (filename != (char *) NULL) { @@ -680,29 +686,91 @@ static int write_param_info( FILE *fp, /* File to write to */ Ifs_Table_t *ifs_table) /* Table of Interface Specification data */ { - int xrc = 0; - int i; - const char *str; - + Param_Info_t * const param = ifs_table->param; + const int num_param = ifs_table->num_param; + int rc, xrc = 0; + int i, dv_idx; + const char *str; /* Only write the paramTable if there is something to put in it. */ /* Otherwise, we will put NULL in the SPICEdev structure in its slot */ - if (ifs_table->num_param == 0) { + if (num_param <= 0) { return 0; } + /* Write the default values for each parameter. */ - /* Write the structure beginning */ - int rc = 0; + for (i = 0, dv_idx = 0, rc = 0; i < num_param; i++) { + Param_Info_t * p_param_cur = param + i; + My_Value_t * p_val = ifs_table->defaults_var + dv_idx; + int start_index = dv_idx; + + if (dv_idx >= ifs_table->num_default_values) { + fprintf(stderr, "Not enough default values for parameter: %s.\n", + p_param_cur->name); + return 1; + } + + if (!p_val->has_value) { + /* Dummy entry, no default values. */ + + ++dv_idx; + p_param_cur->default_value_cnt = 0; + continue; + } + rc |= fprintf(fp, "static struct Mif_Parse_Value %s_default[] = {\n", + p_param_cur->name); + + do { // Write the default values for this parameter. + if (!p_val->advance && !p_param_cur->is_array) { + fprintf(stderr, + "Vector initialisation of default values " + "for non-vector parameter: %s.\n", + p_param_cur->name); + return 1; + } + + if (p_val->kind != p_param_cur->type) { + if (p_val->kind == CMPP_INTEGER && + p_param_cur->type == CMPP_REAL) { + /* Promote it. */ + + p_val->u.rvalue = p_val->u.ivalue; + } else { + fprintf(stderr, + "Data type of default value does not match for " + "parameter: %s.\n", + p_param_cur->name); + return 1; + } + } + + str = value_to_str(p_param_cur->type, p_val->u); + rc |= fprintf(fp, " %s,\n", str); + ++dv_idx; ++p_val; + } while (dv_idx < ifs_table->num_default_values && !p_val->advance); + + rc |= fprintf(fp, "};\n\n"); + p_param_cur->default_value_cnt = dv_idx - start_index; + } + + /* Check outputs */ + + if (rc < 0) { + print_error("Writing of default param values failed."); + return -1; + } + + /* Write the main parameter structure beginning. */ + + rc = 0; rc |= fprintf(fp, "\n" "static Mif_Param_Info_t MIFparamTable[] = {\n"); - /* Write out an entry for each parameter in the table */ - const Param_Info_t * const param = ifs_table->param; - const int num_param = ifs_table->num_param; + for (i = 0; i < num_param; i++) { const Param_Info_t * const p_param_cur = param + i; @@ -713,14 +781,11 @@ static int write_param_info( rc |= fprintf(fp, " %s,\n", data_type_to_str(p_param_cur->type)); - str = boolean_to_str(p_param_cur->has_default); - rc |= fprintf(fp, " %s,\n", str); - - if (p_param_cur->has_default == true) - str = value_to_str(p_param_cur->type, p_param_cur->default_value); + rc |= fprintf(fp, " %d,\n", p_param_cur->default_value_cnt); + if (p_param_cur->default_value_cnt) + rc |= fprintf(fp, " %s_default,\n", p_param_cur->name); else - str = no_value_to_str(); - rc |= fprintf(fp, " %s,\n", str); + rc |= fprintf(fp, " NULL,\n"); str = boolean_to_str(p_param_cur->has_lower_limit); rc |= fprintf(fp, " %s,\n", str); diff --git a/src/xspice/mif/mif_inp2.c b/src/xspice/mif/mif_inp2.c index e09d8c378..13304cc80 100644 --- a/src/xspice/mif/mif_inp2.c +++ b/src/xspice/mif/mif_inp2.c @@ -570,7 +570,7 @@ MIF_INP2A ( if(mdfast->param[i]->is_null) { char* emessage; - if(! param_info->has_default) { + if(param_info->default_value_siz == 0) { if (param_info->type == MIF_STRING) continue; // Allow NULL emessage = tprintf("Parameter %s on model %s has no default", diff --git a/src/xspice/mif/mifsetup.c b/src/xspice/mif/mifsetup.c index 8bac8705f..f280503a2 100644 --- a/src/xspice/mif/mifsetup.c +++ b/src/xspice/mif/mifsetup.c @@ -135,7 +135,6 @@ MIFsetup( for( ; model != NULL; model = MIFnextModel(model)) { - /* For each parameter not given explicitly on the .model */ /* card, default it */ @@ -151,42 +150,66 @@ MIFsetup( model->param[i]->size = 1; model->param[i]->element = TMALLOC(Mif_Value_t, 1); } else { /* parameter is an array */ - /* MIF_INP2A() parser assures that there is an associated array connection */ - /* Since several instances may share this model, we have to create an array */ - /* big enough for the instance with the biggest connection array */ - max_size = 0; - for(here = MIFinstances(model); here != NULL; here = MIFnextInstance(here)) { - size = here->conn[param_info->conn_ref]->size; - if(size > max_size) - max_size = size; + /* If there is an associated array connection, take the + * size from there. Since several instances may share + * this model, create an array big enough for the + * instance with the biggest connection array. + * Otherwise, use the size of the default. + */ + + if (param_info->has_conn_ref) { + for (here = MIFinstances(model), max_size = 0; + here != NULL; + here = MIFnextInstance(here)) { + size = here->conn[param_info->conn_ref]->size; + if (size > max_size) + max_size = size; + } + } else { + max_size = param_info->default_value_siz; + if (param_info->has_lower_bound && + param_info->lower_bound > max_size) { + max_size = param_info->lower_bound; + } } model->param[i]->size = max_size; model->param[i]->element = TMALLOC(Mif_Value_t, max_size); } /* end if parameter is an array */ - /* set the parameter element(s) to default value */ - for(j = 0; j < model->param[i]->size; j++) { + if (param_info->default_value_siz == 0) + continue; + /* Set the parameter element(s) to default value(s). */ + + for(j = 0; j < model->param[i]->size; j++) { + Mif_Parse_Value_t *dvp; + + if (j >= param_info->default_value_siz) { + dvp = param_info->default_values + + param_info->default_value_siz - 1; + } else { + dvp = param_info->default_values + j; + } switch(param_info->type) { case MIF_BOOLEAN: - model->param[i]->element[j].bvalue = param_info->default_value.bvalue; + model->param[i]->element[j].bvalue = dvp->bvalue; break; case MIF_INTEGER: - model->param[i]->element[j].ivalue = param_info->default_value.ivalue; + model->param[i]->element[j].ivalue = dvp->ivalue; break; case MIF_REAL: - model->param[i]->element[j].rvalue = param_info->default_value.rvalue; + model->param[i]->element[j].rvalue = dvp->rvalue; break; case MIF_COMPLEX: - model->param[i]->element[j].cvalue = param_info->default_value.cvalue; + model->param[i]->element[j].cvalue = dvp->cvalue; break; case MIF_STRING: - model->param[i]->element[j].svalue = param_info->default_value.svalue; + model->param[i]->element[j].svalue = dvp->svalue; break; default: