ngspice/src/frontend/com_let.c

249 lines
6.3 KiB
C

#include <stddef.h>
#include "ngspice/dvec.h"
#include "ngspice/ngspice.h"
#include "ngspice/fteext.h"
#include "ngspice/cpextern.h"
#include "com_let.h"
#include "com_display.h"
#include "completion.h"
void
com_let(wordlist *wl)
{
char *p, *q, *s;
int indices[MAXDIMS];
int numdims;
wordlist fake_wl;
int need_open;
int offset, length;
struct pnode *names;
struct dvec *n, *t;
int i, cube;
int j, depth;
int newvec;
char *rhs;
fake_wl.wl_next = NULL;
if (!wl) {
com_display(NULL);
return;
}
p = wl_flatten(wl);
/* extract indices */
numdims = 0;
if ((rhs = strchr(p, '=')) != NULL) {
*rhs++ = 0;
} else {
fprintf(cp_err, "Error: bad let syntax\n");
tfree(p);
return;
}
if ((s = strchr(p, '[')) != NULL) {
need_open = 0;
*s++ = 0;
while (!need_open || *s == '[') {
depth = 0;
if (need_open)
s++;
for (q = s; *q && (*q != ']' && (*q != ',' || depth > 0)); q++) {
switch (*q) {
case '[':
depth += 1;
break;
case ']':
depth -= 1;
break;
}
}
if (depth != 0 || !*q) {
printf("syntax error specifying index\n");
tfree(p);
return;
}
if (*q == ']')
need_open = 1;
else
need_open = 0;
if (*q)
*q++ = 0;
/* evaluate expression between s and q */
/* va, indexing */
fake_wl.wl_word = s;
names = ft_getpnames(&fake_wl, TRUE);
if (!names) {
/* XXX error message */
tfree(p);
return;
}
t = ft_evaluate(names);
if (!t) {
fprintf(cp_err, "Error: Can't evaluate %s\n", s);
free_pnode(names);
tfree(p);
return;
}
if (!isreal(t) || t->v_link2 || t->v_length != 1 || !t->v_realdata) {
fprintf(cp_err, "Error: index is not a scalar.\n");
goto quit;
}
j = (int)floor(t->v_realdata[0]+0.5); /* ignore sanity checks for now, va, which checks? */
if (j < 0) {
printf("negative index (%d) is not allowed\n", j);
goto quit;
}
indices[numdims++] = j;
/* va: garbage collection for t, if pnode `names' is no simple value */
if (names != NULL && names->pn_value == NULL && t != NULL)
vec_free(t);
free_pnode(names); /* frees also t, if pnode `names' is simple value */
for (s = q; *s && isspace(*s); s++)
;
}
}
/* vector name at p */
for (q = p + strlen(p) - 1; *q <= ' ' && p <= q; q--)
;
*++q = 0;
/* sanity check */
if (eq(p, "all") ||strchr(p, '@')) {
fprintf(cp_err, "Error: bad variable name %s\n", p);
tfree(p);
return;
}
/* evaluate rhs */
fake_wl.wl_word = rhs;
names = ft_getpnames(&fake_wl, TRUE);
if (names == NULL) {
/* XXX error message */
tfree(p);
return;
}
t = ft_evaluate(names);
if (!t) {
fprintf(cp_err, "Error: Can't evaluate %s\n", rhs);
free_pnode(names);
tfree(p);
return;
}
if (t->v_link2)
fprintf(cp_err, "Warning: extra wildcard values ignored\n");
n = vec_get(p);
if (n) {
/* re-allocate? */
/* vec_free(n); */
newvec = 0;
} else {
if (numdims) {
fprintf(cp_err, "Can't assign into a subindex of a new vector\n");
goto quit;
}
/* create and assign a new vector */
n = alloc(struct dvec);
ZERO(n, struct dvec);
n->v_name = copy(p);
n->v_type = t->v_type;
n->v_flags = (t->v_flags | VF_PERMANENT);
n->v_length = t->v_length;
if ((t->v_numdims) <= 1) { // changed from "!t->v_numdims" by Friedrich Schmidt
n->v_numdims = 1;
n->v_dims[0] = n->v_length;
} else {
n->v_numdims = t->v_numdims;
for (i = 0; i < t->v_numdims; i++)
n->v_dims[i] = t->v_dims[i];
}
if (isreal(t))
n->v_realdata = TMALLOC(double, n->v_length);
else
n->v_compdata = TMALLOC(ngcomplex_t, n->v_length);
newvec = 1;
vec_new(n);
}
/* fix-up dimensions; va, also for v_dims */
if (n->v_numdims < 1 || n->v_dims[0] == 0 ) {
n->v_numdims = 1;
n->v_dims[0] = n->v_length;
}
/* Compare dimensions */
offset = 0;
length = n->v_length;
cube = 1;
for (i = n->v_numdims - 1; i >= numdims; i--)
cube *= n->v_dims[i];
for (i = numdims - 1; i >= 0; i--) {
offset += cube * indices[i];
if (i < n->v_numdims) {
cube *= n->v_dims[i];
length /= n->v_dims[i];
}
}
/* length is the size of the unit refered to */
/* cube ends up being the length */
if (length > t->v_length) {
fprintf(cp_err, "left-hand expression is too small (need %d)\n",
length * cube);
if (newvec)
n->v_flags &= ~VF_PERMANENT;
goto quit;
}
if (isreal(t) != isreal(n)) {
fprintf(cp_err,
"Types of vectors are not the same (real vs. complex)\n");
if (newvec)
n->v_flags &= ~VF_PERMANENT;
goto quit;
} else if (isreal(t)) {
bcopy(t->v_realdata, n->v_realdata + offset,
(size_t) length * sizeof(double));
} else {
bcopy(t->v_compdata, n->v_compdata + offset,
(size_t) length * sizeof(ngcomplex_t));
}
n->v_minsignal = 0.0; /* How do these get reset ??? */
n->v_maxsignal = 0.0;
n->v_scale = t->v_scale;
if (newvec)
cp_addkword(CT_VECTOR, n->v_name);
quit:
/* va: garbage collection for t, if pnode `names' is no simple value */
if (names != NULL && names->pn_value == NULL && t != NULL)
vec_free(t);
free_pnode(names); /* frees also t, if pnode `names' is simple value */
tfree(p);
}