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