inp_do_macro_param_replace(), fix several bugs concerning .func processing
This commit is contained in:
parent
fd47aafc4e
commit
7f7453a227
|
|
@ -1180,6 +1180,7 @@ AC_CONFIG_FILES([Makefile
|
|||
tests/regression/subckt-processing/Makefile
|
||||
tests/regression/lib-processing/Makefile
|
||||
tests/regression/parser/Makefile
|
||||
tests/regression/func/Makefile
|
||||
tests/sensitivity/Makefile
|
||||
tests/transient/Makefile
|
||||
tests/transmission/Makefile
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ struct function_env
|
|||
char *macro;
|
||||
char *params[N_PARAMS];
|
||||
int num_parameters;
|
||||
const char *accept;
|
||||
} *functions;
|
||||
};
|
||||
|
||||
|
|
@ -2888,6 +2889,17 @@ inp_get_func_from_line(struct function_env *env, char *line)
|
|||
temp_buf[str_len++] = '\0';
|
||||
|
||||
function->macro = strdup(temp_buf);
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
char *accept = TMALLOC(char, function->num_parameters + 1);
|
||||
for (i = 0; i < function->num_parameters; i++)
|
||||
accept[i] = function->params[i][0];
|
||||
accept[i] = '\0';
|
||||
|
||||
function->accept = accept;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2925,115 +2937,100 @@ inp_grab_func(struct function_env *env, struct line *c)
|
|||
|
||||
|
||||
static char*
|
||||
inp_do_macro_param_replace(struct function *fcn, char *params[])
|
||||
search_func_arg(char *str, struct function *fcn, int *which, char *str_begin)
|
||||
{
|
||||
char *param_ptr, *curr_ptr, *new_str, *curr_str = NULL, *search_ptr;
|
||||
char keep, before, after;
|
||||
int i;
|
||||
for (; (str = strpbrk(str, fcn->accept)) != NULL; str++) {
|
||||
char before;
|
||||
|
||||
if (fcn->num_parameters == 0)
|
||||
return strdup(fcn->macro);
|
||||
if (str > str_begin)
|
||||
before = str[-1];
|
||||
else
|
||||
before = '\0';
|
||||
|
||||
for (i = 0; i < fcn->num_parameters; i++) {
|
||||
|
||||
if (curr_str == NULL) {
|
||||
search_ptr = curr_ptr = strdup(fcn->macro);
|
||||
} else {
|
||||
search_ptr = curr_ptr = curr_str;
|
||||
curr_str = NULL;
|
||||
}
|
||||
|
||||
while ((param_ptr = strstr(search_ptr, fcn->params[i])) != NULL) {
|
||||
char *op_ptr = NULL, *cp_ptr = NULL;
|
||||
int is_vi = 0;
|
||||
|
||||
/* make sure actually have the parameter name */
|
||||
if (param_ptr == search_ptr) /* no valid 'before' */
|
||||
before = '\0';
|
||||
else
|
||||
before = *(param_ptr-1);
|
||||
after = param_ptr [ strlen(fcn->params[i]) ];
|
||||
if (!(is_arith_char(before) || isspace(before) ||
|
||||
before == ',' || before == '=' || (param_ptr-1) < curr_ptr) ||
|
||||
!(is_arith_char(after) || isspace(after) ||
|
||||
after == ',' || after == '=' || after == '\0'))
|
||||
{
|
||||
search_ptr = param_ptr + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* exclude v(nn, parameter), v(parameter, nn), v(parameter),
|
||||
and i(parameter) if here 'parameter' is also a node name */
|
||||
if (before != '\0') {
|
||||
/* go backwards from 'parameter' and find '(' */
|
||||
for (op_ptr = param_ptr-1; op_ptr > curr_ptr; op_ptr--) {
|
||||
if (*op_ptr == ')') {
|
||||
is_vi = 0;
|
||||
break;
|
||||
}
|
||||
if ((*op_ptr == '(') && (op_ptr - 2 > curr_ptr) &&
|
||||
((*(op_ptr - 1) == 'v') || (*(op_ptr - 1) == 'i')) &&
|
||||
(is_arith_char(*(op_ptr - 2)) || isspace(*(op_ptr - 2)) ||
|
||||
*(op_ptr - 2) == ',' || *(op_ptr - 2) == '=' )) {
|
||||
is_vi = 1;
|
||||
break;
|
||||
if (is_arith_char(before) || isspace(before) || strchr(",=", before)) {
|
||||
int i;
|
||||
for (i = 0; i < fcn->num_parameters; i++) {
|
||||
size_t len = strlen(fcn->params[i]);
|
||||
if (strncmp(str, fcn->params[i], len) == 0) {
|
||||
char after = str[len];
|
||||
if (is_arith_char(after) || isspace(after) || strchr(",=", after)) {
|
||||
*which = i;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
/* We have a true v( or i( */
|
||||
if (is_vi) {
|
||||
cp_ptr = param_ptr;
|
||||
/* go forward and find closing ')' */
|
||||
while (*cp_ptr) {
|
||||
cp_ptr++;
|
||||
if (*cp_ptr == '(') {
|
||||
is_vi = 0;
|
||||
break;
|
||||
}
|
||||
if (*cp_ptr == ')')
|
||||
break;
|
||||
}
|
||||
if (*cp_ptr == '\0')
|
||||
is_vi = 0;
|
||||
}
|
||||
/* We have a true v(...) or i(...),
|
||||
so skip it, and continue searching for new 'parameter' */
|
||||
if (is_vi) {
|
||||
search_ptr = cp_ptr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
keep = *param_ptr;
|
||||
*param_ptr = '\0';
|
||||
|
||||
{
|
||||
size_t curr_str_len = curr_str ? strlen(curr_str) : 0;
|
||||
size_t len = strlen(curr_ptr) + strlen(params[i]) + 1;
|
||||
if (str_has_arith_char(params[i])) {
|
||||
curr_str = TREALLOC(char, curr_str, curr_str_len + len + 2);
|
||||
sprintf(curr_str + curr_str_len, "%s(%s)", curr_ptr, params[i]);
|
||||
} else {
|
||||
curr_str = TREALLOC(char, curr_str, curr_str_len + len);
|
||||
sprintf(curr_str + curr_str_len, "%s%s", curr_ptr, params[i]);
|
||||
}
|
||||
}
|
||||
|
||||
*param_ptr = keep;
|
||||
search_ptr = curr_ptr = param_ptr + strlen(fcn->params[i]);
|
||||
}
|
||||
|
||||
if (param_ptr == NULL) {
|
||||
if (curr_str == NULL) {
|
||||
curr_str = curr_ptr;
|
||||
} else {
|
||||
new_str = tprintf("%s%s", curr_str, curr_ptr);
|
||||
tfree(curr_str);
|
||||
curr_str = new_str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return curr_str;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static char*
|
||||
inp_do_macro_param_replace(struct function *fcn, char *params[])
|
||||
{
|
||||
char *str = strdup(fcn->macro);
|
||||
int i;
|
||||
|
||||
char *collect_ptr = NULL;
|
||||
char *arg_ptr = str;
|
||||
char *rest = str;
|
||||
|
||||
while ((arg_ptr = search_func_arg(arg_ptr, fcn, &i, str)) != NULL) {
|
||||
char *p;
|
||||
int is_vi = 0;
|
||||
|
||||
/* exclude v(nn, parameter), v(parameter, nn), v(parameter),
|
||||
and i(parameter) if here 'parameter' is also a node name */
|
||||
|
||||
/* go backwards from 'parameter' and find '(' */
|
||||
for (p = arg_ptr; --p > str; )
|
||||
if (*p == '(' || *p == ')') {
|
||||
if ((*p == '(') && strchr("vi", p[-1]) &&
|
||||
(p - 2 < str || is_arith_char(p[-2]) || isspace(p[-2]) || strchr(",=", p[-2])))
|
||||
is_vi = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we have a true v( or i( */
|
||||
if (is_vi) {
|
||||
/* go forward and find closing ')' */
|
||||
for (p = arg_ptr + 1; *p; p++)
|
||||
if (*p == '(' || *p == ')')
|
||||
break;
|
||||
/* We have a true v(...) or i(...),
|
||||
so skip it, and continue searching for new 'parameter' */
|
||||
if (*p == ')') {
|
||||
arg_ptr = p;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
size_t collect_ptr_len = collect_ptr ? strlen(collect_ptr) : 0;
|
||||
size_t len = strlen(rest) + strlen(params[i]) + 1;
|
||||
int prefix_len = (int) (arg_ptr - rest);
|
||||
if (str_has_arith_char(params[i])) {
|
||||
collect_ptr = TREALLOC(char, collect_ptr, collect_ptr_len + len + 2);
|
||||
sprintf(collect_ptr + collect_ptr_len, "%.*s(%s)", prefix_len, rest, params[i]);
|
||||
} else {
|
||||
collect_ptr = TREALLOC(char, collect_ptr, collect_ptr_len + len);
|
||||
sprintf(collect_ptr + collect_ptr_len, "%.*s%s", prefix_len, rest, params[i]);
|
||||
}
|
||||
}
|
||||
|
||||
arg_ptr += strlen(fcn->params[i]);
|
||||
rest = arg_ptr;
|
||||
}
|
||||
|
||||
if (collect_ptr) {
|
||||
char *new_str = tprintf("%s%s", collect_ptr, rest);
|
||||
tfree(collect_ptr);
|
||||
tfree(str);
|
||||
str = new_str;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -647,8 +647,7 @@ isquote( char ch )
|
|||
bool
|
||||
is_arith_char( char c )
|
||||
{
|
||||
if ( c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' || c == '<' ||
|
||||
c == '>' || c == '?' || c == '|' || c == '&' || c == '^')
|
||||
if (c != '\0' && strchr("+-*/()<>?:|&^!%\\", c))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
SUBDIRS = lib-processing parser subckt-processing
|
||||
SUBDIRS = lib-processing parser subckt-processing func
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
|
||||
TESTS = func-1.cir
|
||||
|
||||
TESTS_ENVIRONMENT = ngspice_vpath=$(srcdir) $(SHELL) $(top_srcdir)/tests/bin/check.sh $(top_builddir)/src/ngspice
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(TESTS) \
|
||||
$(TESTS:.cir=.out)
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
* 'func-1' check .func processing
|
||||
|
||||
* (exec-spice "ngspice -b %s")
|
||||
* (tests-aux-renumber)
|
||||
|
||||
|
||||
* ----------------------------------------
|
||||
* introduce some nodenames and instancenames
|
||||
* intentionally meant to collide with parameter names
|
||||
|
||||
vncol1 n 0 101.0
|
||||
vncol2 p 0 102.0
|
||||
vncol3 x 0 103.0
|
||||
|
||||
vp 1 0 105.0
|
||||
rp 1 0 1.0
|
||||
|
||||
* ----------------------------------------
|
||||
* arbitrary tests
|
||||
|
||||
.func foo0() '1013.0'
|
||||
|
||||
v1001_t n1001_t 0 '100*foo0()'
|
||||
v1001_g n1001_g 0 '101300.0'
|
||||
|
||||
.func bar1(p) 'p'
|
||||
|
||||
v1002_t n1002_t 0 'bar1(117.0)'
|
||||
v1003_t n1003_t 0 '2*bar1(117.0+2.0)'
|
||||
|
||||
v1002_g n1002_g 0 '117.0'
|
||||
v1003_g n1003_g 0 '238.0'
|
||||
|
||||
.func bar2(p) 'v(p)+p'
|
||||
|
||||
b1004_t n1004_t 0 v = 'bar2(17.0)'
|
||||
v1004_g n1004_g 0 '119.0'
|
||||
|
||||
.func bar3(p) 'p+v(p)'
|
||||
|
||||
b1005_t n1005_t 0 v = 'bar3(17.0)'
|
||||
v1005_g n1005_g 0 '119.0'
|
||||
|
||||
.func bar4(p) 'p+v(p)+p'
|
||||
|
||||
b1006_t n1006_t 0 v = 'bar4(17.0)'
|
||||
v1006_g n1006_g 0 '136.0'
|
||||
|
||||
.func baz1(n,vp) 'n+i(vp)+vp'
|
||||
|
||||
b1007_t n1007_t 0 v = 'baz1(17.0,10000)'
|
||||
v1007_g n1007_g 0 '9912'
|
||||
|
||||
.func baz2(p,n) 'v(p)+p+v(n)'
|
||||
|
||||
b1008_t n1008_t 0 v = 'baz2(1000.0,1e20)'
|
||||
v1008_g n1008_g 0 '1203.0'
|
||||
|
||||
.func baz3(x) 'x+x'
|
||||
|
||||
v1009_t n1009_t 0 '17*baz3(100.0)'
|
||||
v1009_g n1009_g 0 '3400.0'
|
||||
|
||||
.func moo1(x,p,n) 'x<p?p:n'
|
||||
v1010_t n1010_t 0 '10*moo1(2,3,5)'
|
||||
v1010_g n1010_g 0 '30'
|
||||
|
||||
v1011_t n1011_t 0 '10*moo1(4,3,5)'
|
||||
v1011_g n1011_g 0 '50'
|
||||
|
||||
.func moo2(x,p,n) 'x<p?p:x>n?n:x'
|
||||
v1012_t n1012_t 0 '10*moo2(4,3,5)*100'
|
||||
v1012_g n1012_g 0 '4000'
|
||||
|
||||
v1013_t n1013_t 0 '10*moo2(2,3,5)*100'
|
||||
v1013_g n1013_g 0 '3000'
|
||||
|
||||
v1014_t n1014_t 0 '10*moo2(6,3,5)*100'
|
||||
v1014_g n1014_g 0 '5000'
|
||||
|
||||
* ----------------------------------------
|
||||
|
||||
.param xoo = 100
|
||||
.func fun1(a, xoo) 'a*xoo'
|
||||
|
||||
v1015_t n1015_t 0 'fun1(xoo,2)'
|
||||
v1015_g n1015_g 0 '200'
|
||||
|
||||
* ----------------------------------------
|
||||
|
||||
.control
|
||||
|
||||
define mismatch(a,b,err) abs(a-b)>err
|
||||
|
||||
op
|
||||
|
||||
let total_count = 0
|
||||
let fail_count = 0
|
||||
|
||||
let tests = 1001 + vector(15)
|
||||
|
||||
foreach n $&tests
|
||||
set n_test = "n{$n}_t"
|
||||
set n_gold = "n{$n}_g"
|
||||
if mismatch(v($n_test), v($n_gold), 1e-9)
|
||||
let v_test = v($n_test)
|
||||
let v_gold = v($n_gold)
|
||||
echo "ERROR, test failure, v($n_test) = $&v_test but should be $&v_gold"
|
||||
let fail_count = fail_count + 1
|
||||
end
|
||||
let total_count = total_count + 1
|
||||
end
|
||||
|
||||
if fail_count > 0
|
||||
echo "ERROR: $&fail_count of $&total_count tests failed"
|
||||
quit 1
|
||||
else
|
||||
echo "INFO: $&fail_count of $&total_count tests failed"
|
||||
quit 0
|
||||
end
|
||||
|
||||
.endc
|
||||
|
||||
.end
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
Circuit: * 'xpressn-1' check xpressn.c parser
|
||||
|
||||
Doing analysis at TEMP = 27.000000 and TNOM = 27.000000
|
||||
|
||||
|
||||
|
||||
No. of Data Rows : 1
|
||||
INFO: 0 of 15 tests failed
|
||||
Loading…
Reference in New Issue