rewrite scope business,

use a tree structure to represent scopeing,
  instead of edge enumeration.

drop a check for "suitable" subckt,
  the scope dictates which .subckt is refered to.

drop a check for redefinition in numparm,
  numparm is definitly defect, it doesn't know about "scope"
The check did only check for some specific situations.

todo:
-  use the scope datastructure in numparm and subckt.c too
-  free the scope datastructure
This commit is contained in:
rlar 2016-11-09 18:40:05 +01:00
parent cdc1e16086
commit 5e6c6371a3
7 changed files with 188 additions and 207 deletions

View File

@ -149,11 +149,12 @@ static char *inp_pathresolve(const char *name);
static char *inp_pathresolve_at(char *name, char *dir);
static char *search_plain_identifier(char *str, const char *identifier);
void tprint(struct line *deck, int numb);
static void inp_add_levels(struct line *deck);
bool inp_check_scope_mod(unsigned short elem_level[], unsigned short mod_level[]);
bool inp_check_scope_sub(unsigned short x_level[], unsigned short subckt_level[]);
static struct nscope *inp_add_levels(struct line *deck);
static char inp_get_elem_ident(char *type);
static void inp_rem_unused_models(struct line *deck);
static void inp_rem_unused_models(struct nscope *root, struct line *deck);
static struct line_assoc *find_subckt(struct nscope *scope, const char *name);
static struct modellist *find_model(struct nscope *scope, const char *name);
struct inp_read_t
{ struct line *cc;
@ -169,9 +170,8 @@ static void inp_poly_err(struct line *deck);
static struct line *
xx_new_line(struct line *next, char *line, int linenum, int linenum_orig, unsigned short level[])
xx_new_line(struct line *next, char *line, int linenum, int linenum_orig, struct nscope *level)
{
int i;
struct line *x = TMALLOC(struct line, 1);
x->li_next = next;
@ -180,13 +180,7 @@ xx_new_line(struct line *next, char *line, int linenum, int linenum_orig, unsign
x->li_line = line;
x->li_linenum = linenum;
x->li_linenum_orig = linenum_orig;
if (level)
for (i = 0; i < NESTINGDEPTH; i++)
x->level[i] = level[i];
else
for (i = 0; i < NESTINGDEPTH; i++)
x->level[i] = 0;
x->level = level;
return x;
}
@ -522,7 +516,7 @@ inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile)
delete_libs();
inp_add_levels(working);
struct nscope *root = inp_add_levels(working);
inp_fix_for_numparam(subckt_w_params, working);
@ -531,7 +525,7 @@ inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile)
comment_out_unused_subckt_models(working);
// tprint(working, tpr++);
inp_rem_unused_models(working);
inp_rem_unused_models(root, working);
// tprint(working, tpr++);
subckt_params_to_param(working);
@ -2752,24 +2746,6 @@ inp_fix_subckt_multiplier(struct names *subckt_w_params, struct line *subckt_car
}
/* a bogus search for a .subckt with given name,
* which does not honour scoping rules
*/
static struct line *
bogus_find_subckt(struct line *d, const char *subckt_name)
{
const size_t len = strlen(subckt_name);
for (; d; d = d->li_next)
if (ciprefix(".subckt", d->li_line)) {
const char *n = skip_ws(skip_non_ws(d->li_line));
if ((strncmp(n, subckt_name, len) == 0) && (!n[len] || isspace_c(n[len])))
break;
}
return d;
}
static void
inp_fix_inst_calls_for_numparam(struct names *subckt_w_params, struct line *deck)
{
@ -2793,11 +2769,7 @@ inp_fix_inst_calls_for_numparam(struct names *subckt_w_params, struct line *deck
char *subckt_name = inp_get_subckt_name(inst_line);
if (found_mult_param(num_inst_params, inst_param_names)) {
struct line *d, *p = NULL;
// iterate through the deck to find the subckt (last one defined wins)
for (d = deck; (d = bogus_find_subckt(d, subckt_name)) != NULL; d = d->li_next)
p = d;
struct line *p = find_subckt(c->level, subckt_name)->line;
if (p) {
int num_subckt_params = inp_get_params(p->li_line, subckt_param_names, subckt_param_values);
@ -2833,7 +2805,8 @@ inp_fix_inst_calls_for_numparam(struct names *subckt_w_params, struct line *deck
if (find_name(subckt_w_params, subckt_name)) {
struct line *d;
for (d = deck; (d = bogus_find_subckt(d, subckt_name)) != NULL; d = d->li_next) {
d = find_subckt(c->level, subckt_name)->line;
{
char *subckt_line = d->li_line;
subckt_line = skip_non_ws(subckt_line);
subckt_line = skip_ws(subckt_line);
@ -2841,32 +2814,6 @@ inp_fix_inst_calls_for_numparam(struct names *subckt_w_params, struct line *deck
int num_subckt_params = inp_get_params(subckt_line, subckt_param_names, subckt_param_values);
int num_inst_params = inp_get_params(inst_line, inst_param_names, inst_param_values);
// make sure that if have inst params that one matches subckt
if (num_inst_params != 0) {
bool found_param_match = FALSE;
int j, k;
for (j = 0; j < num_inst_params; j++) {
for (k = 0; k < num_subckt_params; k++)
if (strcmp(subckt_param_names[k], inst_param_names[j]) == 0) {
found_param_match = TRUE;
break;
}
if (found_param_match)
break;
}
if (!found_param_match && inp_check_scope_sub(c->level, d->level)) {
// comment out .subckt and continue
while (d != NULL && !ciprefix(".ends", d->li_line)) {
*(d->li_line) = '*';
d = d->li_next;
}
*(d->li_line) = '*';
continue;
}
}
c->li_line = inp_fix_inst_line(inst_line, num_subckt_params, subckt_param_names, subckt_param_values, num_inst_params, inst_param_names, inst_param_values);
for (i = 0; i < num_subckt_params; i++) {
tfree(subckt_param_names[i]);
@ -2877,8 +2824,6 @@ inp_fix_inst_calls_for_numparam(struct names *subckt_w_params, struct line *deck
tfree(inst_param_names[i]);
tfree(inst_param_values[i]);
}
break;
}
}
@ -5922,10 +5867,9 @@ tprint(struct line *t, int numb)
if (*(tmp->li_line) != '*') {
fprintf(fd, "%6d %6d %s", tmp->li_linenum_orig, tmp->li_linenum, tmp->li_line);
fprintf(fd, " level: ");
int i;
for (i = 0; i < NESTINGDEPTH; i++) {
fprintf(fd, "%3d", tmp->level[i]);
}
struct nscope *x = tmp->level;
for (; x; x = x->next)
fprintf(fd, "/%p", tmp->level); /* fixme */
fprintf(fd, "\n");
}
fprintf(fd, "\n*********************************************************************************\n");
@ -6739,17 +6683,90 @@ inp_meas_current(struct line *deck)
}
static struct line_assoc *
find_subckt_1(struct nscope *scope, const char *name) {
struct line_assoc *p = scope->subckts;
for (; p; p = p->next)
if (eq(name, p->name))
break;
return p;
}
static struct line_assoc *
find_subckt(struct nscope *scope, const char *name) {
for(; scope; scope = scope->next) {
struct line_assoc *p = find_subckt_1(scope, name);
if (p)
return p;
}
return NULL;
}
static void
add_subckt(struct nscope *scope, struct line *subckt_line)
{
char *n = skip_ws(skip_non_ws(subckt_line->li_line));
char *name = copy_substring(n, skip_non_ws(n));
if (find_subckt_1(scope, name)) {
fprintf(stderr, "redefinition of .subckt %s\n", name);
exit(1);
}
struct line_assoc *entry = TMALLOC(struct line_assoc, 1);
entry->name = name;
entry->line = subckt_line;
entry->next = scope->subckts;
scope->subckts = entry;
}
/* linked list of models, includes use info */
struct modellist
{
struct line *model;
char *modelname;
bool used;
char elemb;
struct modellist *next;
};
static struct modellist *
find_model_1(struct nscope *scope, const char *name) {
struct modellist *p = scope->models;
for (; p; p = p->next)
if (model_name_match(name, p->modelname))
break;
return p;
}
static struct modellist *
find_model(struct nscope *scope, const char *name) {
for(; scope; scope = scope->next) {
struct modellist *p = find_model_1(scope, name);
if (p)
return p;
}
return NULL;
}
/* scan through deck and add level information to all struct line
* depending on nested subcircuits */
static void
static struct nscope *
inp_add_levels(struct line *deck)
{
struct line *card, *card_prev = deck;
int skip_control = 0, subs = 0, i;
unsigned short levelinfo[NESTINGDEPTH];
struct line *card;
int skip_control = 0;
for (i = 0; i < NESTINGDEPTH; i++)
levelinfo[i] = 0;
struct nscope *root = TMALLOC(struct nscope, 1);
root->next = NULL;
root->subckts = NULL;
root->models = NULL;
struct nscope *lvl = root;
for (card = deck; card; card = card->li_next) {
@ -6768,71 +6785,36 @@ inp_add_levels(struct line *deck)
continue;
}
if (*curr_line == '*')
continue;
if (*curr_line == '.') {
if (ciprefix(".subckt", curr_line)) {
levelinfo[subs++]++;
for (i = 0; i < NESTINGDEPTH; i++)
card->level[i] = levelinfo[i];
card_prev = card;
add_subckt(lvl, card);
card->level = lvl;
lvl = TMALLOC(struct nscope, 1);
// lvl->name = ..., or just point to the deck
lvl->next = card->level;
lvl->subckts = NULL;
lvl->models = NULL;
}
else if (ciprefix(".ends", curr_line)) {
subs--;
for (i = 0; i < NESTINGDEPTH; i++)
if (i < subs)
card->level[i] = card_prev->level[i];
else
card->level[i] = 0;
card_prev = card;
if (lvl == root) {
fprintf(stderr, ".suckt/.ends not balanced\n");
exit(1);
}
lvl = card->level = lvl->next;
}
else {
for (i = 0; i < NESTINGDEPTH; i++)
card->level[i] = card_prev->level[i];
card_prev = card;
card->level = lvl;
}
}
else {
for (i = 0; i < NESTINGDEPTH; i++)
card->level[i] = card_prev->level[i];
card_prev = card;
card->level = lvl;
}
}
}
if (lvl != root)
fprintf(stderr, "nesting error\n");
/* return TRUE if element is within scope of model */
bool
inp_check_scope_mod(unsigned short elem_level[], unsigned short mod_level[])
{
int i;
/* model at top level, accessible from all devices */
if (mod_level[0] == 0)
return TRUE;
/* model at nesting level */
for (i = 0; i < NESTINGDEPTH - 1; i++)
if ((elem_level[i] > 0) && (elem_level[i] == mod_level[i]) && (mod_level[i + 1] == 0))
return TRUE;
if ((elem_level[NESTINGDEPTH - 1] > 0) && (elem_level[NESTINGDEPTH - 1] == mod_level[NESTINGDEPTH - 1]))
return TRUE;
return FALSE;
}
/* not yet checked.
* Question: how to express overloading a sub at a lower level ? */
bool
inp_check_scope_sub(unsigned short x_level[], unsigned short subckt_level[])
{
int i;
/* subcircuit at top level, accessible from all x lines */
if ((subckt_level[0] > 0) && (subckt_level[1] == 0))
return TRUE;
for (i = 1; i < NESTINGDEPTH - 1; i++)
if ((x_level[i] == subckt_level[i]) && (x_level[i + 1] == 0))
return TRUE;
return FALSE;
return root;
}
@ -6896,23 +6878,41 @@ inp_get_elem_ident(char *type)
}
/* linked list of models, includes use info */
struct modellist
static void
rem_unused_xxx(struct nscope *level)
{
struct line *model;
char *modelname;
bool used;
char elemb;
struct modellist *next;
};
struct modellist *m = level->models;
while (m) {
struct modellist *next_m = m->next;
if (!m->used)
m->model->li_line[0] = '*';
tfree(m->modelname);
tfree(m);
m = next_m;
}
level->models = NULL;
struct line_assoc *p = level->subckts;
for (; p; p = p->next)
rem_unused_xxx(p->line->li_next->level);
}
static void
inp_rem_unused_models(struct line *deck)
mark_all_binned(struct nscope *scope, char *name)
{
struct modellist *p = scope->models;
for (; p; p = p->next)
if (model_name_match(name, p->modelname))
p->used = TRUE;
}
static void
inp_rem_unused_models(struct nscope *root, struct line *deck)
{
struct line *card;
struct modellist *modl = NULL, *modl_new;
int nested, i;
struct modellist *modn;
int skip_control = 0;
/* create a list of .model */
@ -6937,17 +6937,19 @@ inp_rem_unused_models(struct line *deck)
continue;
if (ciprefix(".model", curr_line)) {
struct modellist *modl_new;
modl_new = TMALLOC(struct modellist, 1);
char *model_type = get_model_type(curr_line);
modl_new->elemb = inp_get_elem_ident(model_type);
modl_new->modelname = get_subckt_model_name(curr_line);
modl_new->model = card;
modl_new->used = FALSE;
modl_new->next = modl;
modl = modl_new;
modl_new->next = card->level->models;
card->level->models = modl_new;
tfree(model_type);
}
}
/* scan through all element lines that require or may need a model */
for (card = deck; card; card = card->li_next) {
@ -6986,10 +6988,6 @@ inp_rem_unused_models(struct line *deck)
break;
}
for (nested = 0; nested < NESTINGDEPTH; nested++)
if (card->level[nested] == 0)
break;
/* check if correct model name */
int num_terminals = get_number_terminals(curr_line);
/* num_terminals may be 0 for a elements */
@ -7001,56 +6999,24 @@ inp_rem_unused_models(struct line *deck)
elem_model_name = get_model_name(curr_line, num_terminals);
if (is_a_modelname(elem_model_name)) {
/* if element is on top level, do faster here */
if (nested == 0) {
for (modn = modl; modn; modn = modn->next)
/* check if model is at top level, element is o.k., and model name is fitting */
if ((modn->model->level[0] == 0) && (*curr_line == modn->elemb) && model_name_match(elem_model_name, modn->modelname))
modn->used = TRUE;
}
else {
/* scan through levels, starting with element level */
for (i = nested - 1; i >= 0; i--) {
bool got_a_model = FALSE;
for (modn = modl; modn; modn = modn->next) {
/* check if element o.k., model name is fitting, and level is o.k. */
if ((*curr_line == modn->elemb) && model_name_match(elem_model_name, modn->modelname) && (card->level[i] == modn->model->level[i])) {
modn->used = TRUE;
got_a_model = TRUE;
/* repeat for binning models, leave immediately after lowest possible level matches */
}
/* model is at top level, element level does not matter */
if ((i == 0) && (*curr_line == modn->elemb) && model_name_match(elem_model_name, modn->modelname) && (modn->model->level[i] == 0)) {
modn->used = TRUE;
got_a_model = TRUE;
/* repeat for binning models, leave immediately after lowest possible level matches */
}
}
if (got_a_model) {
tfree(elem_model_name);
goto nextcard;
}
}
struct modellist *m = find_model(card->level, elem_model_name);
if (m) {
if (*curr_line != m->elemb)
fprintf(stderr, "warning, model type mismatch\n");
mark_all_binned(m->model->level, elem_model_name);
} else {
fprintf(stderr, "warning, can't find model %s\n", elem_model_name);
}
} else {
fprintf(stderr, "warning, not a valid modelname %s\n", elem_model_name);
}
tfree(elem_model_name);
}
nextcard:
;
}
/* discard all unused models */
for (modn = modl; modn; modn = modn->next)
if (modn->used == FALSE)
modn->model->li_line[0] = '*';
/* remove modellist */
for (modn = modl; modn; ) {
struct modellist *modn_prev;
tfree(modn->modelname);
modn_prev = modn;
modn = modn->next;
tfree(modn_prev);
}
// disable unused .model lines, and free the models assoc lists
rem_unused_xxx(root);
}

View File

@ -11,10 +11,12 @@
#define NUPASUBDONE 2
#define NUPAEVALDONE 3
struct nscope;
extern char *nupa_copy(char *s, int linenum);
extern int nupa_eval(char *s, int linenum, int orig_linenum);
extern int nupa_signal(int sig, char *info);
extern void nupa_scan(char * s, int linenum, int is_subckt, unsigned short level[]);
extern void nupa_scan(char * s, int linenum, int is_subckt, struct nscope *level);
extern void nupa_list_params(FILE *cp_out);
extern double nupa_get_param(char *param_name, int *found);
extern void nupa_add_param(char *param_name, double value);

View File

@ -28,7 +28,7 @@ typedef struct entry_s {
int ivl; /* int value or string buffer index */
char *sbbase; /* string buffer base address if any */
struct entry_s *pointer; /* pointer chain */
unsigned short levelinfo[NESTINGDEPTH];
struct nscope *levelinfo;
} entry_t;
@ -55,7 +55,7 @@ typedef struct { /* the input scanner data structure */
void initdico(dico_t *);
int donedico(dico_t *);
void dico_free_entry(entry_t *);
bool defsubckt(dico_t *, char *s, int w, char categ, unsigned short level[]);
bool defsubckt(dico_t *, char *s, int w, char categ, struct nscope *level);
int findsubckt(dico_t *, char *s, SPICE_DSTRINGPTR subname);
bool nupa_substitute(dico_t *, char *s, char *r, bool err);
bool nupa_assignment(dico_t *, char *s, char mode);
@ -63,5 +63,5 @@ bool nupa_subcktcall(dico_t *, char *s, char *x, bool err);
void nupa_subcktexit(dico_t *);
dico_t *nupa_fetchinstance(void);
char getidtype(dico_t *, char *s);
entry_t *attrib(dico_t *, NGHASHPTR htable, char *t, char op, unsigned short level[]);
entry_t *attrib(dico_t *, NGHASHPTR htable, char *t, char op, struct nscope *level);
void del_attrib(void *);

View File

@ -533,7 +533,7 @@ nupa_done(void)
/* SJB - Scan the line for subcircuits */
void
nupa_scan(char *s, int linenum, int is_subckt, unsigned short level[])
nupa_scan(char *s, int linenum, int is_subckt, struct nscope *level)
{
if (is_subckt)
defsubckt(dicoS, s, linenum, 'U', level);

View File

@ -421,7 +421,7 @@ fetchnumentry(dico_t *dico, char *s, bool *perr)
/******* writing dictionary entries *********/
entry_t *
attrib(dico_t *dico, NGHASHPTR htable_p, char *t, char op, unsigned short levelinfo[])
attrib(dico_t *dico, NGHASHPTR htable_p, char *t, char op, struct nscope *levelinfo)
{
/* seek or attribute dico entry number for string t.
Option op='N' : force a new entry, if tos>level and old is valid.
@ -436,14 +436,11 @@ attrib(dico_t *dico, NGHASHPTR htable_p, char *t, char op, unsigned short leveli
}
if (!entry) {
int i;
entry = TMALLOC(entry_t, 1);
entry->symbol = strdup(t);
entry->tp = '?'; /* signal Unknown */
entry->level = dico->stack_depth;
if (levelinfo)
for (i = 0; i < NESTINGDEPTH; i++)
entry->levelinfo[i] = levelinfo[i];
entry->levelinfo = levelinfo;
nghash_insert(htable_p, t, entry);
}
@ -475,7 +472,7 @@ nupa_define(dico_t *dico,
double z, /* float value if any */
int w, /* integer value if any */
char *base, /* string pointer if any */
unsigned short level[]) /* level info */
struct nscope *level) /* level info */
{
/*define t as real or integer,
opcode= 'N' impose a new item under local conditions.
@ -531,6 +528,7 @@ nupa_define(dico_t *dico,
/* FIXME: better do this recursively in a new function */
/* No new entry defined, but previous entry with same name returned
from function attrib(), compare levels, if not equal, o.k. (for now) */
#if 0
unsigned short newlevel[NESTINGDEPTH];
unsigned short oldlevel[NESTINGDEPTH];
int i;
@ -553,6 +551,7 @@ nupa_define(dico_t *dico,
&& (newlevel[2] > 0) && (oldlevel[2] > 1)
&& (newlevel[3] == 0) && (oldlevel[3] == 0))
fprintf(stderr, "Warning: %s is already used,\n cannot be redefined\n", t);
#endif
}
}
@ -561,7 +560,7 @@ nupa_define(dico_t *dico,
bool
defsubckt(dico_t *dico, char *s, int w, char categ, unsigned short level[])
defsubckt(dico_t *dico, char *s, int w, char categ, struct nscope *level)
/* called on 1st pass of spice source code,
to enter subcircuit (categ=U) and model (categ=O) names
*/

View File

@ -21,7 +21,7 @@ struct line {
char *li_error;
struct line *li_next;
struct line *li_actual;
unsigned short level[NESTINGDEPTH];
struct nscope *level;
} ;
/* Listing types. */

View File

@ -62,6 +62,20 @@ struct INPtables{
GENmodel *defZmod;
};
struct modellist;
struct nscope {
struct nscope *next;
struct line_assoc *subckts;
struct modellist *models;
};
struct line_assoc {
const char *name;
struct line *line;
struct line_assoc *next;
};
struct card{
int linenum;
int linenum_orig;
@ -69,7 +83,7 @@ struct card{
char *error;
card *nextcard;
card *actualLine;
unsigned short level[NESTINGDEPTH];
struct nscope *level;
};
/* structure used to save models in after they are read during pass 1 */