diff --git a/ChangeLog b/ChangeLog index ac7b1bfeb..5b2c6d5d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2010-07-10 Holger Vogt + * com_measure2.c: allow variables v(n1)=v(n2) + * inpcom.c: par('expression') in .four, .plot, .print, .meas, .save + * string.c, ngspice.h: new fcn gettok_iv() + 2010-07-09 Robert Larice * src/frontend/spiceif.c , * src/spicelib/analysis/tfanal.c , diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index 9e6f3de35..2d9999a0d 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -299,7 +299,7 @@ int measure_extract_variables( char *line ) char *item ; /* parsing item */ char *measure ; /* measure keyword */ char *analysis ; /* analysis option */ - char *variable ; /* variable to trace */ + char *variable, *variable2 ; /* variable to trace */ wordlist *measure_var ; /* wordlist of measurable */ ANALYSIS_TYPE_T op ; /* measure function type */ @@ -326,16 +326,27 @@ int measure_extract_variables( char *line ) op = measure_function_type(item) ; if( op != AT_UNKNOWN ){ /* We have a variable/complex variable coming next */ - variable = gettok(&line) ; + variable = gettok_iv(&line) ; + variable2 = NULL; + if (*line == '=') variable2 = gettok_iv(&line) ; if( variable ){ len = strlen(item) ; if( item[len-1] == '=' ){ } else { + /* We may have something like V(n1)=1 + or v(n1)=2 , same with i() */ measure_var = gettoks(variable) ; com_save2(measure_var, analysis); status = FALSE; } } + if( variable2 ){ + /* We may have something like v(n1)=v(n2) + v(n2) is handled here, same with i() */ + measure_var = gettoks(variable2) ; + com_save2(measure_var, analysis); + status = FALSE; + } } } } while(line && *line) ; diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 91dc917ab..045aac123 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -3580,9 +3580,10 @@ inp_split_multi_param_lines( struct line *deck, int line_num ) static void inp_compat(struct line *deck) { char *str_ptr, *cut_line, *title_tok, *node1, *node2; + char *out_ptr, *exp_ptr, *beg_ptr, *end_ptr, *copy_ptr, *del_ptr; char *xline; - size_t xlen, i; - char *ckt_array[4]; + size_t xlen, i, pai=0, paui=0, ii; + char *ckt_array[100]; struct line *new_line, *tmp_ptr; struct line *param_end = NULL, *param_beg = NULL; @@ -3906,6 +3907,295 @@ static void inp_compat(struct line *deck) param_beg = param_end = NULL; } + /* .probe -> .save + .print, .plot, .save, .four, + An ouput vector may be replaced by the following: + myoutput=par('expression') + .meas + A vector out_variable may be replaced by + par('expression') + */ + else if ( *curr_line == '.' ) { + // replace .probe by .save + if(str_ptr = strstr(curr_line, ".probe")) + memcpy(str_ptr, ".save ", 6); + + /* Various formats for measure statement: + * .MEASURE {DC|AC|TRAN} result WHEN out_variable=val + * + + * + + * + * .MEASURE {DC|AC|TRAN} result WHEN out_variable=out_variable2 + * + + * + + * + * .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=val + * + + * + + * + * .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=out_variable3 + * + + * + + * + * .MEASURE {DC|AC|TRAN} result FIND out_variable AT=val + * + + * + * .MEASURE {DC|AC|TRAN} result {AVG|MIN|MAX|MIN_AT|MAX_AT|PP|RMS} out_variable + * + + * + * .MEASURE {DC|AC|TRAN} result INTEG out_variable + * + + * + * .MEASURE {DC|AC|TRAN} result DERIV out_variable AT=val + * + * .MEASURE {DC|AC|TRAN} result DERIV out_variable WHEN out_variable2=val + * + + * + + * + * .MEASURE {DC|AC|TRAN} result DERIV out_variable WHEN out_variable2=out_variable3 + * + + * + + + The user may set any out_variable to par(' expr '). + We have to teplace this by v(pa_xx) and generate a B source line. + + * ----------------------------------------------------------------- */ + if ( ciprefix(".meas", curr_line) ) { + if (strstr(curr_line, "par") == NULL) continue; + cut_line = curr_line; + // search for 'par' + while(str_ptr = strstr(cut_line, "par")) { + if (i > 99) { + fprintf(stderr, "ERROR: No more than 99 'par' per input file\n", + curr_line); + controlled_exit(EXIT_FAILURE); + } + + // we have ' par({ ... })', the right delimeter is a ' ' or '=' + if ( ciprefix(" par({", (str_ptr-1)) ) { + // find expression + beg_ptr = end_ptr = str_ptr + 5; + while ((*end_ptr != ' ') && (*end_ptr != '=') && (*end_ptr != '\0')) + end_ptr++; + exp_ptr = copy_substring(beg_ptr, end_ptr-2); + cut_line = str_ptr; + // generate node + out_ptr = (char*)tmalloc(6); + sprintf(out_ptr, "pa_%02d", pai); + // Bout_ptr out_ptr 0 V = v(expr_ptr) + xlen = 2*strlen(out_ptr) + strlen(exp_ptr )+ 15 - 2*3 + 1; + ckt_array[pai] = (char*)tmalloc(xlen); + sprintf(ckt_array[pai], "b%s %s 0 v = %s", + out_ptr, out_ptr, exp_ptr); + ckt_array[++pai] = NULL; + // length of the replacement V(out_ptr) + xlen = strlen(out_ptr) + 4; + del_ptr = copy_ptr = (char*)tmalloc(xlen); + sprintf(copy_ptr, "v(%s)", out_ptr); + // length of the replacement part in original line + xlen = strlen(exp_ptr) + 7; + // copy the replacement without trailing '\0' + for (ii = 0; ii < xlen; ii++) + if (*copy_ptr) + *cut_line++ = *copy_ptr++; + else + *cut_line++ = ' '; + + tfree(del_ptr); tfree(exp_ptr); tfree(out_ptr); + } + // or we have '={par({ ... })}', the right delimeter is a ' ' + else if ( ciprefix("={par({", (str_ptr-2)) ) { + // find expression + beg_ptr = end_ptr = str_ptr + 5; + while ((*end_ptr != ' ') && (*end_ptr != '\0')) + end_ptr++; + exp_ptr = copy_substring(beg_ptr, end_ptr-3); + // generate node + out_ptr = (char*)tmalloc(6); + sprintf(out_ptr, "pa_%02d", pai); + // Bout_ptr out_ptr 0 V = v(expr_ptr) + xlen = 2*strlen(out_ptr) + strlen(exp_ptr )+ 15 - 2*3 + 1; + ckt_array[pai] = (char*)tmalloc(xlen); + sprintf(ckt_array[pai], "b%s %s 0 v = %s", + out_ptr, out_ptr, exp_ptr); + ckt_array[++pai] = NULL; + // length of the replacement V(out_ptr) + xlen = strlen(out_ptr) + 4; + del_ptr = copy_ptr = (char*)tmalloc(xlen); + sprintf(copy_ptr, "v(%s)", out_ptr); + // length of the replacement part in original line + xlen = strlen(exp_ptr) + 9; + // skip '=' + cut_line++; + // copy the replacement without trailing '\0' + for (ii = 0; ii < xlen; ii++) + if (*copy_ptr) + *cut_line++ = *copy_ptr++; + else *cut_line++ = ' '; + + tfree(del_ptr); tfree(exp_ptr); tfree(out_ptr); + } + // nothing to replace + else { + cut_line = str_ptr + 1; + continue; + } + + } // while 'par' + // no replacement done, go to next line + if (pai == paui) continue; + // remove white spaces + card->li_line = inp_remove_ws(curr_line); + // insert new B source line immediately after current line + tmp_ptr = card->li_next; + for ( ii = paui; ii < pai; ii++ ) + { + if ( param_end ) + { + param_end->li_next = alloc(struct line); + param_end = param_end->li_next; + } + else + { + param_end = param_beg = alloc(struct line); + } + param_end->li_next = NULL; + param_end->li_error = NULL; + param_end->li_actual = NULL; + param_end->li_line = ckt_array[ii]; + param_end->li_linenum = 0; + } + + // insert new param lines immediately after current line + tmp_ptr = card->li_next; + card->li_next = param_beg; + param_end->li_next = tmp_ptr; + // point 'card' pointer to last in scalar list + card = param_end; + + param_beg = param_end = NULL; + paui = pai; + } + else if (( ciprefix(".save", curr_line) ) || ( ciprefix(".four", curr_line) ) + || ( ciprefix(".print", curr_line) ) || ( ciprefix(".plot", curr_line) )) { + if (strstr(curr_line, "par") == NULL) continue; + cut_line = curr_line; + // search for 'par' + while(str_ptr = strstr(cut_line, "par")) { + if (pai > 99) { + fprintf(stderr, "ERROR: No more than 99 'par' per input file!\n", + curr_line); + controlled_exit(EXIT_FAILURE); + } + + // we have ' par({ ... })' + if ( ciprefix(" par({", (str_ptr-1)) ) { + + // find expression + beg_ptr = end_ptr = str_ptr + 5; + while ((*end_ptr != ' ') && (*end_ptr != '\0')) + end_ptr++; + exp_ptr = copy_substring(beg_ptr, end_ptr-2); + cut_line = str_ptr; + // generate node + out_ptr = (char*)tmalloc(6); + sprintf(out_ptr, "pa_%02d", pai); + // Bout_ptr out_ptr 0 V = v(expr_ptr) + xlen = 2*strlen(out_ptr) + strlen(exp_ptr )+ 15 - 2*3 + 1; + ckt_array[pai] = (char*)tmalloc(xlen); + sprintf(ckt_array[pai], "b%s %s 0 v = %s", + out_ptr, out_ptr, exp_ptr); + ckt_array[++pai] = NULL; + // length of the replacement V(out_ptr) + xlen = strlen(out_ptr) + 1; + del_ptr = copy_ptr = (char*)tmalloc(xlen); + sprintf(copy_ptr, "%s", out_ptr); + // length of the replacement part in original line + xlen = strlen(exp_ptr) + 7; + // copy the replacement without trailing '\0' + for (ii = 0; ii < xlen; ii++) + if (*copy_ptr) + *cut_line++ = *copy_ptr++; + else + *cut_line++ = ' '; + + tfree(del_ptr); tfree(exp_ptr); tfree(out_ptr); + } + // or we have '={par({ ... })}' + else if ( ciprefix("={par({", (str_ptr-2)) ) { + + // find myoutput + beg_ptr = end_ptr = str_ptr - 2; + while (*beg_ptr != ' ') + beg_ptr--; + out_ptr = copy_substring(beg_ptr + 1, end_ptr); + cut_line = beg_ptr + 1; + // find expression + beg_ptr = end_ptr = str_ptr + 5; + while ((*end_ptr != ' ') && (*end_ptr != '\0')) + end_ptr++; + exp_ptr = copy_substring(beg_ptr, end_ptr-3); + // Bout_ptr out_ptr 0 V = v(expr_ptr) + xlen = 2*strlen(out_ptr) + strlen(exp_ptr )+ 15 - 2*3 + 1; + ckt_array[pai] = (char*)tmalloc(xlen); + sprintf(ckt_array[pai], "b%s %s 0 v = %s", + out_ptr, out_ptr, exp_ptr); + ckt_array[++pai] = NULL; + // length of the replacement V(out_ptr) + xlen = strlen(out_ptr) + 1; + del_ptr = copy_ptr = (char*)tmalloc(xlen); + sprintf(copy_ptr, "%s", out_ptr); + // length of the replacement part in original line + xlen = strlen(out_ptr) + strlen(exp_ptr) + 10; + // copy the replacement without trailing '\0' + for (ii = 0; ii < xlen; ii++) + if (*copy_ptr) + *cut_line++ = *copy_ptr++; + else *cut_line++ = ' '; + + tfree(del_ptr); tfree(exp_ptr); tfree(out_ptr); + } + // nothing to replace + else + cut_line = str_ptr + 1; + } // while 'par' + // no replacement done, go to next line + if (pai == paui) continue; + // remove white spaces + card->li_line = inp_remove_ws(curr_line); + // insert new B source line immediately after current line + tmp_ptr = card->li_next; + for ( ii = paui; ii < pai; ii++ ) + { + if ( param_end ) + { + param_end->li_next = alloc(struct line); + param_end = param_end->li_next; + } + else + { + param_end = param_beg = alloc(struct line); + } + param_end->li_next = NULL; + param_end->li_error = NULL; + param_end->li_actual = NULL; + param_end->li_line = ckt_array[ii]; + param_end->li_linenum = 0; + } + // comment out current variable capacitor line +// *(ckt_array[0]) = '*'; + // insert new param lines immediately after current line + tmp_ptr = card->li_next; + card->li_next = param_beg; + param_end->li_next = tmp_ptr; + // point 'card' pointer to last in scalar list + card = param_end; + + param_beg = param_end = NULL; + paui = pai; + // continue; + } // if .print etc. + } // if('.') } } /* lines for B sources: no parsing in numparam code, just replacement of parameters. diff --git a/src/include/ngspice.h b/src/include/ngspice.h index 21c343983..6dd76ef18 100644 --- a/src/include/ngspice.h +++ b/src/include/ngspice.h @@ -201,6 +201,7 @@ extern struct timeb timebegin; extern char *gettok(char **s); extern char *gettok_noparens(char **s); extern char *gettok_node(char **s); +extern char *gettok_iv(char **s); extern int get_l_paren(char **s); extern int get_r_paren(char **s); extern void appendc(char *s, char c); diff --git a/src/misc/string.c b/src/misc/string.c index a91d72fd6..1c93f2201 100644 --- a/src/misc/string.c +++ b/src/misc/string.c @@ -236,6 +236,48 @@ gettok(char **s) return ( token ) ; } +/*-------------------------------------------------------------------------* + * gettok skips over whitespaces or '=' and returns the next token found, + * if the token is something like i(xxx), v(yyy), or v(xxx,yyy) + * -- h_vogt 10.07.2010. + *-------------------------------------------------------------------------*/ +char * +gettok_iv(char **s) +{ + char c; + int paren; + char *token ; /* return token */ + SPICE_DSTRING buf ; /* allow any length string */ + + paren = 0; + while ((isspace(**s)) || (**s=='=')) + (*s)++; + if ((!**s) || ((**s != 'v') && (**s != 'i') && (**s != 'V') && (**s != 'I'))) + return (NULL); + // initialize string + spice_dstring_init(&buf); + // add v or i to buf + spice_dstring_append_char( &buf, *(*s)++ ) ; + while (c = **s) { + if (c == '('/*)*/) + paren += 1; + else if (c == /*(*/')') + paren -= 1; + if (isspace(c)) + *(*s)++; + else { + spice_dstring_append_char( &buf, *(*s)++ ) ; + if (paren == 0) break; + } + } + while (isspace(**s) || **s == ',') + (*s)++; + token = copy( spice_dstring_value(&buf) ) ; + spice_dstring_free(&buf) ; + return ( token ) ; +} + + /*-------------------------------------------------------------------------* * gettok_noparens was added by SDB on 4.21.2003. * It acts like gettok, except that it treats parens and commas like