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
| | | | | | | |