allow 'temper' keyword in .param, .model and device instance lines

inpcom.c: fcns inp_fix_temper_in_param(), inp_new_func(), inp_rem_func()
  to convert .param with 'temper' to .func, and replace all affected
  parameter tokens xxx by their func counterpart xxx()

inpcom.c; fcns inp_temper_compat(), inp_modify_exp() added
  to prepare expression with 'temper' for numparam

inp.c: fcns inp_parse_temper(), inp_parse_temper_trees() added

inp_evaluate_temper()
  to prepare, parse and evaluate the expressions containing 'temper'

cktdefs.h: add global variable to expressions with 'temper'

dctrcurv.c: add fcn inp_evaluate_temper()
   when temp has changed
This commit is contained in:
h_vogt 2013-09-04 01:01:29 +02:00 committed by rlar
parent 8c85064018
commit d70865a162
4 changed files with 792 additions and 0 deletions

View File

@ -31,6 +31,7 @@ Author: 1985 Wayne A. Christopher
#include "subckt.h"
#include "spiceif.h"
#include "com_let.h"
#include "com_commands.h"
#ifdef XSPICE
#include "ngspice/ipctiein.h"
@ -51,10 +52,25 @@ static bool doedit(char *filename);
static struct line *com_options = NULL;
static void cktislinear(CKTcircuit *ckt, struct line *deck);
static void dotifeval(struct line *deck);
static int inp_parse_temper(struct line *deck);
static void inp_parse_temper_trees(void);
void line_free_x(struct line *deck, bool recurse);
void create_circbyline(char *line);
void inp_evaluate_temper(void);
/* structure used to save expression parse trees for .model and
* device instance lines
*/
struct pt_temper {
char *expression;
wordlist *wl;
wordlist *wlend;
INPparseTree *pt;
struct pt_temper *next;
};
/*
* create an unique artificial *unusable* FILE ptr
@ -572,6 +588,10 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
tmp_options->li_next = options;
}
/* prepare parse trees from 'temper' expressions */
if (expr_w_temper)
inp_parse_temper(deck);
/* now load deck into ft_curckt -- the current circuit. */
inp_dodeck(deck, tt, wl_first, FALSE, options, filename);
/* inp_dodeck did take ownership */
@ -664,6 +684,13 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
(void) fclose(fdo);
}
if (expr_w_temper) {
/* Now the circuit is defined, so generate the parse trees */
inp_parse_temper_trees();
/* Get the actual data for model and device instance parameters */
inp_evaluate_temper();
}
/* linked list dbs is used to store the "save" or .save data (defined in breakp2.c),
(When controls are executed later on, also stores TRACE, IPLOT, and STOP data) */
/* set to NULL to allow generation of a new dbs */
@ -1286,3 +1313,214 @@ dotifeval(struct line *deck)
tfree(dottoken);
}
}
/* List of all expressions found in .model lines */
static struct pt_temper *modtlist = NULL;
/* List of all expressions found in device instance lines */
static struct pt_temper *devtlist = NULL;
/*
Evaluate expressions containing 'temper' keyword, found in
.model lines or device instance lines.
Activity has four steps:
1) Prepare the expressions to survive numparam expansion
(see function inp_temper_compat() in inpcom.c). A global
variable expr_w_temper is set TRUE if any expression with
'temper' has been found.
2) After numparam insertion and subcircuit expansion,
get the expressions, store them with a place holder for the
pointer to the expression parse tree and a wordlist containing
device/model name, parameter name and a placeholder for the
evaluation result ready to be used by com_alter(mod) functions,
in linked lists modtlist (model) or devtlist (device instance).
(done function inp_parse_temper()).
3) After the circuit structure has been established, generate
the parse trees. We can do it only then because pointers to
ckt->CKTtemp and others are stored in the trees.
(done in function inp_parse_temper_trees()).
4) Evaluation of the parse trees is requested by calling function
inp_evaluate_temper(). The B Source parser is invoked here.
ckt->CKTtemp is used to replace the 'temper' token by the actual
circuit temperature. The evaluation results are added to the
wordlist, com_alter(mod) is called to set the new parameters
to the model parameters or device instance parameters.
*/
static int
inp_parse_temper(struct line *card)
{
int error = 0;
char *end_tstr, *beg_tstr, *beg_pstr, *str_ptr, *devmodname, *paramname, *expression;
/* skip title line */
card = card->li_next;
for (; card; card = card->li_next) {
char *curr_line = card->li_line;
/* exclude some elements */
if ((*curr_line == '*') || (*curr_line == 'v') || (*curr_line == 'b') || (*curr_line == 'i') ||
(*curr_line == 'e') || (*curr_line == 'g') || (*curr_line == 'f') || (*curr_line == 'h'))
continue;
/* exclude all dot commands except .model */
if ((*curr_line == '.') && (!prefix(".model", curr_line)))
continue;
/* exclude lines not containing 'temper' */
if (strstr(curr_line, "temper") == NULL)
continue;
/* now start processing of the remaining lines containing 'temper' */
if (prefix(".model", curr_line)) {
struct pt_temper *modtlistnew = NULL;
/* remove '.model' */
str_ptr = gettok(&curr_line);
tfree(str_ptr);
devmodname = gettok(&curr_line);
beg_tstr = curr_line;
while ((end_tstr = beg_tstr = strstr(beg_tstr, "temper")) != NULL) {
wordlist *wl = NULL, *wlend = NULL;
modtlistnew = TMALLOC(struct pt_temper, 1);
while ((*beg_tstr) != '=')
beg_tstr--;
beg_pstr = beg_tstr;
/* go back over param name */
while(isspace(*beg_pstr))
beg_pstr--;
while(!isspace(*beg_pstr))
beg_pstr--;
/* get parameter name */
paramname = copy_substring(beg_pstr + 1, beg_tstr);
/* find end of expression string */
while (((*end_tstr) != '\0') && ((*end_tstr) != '='))
end_tstr++;
/* go back over next param name */
if (*end_tstr == '=') {
end_tstr--;
while(isspace(*end_tstr))
end_tstr--;
while(!isspace(*end_tstr))
end_tstr--;
}
expression = copy_substring(beg_tstr + 1, end_tstr);
modtlistnew->expression = copy(expression);
/* now remove this parameter entry by overwriting with ' '
ngspice then will use the default parameter to set up the circuit */
for (str_ptr = beg_pstr; str_ptr < end_tstr; str_ptr++)
*str_ptr = ' ';
modtlistnew->next = NULL;
/* create wordlist suitable for com_altermod */
wl_append_word(&wl, &wlend, devmodname);
wl_append_word(&wl, &wlend, paramname);
wl_append_word(&wl, &wlend, copy("="));
/* to be filled in by evaluation function */
wl_append_word(&wl, &wlend, NULL);
modtlistnew->wl = wl;
modtlistnew->wlend = wlend;
/* fill in the linked parse tree list */
if (modtlist) {
struct pt_temper *modtlisttmp = modtlist;
modtlist = modtlistnew;
modtlist->next = modtlisttmp;
} else {
modtlist = modtlistnew;
}
}
} else { /* instance expression with 'temper' */
struct pt_temper *devtlistnew = NULL;
/* get device name */
devmodname = gettok(&curr_line);
beg_tstr = curr_line;
while ((end_tstr = beg_tstr = strstr(beg_tstr, "temper")) != NULL) {
wordlist *wl = NULL, *wlend = NULL;
devtlistnew = TMALLOC(struct pt_temper, 1);
while ((*beg_tstr) != '=')
beg_tstr--;
beg_pstr = beg_tstr;
/* go back over param name */
while(isspace(*beg_pstr))
beg_pstr--;
while(!isspace(*beg_pstr))
beg_pstr--;
/* get parameter name */
paramname = copy_substring(beg_pstr + 1, beg_tstr);
/* find end of expression string */
while (((*end_tstr) != '\0') && ((*end_tstr) != '='))
end_tstr++;
/* go back over next param name */
if (*end_tstr == '=') {
end_tstr--;
while(isspace(*end_tstr))
end_tstr--;
while(!isspace(*end_tstr))
end_tstr--;
}
expression = copy_substring(beg_tstr + 1, end_tstr);
devtlistnew->expression = copy(expression);
/* now remove this parameter entry by overwriting with ' '
ngspice then will use the default parameter to set up the circuit */
for (str_ptr = beg_pstr; str_ptr < end_tstr; str_ptr++)
*str_ptr = ' ';
devtlistnew->next = NULL;
/* create wordlist suitable for com_altermod */
wl_append_word(&wl, &wlend, devmodname);
wl_append_word(&wl, &wlend, paramname);
wl_append_word(&wl, &wlend, copy("="));
/* to be filled in by evaluation function */
wl_append_word(&wl, &wlend, NULL);
devtlistnew->wl = wl;
devtlistnew->wlend = wlend;
/* fill in the linked parse tree list */
if (devtlist) {
struct pt_temper *devtlisttmp = devtlist;
devtlist = devtlistnew;
devtlist->next = devtlisttmp;
} else {
devtlist = devtlistnew;
}
}
}
}
return error;
}
static void
inp_parse_temper_trees(void)
{
struct pt_temper *d;
for(d = devtlist; d; d = d->next)
INPgetTree(&d->expression, &d->pt, ft_curckt->ci_ckt, NULL);
for(d = modtlist; d; d = d->next)
INPgetTree(&d->expression, &d->pt, ft_curckt->ci_ckt, NULL);
}
void
inp_evaluate_temper(void)
{
struct pt_temper *d;
double result;
char fts[128];
for(d = devtlist; d; d = d->next) {
IFeval((IFparseTree *) d->pt, 1e-12, &result, NULL, NULL);
sprintf(fts, "%g", result);
d->wlend->wl_word = copy(fts);
com_alter(d->wl);
}
for(d = modtlist; d; d = d->next) {
IFeval((IFparseTree *) d->pt, 1e-12, &result, NULL, NULL);
sprintf(fts, "%g", result);
d->wlend->wl_word = copy(fts);
com_altermod(d->wl);
}
}

View File

@ -66,6 +66,14 @@ struct function_env
} *functions;
};
struct func_temper
{
char* funcname;
int subckt_depth;
int subckt_count;
struct func_temper *next;
};
static COMPATMODE_T inp_compat_mode;
@ -77,6 +85,9 @@ int dynMaxckt = 0; /* subckt.c 307 */
/* number of parameter substitutions */
long dynsubst; /* spicenum.c 221 */
/* Expression handling with 'temper' parameter required */
bool expr_w_temper = FALSE;
static char *readline(FILE *fd);
static int get_number_terminals(char *c);
@ -96,7 +107,12 @@ static void inp_sort_params(struct line *start_card, struct line *end_card, stru
static char *inp_remove_ws(char *s);
static void inp_compat(struct line *deck);
static void inp_bsource_compat(struct line *deck);
static void inp_temper_compat(struct line *card);
static void inp_dot_if(struct line *deck);
static char *inp_modify_exp(char* expression);
static void inp_new_func(char *funcname, char *funcbody, struct line *card,
struct func_temper **new_func, int *sub_count, int subckt_depth);
static void inp_rem_func(struct func_temper **new_func);
static bool chk_for_line_continuation(char *line);
static void comment_out_unused_subckt_models(struct line *start_card, int no_of_lines);
@ -110,6 +126,7 @@ static char *get_quoted_token(char *string, char **token);
static void replace_token(char *string, char *token, int where, int total);
static void inp_add_series_resistor(struct line *deck);
static void subckt_params_to_param(struct line *deck);
static void inp_fix_temper_in_param(struct line *deck);
static char *skip_back_non_ws(char *d) { while (d[-1] && !isspace(d[-1])) d--; return d; }
static char *skip_back_ws(char *d) { while (isspace(d[-1])) d--; return d; }
@ -779,6 +796,7 @@ inp_readall(FILE *fp, int call_depth, char *dir_name, bool comfile, bool intfile
inp_fix_macro_param_func_paren_io(working);
inp_fix_ternary_operator(working);
inp_fix_temper_in_param(working);
inp_expand_macros_in_deck(NULL, working);
inp_fix_param_values(working);
@ -813,6 +831,7 @@ inp_readall(FILE *fp, int call_depth, char *dir_name, bool comfile, bool intfile
/* B source numparam compatibility transformation */
inp_bsource_compat(working);
inp_dot_if(working);
inp_temper_compat(working);
}
inp_add_series_resistor(working);
@ -5504,6 +5523,263 @@ inp_bsource_compat(struct line *card)
}
/* Find all expression containing the keyword 'temper',
* except for B lines and some other exclusions. Prepare
* these expressions by calling inp_modify_exp() and return
* a modified card->li_line
*/
static void
inp_temper_compat(struct line *card)
{
int skip_control = 0;
char *beg_str, *end_str, *new_str = NULL, *beg_tstr, *end_tstr, *exp_str;
char actchar;
for (; card; card = card->li_next) {
char *curr_line = card->li_line;
/* exclude any command inside .control ... .endc */
if (ciprefix(".control", curr_line)) {
skip_control ++;
continue;
} else if (ciprefix(".endc", curr_line)) {
skip_control --;
continue;
} else if (skip_control > 0) {
continue;
}
/* exclude some elements */
if ((*curr_line == '*') || (*curr_line == 'v') || (*curr_line == 'b') || (*curr_line == 'i') ||
(*curr_line == 'e') || (*curr_line == 'g') || (*curr_line == 'f') || (*curr_line == 'h'))
continue;
/* exclude all dot commands except .model */
if ((*curr_line == '.') && (!prefix(".model", curr_line)))
continue;
/* exclude lines not containing 'temper' */
if (strstr(curr_line, "temper") == NULL)
continue;
/* now start processing of the remaining lines containing 'temper' */
/* remove white spaces of everything inside {}*/
card->li_line = inp_remove_ws(card->li_line);
curr_line = card->li_line;
/* now check if 'temper' is a token or just a substring of another string, e.g. mytempers */
/* we may have multiple temper and mytempers in multiple expressions in a line */
beg_str = beg_tstr = curr_line;
while ((beg_tstr = strstr(beg_tstr, "temper")) != NULL) {
actchar = *(beg_tstr - 1);
if (!isspace(actchar) && !is_arith_char(actchar)) {
beg_tstr++;
continue;
}
actchar = *(beg_tstr + 6);
if (!isspace(actchar) && !is_arith_char(actchar))
continue;
/* we have found a true 'temper' */
/* set the global variable */
expr_w_temper = TRUE;
/* find the expression: first go back to the opening '{',
then find the closing '}' */
while ((*beg_tstr) != '{')
beg_tstr--;
end_str = end_tstr = beg_tstr;
exp_str = gettok_char(&end_tstr, '}', TRUE, TRUE);
/* modify the expression string */
exp_str = inp_modify_exp(exp_str);
/* add the intermediate string between previous and next expression to the new line */
new_str = INPstrCat(new_str, copy_substring(beg_str, end_str), " ");
/* add the modified expression string to the new line */
new_str = INPstrCat(new_str, exp_str, " ");
new_str = INPstrCat(new_str, copy(" "), " ");
/* move on to the next intermediate string */
beg_str = beg_tstr = end_tstr;
}
if (*beg_str)
new_str = INPstrCat(new_str, copy(beg_str), " ");
tfree(card->li_line);
new_str = inp_remove_ws(new_str);
card->li_line = new_str;
}
}
/* lines containing expressions with keyword 'temper':
* no parsing in numparam code, just replacement of parameters.
* Parsing done with B source parser in function inp_parse_temper
* in inp.c. Evaluation is the done with fcn inp_evaluate_temper
* from inp.c, taking the actual temperature into account.
* To achive this, do the following here:
* Remove all '{' and '}' --> no parsing of equations in numparam
* Place '{' and '}' directly around all potential parameters,
* but skip function names like exp (search for 'exp(' to detect fcn name),
* functions containing nodes like v(node), v(node1, node2), i(branch)
* and other keywords like TEMPER. --> Only parameter replacement in numparam
*/
static char *
inp_modify_exp(char* expr)
{
char * str_ptr, *tmp_char, *new_str;
char actchar;
wordlist *wl = NULL, *wlist = NULL;
char buf[512];
size_t i, xlen, ustate = 0;
int error1;
/* scan the expression and remove all '{' and '}' */
str_ptr = expr;
while (*str_ptr) {
if ((*str_ptr == '{') || (*str_ptr == '}'))
*str_ptr = ' ';
str_ptr++;
}
/* scan the expression */
str_ptr = expr;
while (*str_ptr != '\0') {
str_ptr = skip_ws(str_ptr);
if (*str_ptr == '\0')
break;
actchar = *str_ptr;
wl_append_word(&wlist, &wl, NULL);
if ((actchar == ',') || (actchar == '(') || (actchar == ')') ||
(actchar == '*') || (actchar == '/') || (actchar == '^') ||
(actchar == '+') || (actchar == '?') || (actchar == ':'))
{
if ((actchar == '*') && (str_ptr[1] == '*')) {
actchar = '^';
str_ptr++;
}
buf[0] = actchar;
buf[1] = '\0';
wl->wl_word = copy(buf);
str_ptr++;
if (actchar == ')')
ustate = 0;
else
ustate = 1; /* we have an operator */
} else if ((actchar == '>') || (actchar == '<') ||
(actchar == '!') || (actchar == '='))
{
/* >=, <=, !=, ==, <>, ... */
char *beg = str_ptr++;
if ((*str_ptr == '=') || (*str_ptr == '<') || (*str_ptr == '>'))
str_ptr++;
wl->wl_word = copy_substring(beg, str_ptr);
ustate = 1; /* we have an operator */
} else if ((actchar == '|') || (actchar == '&')) {
char *beg = str_ptr++;
if ((*str_ptr == '|') || (*str_ptr == '&'))
str_ptr++;
wl->wl_word = copy_substring(beg, str_ptr);
ustate = 1; /* we have an operator */
} else if ((actchar == '-') && (ustate == 0)) {
buf[0] = actchar;
buf[1] = '\0';
wl->wl_word = copy(buf);
str_ptr++;
ustate = 1; /* we have an operator */
} else if ((actchar == '-') && (ustate == 1)) {
wl->wl_word = copy("");
str_ptr++;
ustate = 2; /* place a '-' in front of token */
} else if (isalpha(actchar)) {
/* unary -, change sign */
if (ustate == 2) {
i = 1;
buf[0] = '-';
} else {
i = 0;
}
if (((actchar == 'v') || (actchar == 'i')) && (str_ptr[1] == '(')) {
while (*str_ptr != ')') {
buf[i] = *str_ptr;
i++;
str_ptr++;
}
buf[i] = *str_ptr;
buf[i+1] = '\0';
wl->wl_word = copy(buf);
str_ptr++;
} else {
while (isalnum(*str_ptr) ||
(*str_ptr == '!') || (*str_ptr == '#') ||
(*str_ptr == '$') || (*str_ptr == '%') ||
(*str_ptr == '_') || (*str_ptr == '[') ||
(*str_ptr == ']'))
{
buf[i] = *str_ptr;
i++;
str_ptr++;
}
buf[i] = '\0';
/* no parens {} around time, hertz, temper, the constants
pi and e which are defined in inpptree.c, around pwl and temp. coeffs */
if ((*str_ptr == '(') ||
cieq(buf, "hertz") || cieq(buf, "temper") ||
cieq(buf, "time") || cieq(buf, "pi") ||
cieq(buf, "e") || cieq(buf, "pwl"))
{
wl->wl_word = copy(buf);
} else if (cieq(buf, "tc1") || cieq(buf, "tc2") ||
cieq(buf, "reciproctc"))
{
str_ptr = skip_ws(str_ptr);
/* no {} around tc1 = or tc2 = , these are temp coeffs. */
if (str_ptr[0] == '=' && str_ptr[1] != '=') {
buf[i++] = '=';
buf[i] = '\0';
str_ptr++;
wl->wl_word = copy(buf);
} else {
xlen = strlen(buf);
tmp_char = TMALLOC(char, xlen + 3);
sprintf(tmp_char, "{%s}", buf);
wl->wl_word = tmp_char;
}
} else {
/* {} around all other tokens */
xlen = strlen(buf);
tmp_char = TMALLOC(char, xlen + 3);
sprintf(tmp_char, "{%s}", buf);
wl->wl_word = tmp_char;
}
}
ustate = 0; /* we have a number */
} else if (isdigit(actchar) || (actchar == '.')) { /* allow .5 format too */
/* allow 100p, 5MEG etc. */
double dvalue = INPevaluate(&str_ptr, &error1, 0);
char cvalue[19];
/* unary -, change sign */
if (ustate == 2)
dvalue *= -1;
sprintf(cvalue, "%18.10e", dvalue);
wl->wl_word = copy(cvalue);
ustate = 0; /* we have a number */
/* skip the `unit', FIXME INPevaluate() should do this */
while (isalpha(*str_ptr))
str_ptr++;
} else { /* strange char */
printf("Preparing expression for numparam\nWhat is this?\n%s\n", str_ptr);
buf[0] = *str_ptr;
buf[1] = '\0';
wl->wl_word = copy(buf);
str_ptr++;
}
}
new_str = wl_flatten(wlist);
wl_free(wlist);
wlist = NULL;
wl = NULL;
tfree(expr);
return(new_str);
}
/*
* destructively fetch a token from the input string
* token is either quoted, or a plain nonwhitespace sequence
@ -5776,3 +6052,270 @@ inp_dot_if(struct line *card)
}
}
}
/* Convert .param lines containing keyword 'temper' into .func lines:
* .param xxx1 = 'temper + 25' ---> .func xxx1() 'temper + 25'
* Add info about the functions (name, subcircuit depth, number of
* subckt) to linked list new_func.
* Then scan new_func, for each xxx1 scan all lines of deck,
* find all xxx1 and convert them to a function:
* xxx1 ---> xxx1()
* If this happens to be in another .param line, convert it to .func,
* add info to end of new_func and continue scanning.
*/
static void
inp_fix_temper_in_param(struct line *deck)
{
int skip_control = 0, subckt_depth = 0, j, *sub_count;
char *beg_pstr, *beg_tstr, *end_tstr, *funcbody, *funcname;
char actchar;
struct func_temper *new_func = NULL, *beg_func;
struct line *card;
sub_count = TMALLOC(int, 16);
for(j = 0; j < 16; j++)
sub_count[j] = 0;
/* first pass: determine all .param with temper inside and replace by .func
.param xxx1 = 'temper + 25'
will become
.func xxx1() 'temper + 25'
*/
card = deck;
for (; card; card = card->li_next) {
char *curr_line = card->li_line;
if (*curr_line == '*')
continue;
/* determine nested depths of subcircuits */
if (ciprefix(".subckt", curr_line)) {
subckt_depth ++;
sub_count[subckt_depth]++;
continue;
} else if (ciprefix(".ends", curr_line)) {
subckt_depth --;
continue;
}
/* exclude any command inside .control ... .endc */
if (ciprefix(".control", curr_line)) {
skip_control ++;
continue;
} else if (ciprefix(".endc", curr_line)) {
skip_control --;
continue;
} else if (skip_control > 0) {
continue;
}
if (ciprefix(".param", curr_line)) {
/* check if we have a true 'temper' */
beg_tstr = curr_line;
while ((end_tstr = beg_tstr = strstr(beg_tstr, "temper")) != NULL) {
actchar = *(beg_tstr - 1);
if (!(actchar == '{') && !isspace(actchar) && !is_arith_char(actchar)) {
beg_tstr++;
continue;
}
actchar = *(beg_tstr + 6);
if (!(actchar == '}') && !isspace(actchar) && !is_arith_char(actchar))
continue;
/* we have found a true 'temper', so start conversion */
/* find function name and function body: We may have multiple
params in a linie!
*/
while ((*beg_tstr) != '=')
beg_tstr--;
beg_pstr = beg_tstr;
/* go back over param name */
while(isspace(*beg_pstr))
beg_pstr--;
while(!isspace(*beg_pstr))
beg_pstr--;
/* get function name from parameter name */
funcname = copy_substring(beg_pstr + 1, beg_tstr);
/* find end of function body */
while (((*end_tstr) != '\0') && ((*end_tstr) != '='))
end_tstr++;
/* go back over next param name */
if (*end_tstr == '=') {
end_tstr--;
while(isspace(*end_tstr))
end_tstr--;
while(!isspace(*end_tstr))
end_tstr--;
}
funcbody = copy_substring(beg_tstr + 1, end_tstr);
inp_new_func(funcname, funcbody, card, &new_func, sub_count, subckt_depth);
beg_tstr = end_tstr;
}
}
}
/* second pass */
/* for each .func entry in new_func start the insertion operation:
search each line from the deck, which has the suitable subcircuit nesting data,
for tokens xxx equalling the funcname, replace xxx by xxx(). After insertion,
remove the respective entry in new_fuc. If the replacement is done in a
.param line, convert it to a .func line and add an entry to new_func.
Continue until new_func is empty.
*/
beg_func = new_func;
for (; new_func; new_func = new_func->next) {
for(j = 0; j < 16; j++)
sub_count[j] = 0;
card = deck;
for (; card; card = card->li_next) {
char *new_str = NULL; /* string we assemble here */
char *curr_str;/* where we are in curr_line */
char *add_str;/* what we add */
char *curr_line = card->li_line;
char * new_tmp_str, *tmp_str;
if (*curr_line == '*')
continue;
/* determine nested depths of subcircuits */
if (ciprefix(".subckt", curr_line)) {
subckt_depth ++;
sub_count[subckt_depth]++;
continue;
} else if (ciprefix(".ends", curr_line)) {
subckt_depth --;
continue;
}
/* exclude any command inside .control ... .endc */
if (ciprefix(".control", curr_line)) {
skip_control ++;
continue;
} else if (ciprefix(".endc", curr_line)) {
skip_control --;
continue;
} else if (skip_control > 0) {
continue;
}
/* exclude lines which do not have the same subcircuit
nesting depth and number as found in new_func */
if (subckt_depth != new_func->subckt_depth)
continue;
if (sub_count[subckt_depth] != new_func->subckt_count)
continue;
curr_str = curr_line;
while ((beg_tstr = strstr(curr_str, new_func->funcname)) != NULL) {
/* start of token */
actchar = *(beg_tstr - 1);
if (!(actchar == '{') && !isspace(actchar) && !is_arith_char(actchar)) {
curr_str++;
continue;
}
/* end of token */
end_tstr = beg_tstr + strlen(new_func->funcname);
actchar = *(end_tstr);
if (!(actchar == '}') && !isspace(actchar) && !is_arith_char(actchar)) {
curr_str++;
continue;
}
if (actchar == '(') {
curr_str++;
continue; /* not the .func xxx() itself */
}
/* we have found a true token equaling funcname, so start insertion */
add_str = copy_substring(curr_str, end_tstr);
new_str = INPstrCat(new_str, add_str, "");
new_str = INPstrCat(new_str, copy("()"), "");
curr_str = end_tstr;
}
if (new_str) /* add final part of line */
new_str = INPstrCat(new_str, copy(curr_str), "");
else
continue;
/* if we have inserted into a .param line, convert to .func */
new_tmp_str = new_str;
if (prefix(".param", new_tmp_str)) {
tmp_str = gettok(&new_tmp_str);
tfree(tmp_str);
funcname = gettok_char(&new_tmp_str, '=', FALSE, FALSE);
funcbody = copy(new_tmp_str + 1);
inp_new_func(funcname, funcbody, card, &new_func, sub_count, subckt_depth);
} else {
/* Or just enter new line into deck */
card->li_next = xx_new_line(card->li_next, new_str, 0, card->li_linenum);
*card->li_line = '*';
}
}
}
/* final memory clearance */
tfree(sub_count);
/* remove new_func */
inp_rem_func(&beg_func);
}
/* enter function name, nested .subckt depths, and
* number of .subckt at given level into struct new_func
* and add line to deck
*/
static void
inp_new_func(char *funcname, char *funcbody, struct line *card, struct func_temper **new_func,
int *sub_count, int subckt_depth)
{
struct func_temper *new_func_tmp;
static struct func_temper *new_func_end;
char *new_str;
new_func_tmp = TMALLOC(struct func_temper, 1);
new_func_tmp->funcname = funcname;
new_func_tmp->next = NULL;
new_func_tmp->subckt_depth = subckt_depth;
new_func_tmp->subckt_count = sub_count[subckt_depth];
/* Insert at the back */
if (*new_func == NULL) {
*new_func = new_func_end = new_func_tmp;
} else {
new_func_end->next = new_func_tmp;
new_func_end = new_func_tmp;
}
/*
if (*new_func == NULL)
*new_func = new_func_tmp;
else {
new_func_tmp->next = *new_func;
*new_func = new_func_tmp;
}
*/
/* replace line in deck */
new_str = TMALLOC(char, strlen(funcname) + strlen(funcbody) + 10);
sprintf(new_str, ".func %s() %s", funcname, funcbody);
card->li_next = xx_new_line(card->li_next, new_str, 0, card->li_linenum);
*card->li_line = '*';
}
static void
inp_rem_func(struct func_temper **beg_func)
{
struct func_temper *b = *beg_func;
for(; b; b = b->next)
tfree(b->funcname);
tfree(*beg_func);
}

View File

@ -434,5 +434,6 @@ extern int NIpred(CKTcircuit *ckt);
#endif
extern IFfrontEnd *SPfrontEnd;
extern bool expr_w_temper;
#endif

View File

@ -28,6 +28,8 @@ Modified: 1999 Paolo Nenzi
static double actval, actdiff;
#endif
extern void inp_evaluate_temper(void);
int
DCtrCurv(CKTcircuit *ckt, int restart)
@ -157,6 +159,8 @@ DCtrCurv(CKTcircuit *ckt, int restart)
job->TRCVvType[i] = TEMP_CODE; /* Set the sweep type code */
ckt->CKTtemp = job->TRCVvStart[i] + CONSTCtoK; /* Set the new circuit temp */
CKTtemp(ckt);
if (expr_w_temper)
inp_evaluate_temper();
goto found;
}
@ -298,6 +302,8 @@ resume:
} else if (job->TRCVvType[i] == TEMP_CODE) {
ckt->CKTtemp = job->TRCVvStart[i] + CONSTCtoK;
CKTtemp(ckt);
if (expr_w_temper)
inp_evaluate_temper();
} else if (job->TRCVvType[i] == rcode) {
((RESinstance *)(job->TRCVvElt[i]))->RESresist =
@ -508,6 +514,8 @@ nextstep:;
{
ckt->CKTtemp += job->TRCVvStep[i];
CKTtemp(ckt);
if (expr_w_temper)
inp_evaluate_temper();
} /* else not possible */
if(SPfrontEnd->IFpauseTest()) {
@ -551,6 +559,8 @@ nextstep:;
else if (job->TRCVvType[i] == TEMP_CODE) {
ckt->CKTtemp = job->TRCVvSave[i];
CKTtemp(ckt);
if (expr_w_temper)
inp_evaluate_temper();
} /* else not possible */
}
SPfrontEnd->OUTendPlot (plot);