Some more $table_model() changes.

The code should be able to correctly parse any command string and
assign the appropriate values from the file to a structure that will
be used to add the information to the table structure.
This commit is contained in:
Cary R 2011-05-02 19:53:41 -07:00 committed by Stephen Williams
parent 0597b56ba2
commit b13c899b89
4 changed files with 161 additions and 98 deletions

View File

@ -31,53 +31,6 @@
*/
static unsigned table_model_debug = 0;
// HERE: Should these just be defines?
/*
* Define the allowed interpolation control values.
*/
typedef enum interp_type_e {
IVL_CLOSEST_POINT = 0, /* D */
IVL_LINEAR_INTERP = 1, /* 1 - Default */
IVL_QUADRATIC_INTERP = 2, /* 2 */
IVL_CUBIC_INTERP = 3, /* 3 */
IVL_IGNORE_COLUMN = 4 /* I */
} interp_type_t;
/*
* Define the allowed extrapolation control values.
*/
typedef enum extrap_type_e {
IVL_CONSTANT_EXTRAP = 0, /* C */
IVL_LINEAR_EXTRAP = 1, /* L - Default */
IVL_ERROR_EXTRAP = 2 /* E */
} extrap_type_t;
/*
* This structure is saved for each table model instance.
*/
typedef struct t_table_mod {
vpiHandle *indep; /* Independent variable arguments. */
double *indep_val; /* Current independent variable values. */
union { /* Data file or argument to get the data file. */
char *name;
vpiHandle arg;
} file;
union { /* Control string argument. */
struct {
char *interp;
char *extrap_low;
char *extrap_high;
} info;
vpiHandle arg;
} control;
// HERE need a pointer to the dependent data and the final table.
unsigned dims; /* The number of independent variables. */
unsigned fields; /* The number of control fields. */
unsigned depend; /* Where the dependent column is located. */
char have_fname; /* Has the file name been allocated? */
char have_ctl; /* Has the file name been allocated? */
} s_table_mod, *p_table_mod;
static p_table_mod *tables = 0;
static unsigned table_count = 0;
@ -382,7 +335,7 @@ static unsigned parse_extrap(vpiHandle callh, p_table_mod table, unsigned idx,
static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table,
char *control)
{
unsigned width, idx;
unsigned num_fields, num_ignore, idx;
char *cp;
/* If we need to fail these must be defined to zero until memory
@ -413,7 +366,7 @@ static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table,
vpi_printf("Control string dependent selector is "
"invalid: %s.\n", cp);
vpi_control(vpiFinish, 1);
return 0;
return 1;
}
val = strtoul(cp, &end, 10);
assert(*end == 0);
@ -424,39 +377,41 @@ static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table,
vpi_printf("Control string dependent value is "
"to large: %lu.\n", val);
vpi_control(vpiFinish, 1);
return 0;
return 1;
}
table->depend = (unsigned) val;
} else table->depend = 1;
/* Find the number of interpolation/extrapolation control fields. */
width = 1;
num_fields = 1;
cp = control;
while ((cp = index(cp, ','))) {
cp += 1;
width += 1;
num_fields += 1;
}
/* We must have at least as many control fields as dimensions. */
if (width < table->dims) {
if (num_fields < table->dims) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Not enough control field(s) (%u) for the dimension(s) "
"(%u).", width, table->dims);
"(%u).", num_fields, table->dims);
vpi_control(vpiFinish, 1);
return 0;
return 1;
}
/* Allocate space for the interpolation/extrapolation values. */
table->control.info.interp = (char *) malloc(width);
table->control.info.interp = (char *) malloc(num_fields);
assert(table->control.info.interp);
table->control.info.extrap_low = (char *) malloc(width);
table->control.info.extrap_low = (char *) malloc(num_fields);
assert(table->control.info.extrap_low);
table->control.info.extrap_high = (char *) malloc(width);
table->control.info.extrap_high = (char *) malloc(num_fields);
assert(table->control.info.extrap_high);
/* Parse the individual dimension control string. */
num_ignore = 0;
cp = control;
for (idx = 0; idx < width; idx += 1) {
for (idx = 0; idx < num_fields; idx += 1) {
switch (*cp) {
/* Closest point interpolation. */
case 'D':
@ -485,12 +440,16 @@ static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table,
/* Ignore column. No extrapolation codes are allowed. */
case 'I':
table->control.info.interp[idx] = IVL_IGNORE_COLUMN;
table->control.info.extrap_low[idx] = IVL_ERROR_EXTRAP;
table->control.info.extrap_high[idx] = IVL_ERROR_EXTRAP;
cp += 1;
num_ignore += 1;
break;
/* This field is not specified so use the default values.
* Linear interpolation and extrapolation. */
case 0:
assert(idx == width-1);
assert(idx == num_fields-1);
case ',':
table->control.info.interp[idx] = IVL_LINEAR_INTERP;
table->control.info.extrap_low[idx] = IVL_LINEAR_EXTRAP;
@ -504,7 +463,7 @@ static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table,
vpi_printf("Unknown interpolation code '%c' for dimension "
"%u: %s\n", *cp, idx+1, control);
vpi_control(vpiFinish, 1);
return 0;
return 1;
}
/* Verify that there is no extra junk at the end of the field. */
@ -514,7 +473,7 @@ static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table,
vpi_printf("Extra control characters found for dimension "
"%u: %s\n", idx+1, control);
vpi_control(vpiFinish, 1);
return 0;
return 1;
}
/* Advance to the next field if we are not at the end of the
@ -522,9 +481,20 @@ static unsigned initialize_control_fields(vpiHandle callh, p_table_mod table,
if (*cp == ',') cp += 1;
}
/* Return the number of fields plus the dependent offset as the
* minimum number of fields. */
return (width + table->depend);
/* We must have a usable control field for each dimensions. */
if ((num_fields - num_ignore) != table->dims) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Usable control field(s) (%u) do not match dimension(s) "
"(%u).", (num_fields - num_ignore), table->dims);
vpi_control(vpiFinish, 1);
return 1;
}
/* Set the number of control fields. */
table->fields = num_fields;
return 0;
}
/*
@ -563,7 +533,7 @@ static void dump_diag_info(vpiHandle callh, p_table_mod table)
unsigned idx;
char msg[64];
snprintf(msg, sizeof(msg), "%s:%d: DEBUG:", vpi_get_str(vpiFile, callh),
snprintf(msg, sizeof(msg), "DEBUG: %s:%d:", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
msg[sizeof(msg)-1] = 0;
fprintf(stderr, "%s Building %u variable table using \"%s\" and\n",
@ -638,11 +608,7 @@ static unsigned initialize_table_model(vpiHandle callh, const char *name,
/* Parse the given file and produce the basic data structure. We
* need to have columns for each control string field and for the
* dependent data. */
// HERE: This is going to return a pointer to the data.
if (! parse_table_model(fp, table->file.name, callh,
table->fields, table->depend)) {
return 1;
}
if (parse_table_model(fp, callh, table)) return 1;
// HERE: once we are done with the control string should we build a table
// of function pointer for the interp/extrap?

View File

@ -21,8 +21,78 @@
#include <stdio.h>
#include <vpi_user.h>
extern int parse_table_model(FILE *fp, const char *file_name, vpiHandle callh,
unsigned indep__cols, unsigned dep_col);
/*
* Define the allowed interpolation control values.
*/
#define IVL_CLOSEST_POINT 0 /* D */
#define IVL_LINEAR_INTERP 1 /* 1 - Default */
#define IVL_QUADRATIC_INTERP 2 /* 2 */
#define IVL_CUBIC_INTERP 3 /* 3 */
#define IVL_IGNORE_COLUMN 4 /* I */
/*
* Define the allowed extrapolation control values.
*/
#define IVL_CONSTANT_EXTRAP 0 /* C */
#define IVL_LINEAR_EXTRAP 1 /* L - Default */
#define IVL_ERROR_EXTRAP 2 /* E */
/*
* Structure that represents an individual iso line element.
*/
typedef struct t_indep {
double value;
struct t_indep *left; /* previous element. */
struct t_indep *right; /* next element. */
union {
double data;
struct t_indep *child;
struct t_build *build;
} data;
} s_indep, *p_indep;
/*
* This is used as an interface element while building the iso lines. It will
* be removed when the list is converted to a balanced threaded tree. It is
* used to make in order insertion faster.
*/
typedef struct t_build {
p_indep first;
p_indep last;
unsigned count;
} s_build, *p_build;
/*
* This structure is saved for each table model instance.
*/
typedef struct t_table_mod {
vpiHandle *indep; /* Independent variable arguments. */
double *indep_val; /* Current independent variable values. */
union { /* Data file or argument to get the data file. */
char *name;
vpiHandle arg;
} file;
union { /* Control string argument. */
struct {
char *interp;
char *extrap_low;
char *extrap_high;
} info;
vpiHandle arg;
} control;
// HERE need a pointer to the dependent data and the final table.
unsigned dims; /* The number of independent variables. */
unsigned fields; /* The number of control fields. */
unsigned depend; /* Where the dependent column is located. */
char have_fname; /* Has the file name been allocated? */
char have_ctl; /* Has the file name been allocated? */
} s_table_mod, *p_table_mod;
/*
* Define the non-static table model routines.
*/
extern unsigned parse_table_model(FILE *fp, vpiHandle callh, p_table_mod table);
extern int tblmodlex();
extern void destroy_tblmod_lexor();

View File

@ -53,7 +53,7 @@ SCALE [afpnumkKMGT]
{EOL} {
tblmodlloc.first_line += 1;
return EOL;
return END_LINE;
}
/* Recognize a real value with a Verilog-AMS scale. */

View File

@ -24,13 +24,17 @@
#include "table_mod.h"
#include "ivl_alloc.h"
static unsigned errors = 0;
static unsigned minimum_columns;
static unsigned indep_values;
static unsigned indep_columns;
static unsigned dep_column;
static unsigned number_of_columns = 0;
static unsigned cur_columns;
static unsigned cur_value;
static double *values;
static const char *in_file_name;
static p_table_mod table_def;
extern int tblmodlex(void);
static void yyerror(const char *fmt, ...);
@ -43,7 +47,7 @@ static void yyerror(const char *fmt, ...);
double real;
};
%token EOL
%token END_LINE
%token <real> REAL
%%
@ -51,14 +55,16 @@ static void yyerror(const char *fmt, ...);
table : point
| table point
point : columns EOL
point : columns END_LINE
{
unsigned idx;
fprintf(stderr, "%#g", values[0]);
for (idx = 1; idx < indep_columns; idx += 1) {
fprintf(stderr, ", %#g", values[idx]);
}
fprintf(stderr, " => %#g\n", values[indep_columns]);
#if 0
unsigned idx;
fprintf(stderr, "%#g", values[0]);
for (idx = 1; idx < indep_values; idx += 1) {
fprintf(stderr, ", %#g", values[idx]);
}
fprintf(stderr, " => %#g\n", values[indep_values]);
#endif
if (number_of_columns) {
if (cur_columns < minimum_columns) {
yyerror("Found %u columns, need at least %u.",
@ -77,43 +83,64 @@ point : columns EOL
columns : REAL
{
values[0] = $1;
if (table_def->control.info.interp[0] != IVL_IGNORE_COLUMN) {
values[0] = $1;
cur_value = 1;
} else cur_value = 0;
cur_columns = 1;
}
| columns REAL
{
if (cur_columns < indep_columns) values[cur_columns] = $2;
else if (cur_columns == dep_column) values[indep_columns] = $2;
if (cur_columns < indep_columns) {
if (table_def->control.info.interp[cur_columns] !=
IVL_IGNORE_COLUMN) {
values[cur_value] = $2;
cur_value += 1;
}
} else if (cur_columns == dep_column) values[indep_values] = $2;
cur_columns += 1;
}
%%
int parse_table_model(FILE *fp, const char *file_name, vpiHandle callh,
unsigned indep_cols, unsigned dep_col)
unsigned parse_table_model(FILE *fp, vpiHandle callh, p_table_mod table)
{
assert(indep_cols > 1);
assert(dep_col > 0);
indep_columns = indep_cols;
minimum_columns = indep_cols + dep_col;
unsigned rtn = 0;
assert(table);
assert(table->fields > 0);
assert(table->depend > 0);
table_def = table;
indep_values = table->dims;
indep_columns = table->fields;
minimum_columns = table->fields + table->depend;
dep_column = minimum_columns - 1;
values = malloc(sizeof(double)*(indep_cols+1));
values = malloc(sizeof(double)*(indep_values+1));
assert(values);
in_file_name = file_name;
in_file_name = table->file.name;
init_tblmod_lexor(fp);
yyparse();
if (yyparse()) errors += 1;
if (errors) {
vpi_printf("ERROR: %s:%u: ", vpi_get_str(vpiFile, callh),
(int) vpi_get(vpiLineNo, callh));
vpi_printf("Had %u error(s) while reading table file.\n", errors);
rtn = 1;
}
destroy_tblmod_lexor();
free(values);
// HERE: Need to handle errors.
return 1;
return rtn;
}
/*
* Because every parse error is reported after the newline subtract one from
* the line count.
*/
void yyerror(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%u: TABLE ERROR: ", in_file_name, yylloc.first_line);
fprintf(stderr, "%s:%u: TABLE ERROR: ", in_file_name,
yylloc.first_line-1);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
errors += 1;
}