1 /**********
2 Copyright 1990 Regents of the University of California. All rights reserved.
3 Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
4 **********/
5
6 /*
7 * User-defined functions. The user defines the function with
8 * define func(arg1, arg2, arg3) <expression involving args...>
9 * Then when he types "func(1, 2, 3)", the commas are interpreted as
10 * binary operations of the lowest priority by the parser, and ft_substdef()
11 * below is given a chance to fill things in and return what the parse tree
12 * would have been had the entire thing been typed.
13 * Note that we have to take some care to distinguish between functions
14 * with the same name and different arities.
15 */
16
17 #include "ngspice/ngspice.h"
18 #include "ngspice/cpdefs.h"
19 #include "ngspice/ftedefs.h"
20 #include "ngspice/dvec.h"
21 #include "ngspice/fteparse.h"
22 #include "define.h"
23
24 #include "completion.h"
25
26
27 static void savetree(struct pnode *pn);
28 static void prdefs(char *name);
29 static void prtree(struct udfunc *ud, FILE *fp);
30 static void prtree1(struct pnode *pn, FILE *fp);
31 static struct pnode *trcopy(struct pnode *tree, char *arg_names, struct pnode *args);
32 static struct pnode *ntharg(int num, struct pnode *args);
33 static int numargs(struct pnode *args);
34
35 static struct udfunc *udfuncs = NULL;
36
37
38 /* Set up a function definition. */
39
40 void
com_define(wordlist * wlist)41 com_define(wordlist *wlist)
42 {
43 int arity = 0, i;
44 char buf[BSIZE_SP], tbuf[BSIZE_SP], *s, *t, *b;
45 wordlist *wl;
46 struct pnode *names;
47 struct udfunc *udf;
48
49 /* If there's nothing then print all the definitions. */
50 if (wlist == NULL) {
51 prdefs(NULL);
52 return;
53 }
54
55 /* Accumulate the function head in the buffer, w/out spaces. A
56 * useful thing here would be to check to make sure that there
57 * are no formal parameters here called "list". But you have
58 * to try really hard to break this here.
59 */
60 buf[0] = '\0';
61
62 for (wl = wlist; wl && (strchr(wl->wl_word, ')') == NULL);
63 wl = wl->wl_next)
64 (void) strcat(buf, wl->wl_word);
65
66 if (wl) {
67 t = strchr(buf, '\0');
68 for (s = wl->wl_word; *s && (*s != ')');)
69 *t++ = *s++;
70 *t++ = ')';
71 *t = '\0';
72 if (*++s)
73 wl->wl_word = copy(s);
74 else
75 wl = wl->wl_next;
76 }
77
78 /* If that's all, then print the definition. */
79 if (wl == NULL) {
80 s = strchr(buf, '(');
81 if (s)
82 *s = '\0';
83 prdefs(buf);
84 return;
85 }
86
87 /* Now check to see if this is a valid name for a function (i.e,
88 * there isn't a predefined function of the same name).
89 */
90 (void) strcpy(tbuf, buf);
91
92 for (b = tbuf; *b; b++)
93 if (isspace_c(*b) || (*b == '(')) {
94 *b = '\0';
95 break;
96 }
97
98 for (i = 0; ft_funcs[i].fu_name; i++)
99 if (eq(ft_funcs[i].fu_name, tbuf)) {
100 fprintf(cp_err, "Error: %s is a predefined function.\n",
101 tbuf);
102 return;
103 }
104
105 /* Parse the rest of it. We can't know if there are the right
106 * number of undefined variables in the expression.
107 */
108 if ((names = ft_getpnames(wl, FALSE)) == NULL)
109 return;
110
111 /* This is a pain -- when things are garbage-collected, any
112 * vectors that may have been mentioned here will be thrown
113 * away. So go down the tree and save any vectors that aren't
114 * formal parameters.
115 */
116 savetree(names);
117
118 /* Format the name properly and add to the list. */
119 b = copy(buf);
120 for (s = b; *s; s++) {
121 if (*s == '(') {
122 *s = '\0';
123 if (s[1] != ')')
124 arity++; /* It will have been 0. */
125 } else if (*s == ')') {
126 *s = '\0';
127 } else if (*s == ',') {
128 *s = '\0';
129 arity++;
130 }
131 }
132
133 for (udf = udfuncs; udf; udf = udf->ud_next)
134 if (prefix(b, udf->ud_name) && (arity == udf->ud_arity))
135 break;
136
137 if (udf == NULL) {
138 udf = TMALLOC(struct udfunc, 1);
139 udf->ud_next = udfuncs;
140 udfuncs = udf;
141 }
142
143 udf->ud_text = names;
144 udf->ud_name = b;
145 udf->ud_arity = arity;
146
147 cp_addkword(CT_UDFUNCS, b);
148 }
149
150
151 /* Kludge. */
152
153 static void
savetree(struct pnode * pn)154 savetree(struct pnode *pn)
155 {
156 struct dvec *d;
157
158 if (pn->pn_value) {
159 /* We specifically don't add this to the plot list
160 * so it won't get gc'ed.
161 */
162 d = pn->pn_value;
163 if ((d->v_length != 0) || eq(d->v_name, "list")) {
164 pn->pn_value = dvec_alloc(copy(d->v_name),
165 d->v_type,
166 d->v_flags,
167 d->v_length, NULL);
168
169 /* this dvec isn't member of any plot */
170
171 if (isreal(d)) {
172 memcpy(pn->pn_value->v_realdata,
173 d->v_realdata,
174 sizeof(double) * (size_t) d->v_length);
175 } else {
176 memcpy(pn->pn_value->v_compdata,
177 d->v_compdata,
178 sizeof(ngcomplex_t) * (size_t) d->v_length);
179 }
180 }
181 } else if (pn->pn_op) {
182 savetree(pn->pn_left);
183 if (pn->pn_op->op_arity == 2)
184 savetree(pn->pn_right);
185 } else if (pn->pn_func) {
186 savetree(pn->pn_left);
187 }
188 }
189
190
191 /* A bunch of junk to print out nodes. */
192
193 static void
prdefs(char * name)194 prdefs(char *name)
195 {
196 struct udfunc *udf;
197
198 if (name && *name) { /* You never know what people will do */
199 for (udf = udfuncs; udf; udf = udf->ud_next)
200 if (eq(name, udf->ud_name))
201 prtree(udf, cp_out);
202 } else {
203 for (udf = udfuncs; udf; udf = udf->ud_next)
204 prtree(udf, cp_out);
205 }
206 }
207
208
209 /* Print out one definition. */
210
211 static void
prtree(struct udfunc * ud,FILE * fp)212 prtree(struct udfunc *ud, FILE *fp)
213 {
214 const char *s = ud->ud_name;
215
216 /* print the function name */
217 fprintf(fp, "%s (", s);
218 s = strchr(s, '\0') + 1;
219
220 /* print the formal args */
221 while (*s) {
222 fputs(s, fp);
223 s = strchr(s, '\0') + 1;
224 if (*s)
225 fputs(", ", fp);
226 }
227 fputs(") = ", fp);
228
229 /* print the function body */
230 prtree1(ud->ud_text, fp);
231 putc('\n', fp);
232 }
233
234
235 static void
prtree1(struct pnode * pn,FILE * fp)236 prtree1(struct pnode *pn, FILE *fp)
237 {
238 if (pn->pn_value) {
239 fputs(pn->pn_value->v_name, fp);
240 } else if (pn->pn_func) {
241 fprintf(fp, "%s (", pn->pn_func->fu_name);
242 prtree1(pn->pn_left, fp);
243 fputs(")", fp);
244 } else if (pn->pn_op && (pn->pn_op->op_arity == 2)) {
245 fputs("(", fp);
246 prtree1(pn->pn_left, fp);
247 fprintf(fp, ")%s(", pn->pn_op->op_name);
248 prtree1(pn->pn_right, fp);
249 fputs(")", fp);
250 } else if (pn->pn_op && (pn->pn_op->op_arity == 1)) {
251 fprintf(fp, "%s(", pn->pn_op->op_name);
252 prtree1(pn->pn_left, fp);
253 fputs(")", fp);
254 } else {
255 fputs("<something strange>", fp);
256 }
257 }
258
259
260 struct pnode *
ft_substdef(const char * name,struct pnode * args)261 ft_substdef(const char *name, struct pnode *args)
262 {
263 struct udfunc *udf, *wrong_udf = NULL;
264 char *arg_names;
265
266 int arity = numargs(args);
267
268 for (udf = udfuncs; udf; udf = udf->ud_next)
269 if (eq(name, udf->ud_name)) {
270 if (arity == udf->ud_arity)
271 break;
272 wrong_udf = udf;
273 }
274
275 if (udf == NULL) {
276 if (wrong_udf)
277 fprintf(cp_err,
278 "Warning: the user-defined function %s has %d args\n",
279 name, wrong_udf->ud_arity);
280 return NULL;
281 }
282
283 arg_names = strchr(udf->ud_name, '\0') + 1;
284
285 /* Now we have to traverse the tree and copy it over,
286 * substituting args.
287 */
288 return trcopy(udf->ud_text, arg_names, args);
289 }
290
291
292 /* Copy the tree and replace formal args with the right stuff. The way
293 * we know that something might be a formal arg is when it is a dvec
294 * with length 0 and a name that isn't "list". I hope nobody calls their
295 * formal parameters "list".
296 */
297
298 static struct pnode *
trcopy(struct pnode * tree,char * arg_names,struct pnode * args)299 trcopy(struct pnode *tree, char *arg_names, struct pnode *args)
300 {
301 if (tree->pn_value) {
302
303 struct dvec *d = tree->pn_value;
304
305 if ((d->v_length == 0) && strcmp(d->v_name, "list")) {
306
307 /* Yep, it's a formal parameter. Substitute for it.
308 * IMPORTANT: we never free parse trees, so we
309 * needn't worry that they aren't trees here.
310 */
311
312 char *s = arg_names;
313 int i;
314
315 for (i = 1; *s; i++) {
316 if (eq(s, d->v_name))
317 return ntharg(i, args);
318 s = strchr(s, '\0') + 1;
319 }
320
321 return tree;
322 }
323
324 return tree;
325 }
326
327 if (tree->pn_func) {
328
329 struct pnode *pn = alloc_pnode();
330
331 /* pn_func are pointers to a global constant struct */
332 pn->pn_func = tree->pn_func;
333
334 pn->pn_left = trcopy(tree->pn_left, arg_names, args);
335 pn->pn_left->pn_use++;
336
337 return pn;
338 }
339
340 if (tree->pn_op) {
341
342 struct pnode *pn = alloc_pnode();
343
344 /* pn_op are pointers to a global constant struct */
345 pn->pn_op = tree->pn_op;
346
347 pn->pn_left = trcopy(tree->pn_left, arg_names, args);
348 pn->pn_left->pn_use++;
349
350 if (pn->pn_op->op_arity == 2) {
351 pn->pn_right = trcopy(tree->pn_right, arg_names, args);
352 pn->pn_right->pn_use++;
353 }
354
355 return pn;
356 }
357
358 fprintf(cp_err, "trcopy: Internal Error: bad parse node\n");
359 return NULL;
360 }
361
362
363 /* Find the n'th arg in the arglist, returning NULL if there isn't one.
364 * Since comma has such a low priority and associates to the right,
365 * we can just follow the right branch of the tree num times.
366 * Note that we start at 1 when numbering the args.
367 */
368
369 static struct pnode *
ntharg(int num,struct pnode * args)370 ntharg(int num, struct pnode *args)
371 {
372 for (; args; args = args->pn_right, --num) {
373 if (num <= 1) {
374 if (args->pn_op && (args->pn_op->op_num == PT_OP_COMMA))
375 return args->pn_left;
376 return args;
377 }
378 if (!(args->pn_op && (args->pn_op->op_num == PT_OP_COMMA)))
379 return NULL;
380 }
381
382 return NULL;
383 }
384
385
386 static int
numargs(struct pnode * args)387 numargs(struct pnode *args)
388 {
389 int arity;
390
391 if (!args)
392 return 0;
393
394 for (arity = 1; args; args = args->pn_right, arity++)
395 if (!(args->pn_op && (args->pn_op->op_num == PT_OP_COMMA)))
396 return arity;
397
398 // note: a trailing NULL pn_right will be counted too
399 return arity;
400 }
401
402
403 void
com_undefine(wordlist * wlist)404 com_undefine(wordlist *wlist)
405 {
406 struct udfunc *udf;
407
408 if (!wlist)
409 return;
410
411 if (*wlist->wl_word == '*') {
412 for (udf = udfuncs; udf;) {
413 struct udfunc *next = udf->ud_next;
414 cp_remkword(CT_UDFUNCS, udf->ud_name);
415 free_pnode(udf->ud_text);
416 tfree(udf->ud_name);
417 tfree(udf);
418 udf = next;
419 }
420 udfuncs = NULL;
421 return;
422 }
423
424 for (; wlist; wlist = wlist->wl_next) {
425 struct udfunc *prev_udf = NULL;
426 for (udf = udfuncs; udf;) {
427 struct udfunc *next = udf->ud_next;
428 if (eq(wlist->wl_word, udf->ud_name)) {
429 if (prev_udf)
430 prev_udf->ud_next = udf->ud_next;
431 else
432 udfuncs = udf->ud_next;
433 cp_remkword(CT_UDFUNCS, wlist->wl_word);
434 free_pnode(udf->ud_text);
435 tfree(udf->ud_name);
436 tfree(udf);
437 } else {
438 prev_udf = udf;
439 }
440 udf = next;
441 }
442 }
443 }
444
445
446 /*
447 * This is only here so I can "call" it from gdb/dbx
448 */
449
450 void
ft_pnode(struct pnode * pn)451 ft_pnode(struct pnode *pn)
452 {
453 prtree1(pn, cp_err);
454 }
455