Icons are changed
[gnuplot] / src / parse.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: parse.c,v 1.47.2.1 2008/04/08 19:00:44 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - parse.c */
6
7 /*[
8  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 #include "parse.h"
38
39 #include "alloc.h"
40 #include "command.h"
41 #include "eval.h"
42 #include "help.h"
43 #include "util.h"
44
45 /* protection mechanism for parsing string followed by + or - sign */
46 static int parse_recursion_level;
47 static TBOOLEAN string_result_only = FALSE;
48
49 /* Exported globals: the current 'dummy' variable names */
50 char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1];
51 char set_dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1] = { "x", "y" };
52
53 /* This is used by plot_option_using() */
54 int at_highest_column_used = -1;
55
56 /* Internal prototypes: */
57
58 static void convert __PROTO((struct value *, int));
59 static void extend_at __PROTO((void));
60 static union argument *add_action __PROTO((enum operators sf_index));
61 static void parse_expression __PROTO((void));
62 static void accept_logical_OR_expression __PROTO((void));
63 static void accept_logical_AND_expression __PROTO((void));
64 static void accept_inclusive_OR_expression __PROTO((void));
65 static void accept_exclusive_OR_expression __PROTO((void));
66 static void accept_AND_expression __PROTO((void));
67 static void accept_equality_expression __PROTO((void));
68 static void accept_relational_expression __PROTO((void));
69 static void accept_additive_expression __PROTO((void));
70 static void accept_multiplicative_expression __PROTO((void));
71 static void parse_primary_expression __PROTO((void));
72 static void parse_conditional_expression __PROTO((void));
73 static void parse_logical_OR_expression __PROTO((void));
74 static void parse_logical_AND_expression __PROTO((void));
75 static void parse_inclusive_OR_expression __PROTO((void));
76 static void parse_exclusive_OR_expression __PROTO((void));
77 static void parse_AND_expression __PROTO((void));
78 static void parse_equality_expression __PROTO((void));
79 static void parse_relational_expression __PROTO((void));
80 static void parse_additive_expression __PROTO((void));
81 static void parse_multiplicative_expression __PROTO((void));
82 static void parse_unary_expression __PROTO((void));
83 static int is_builtin_function __PROTO((int t_num));
84
85 /* Internal variables: */
86
87 static struct at_type *at = NULL;
88 static int at_size = 0;
89
90 static void
91 convert(struct value *val_ptr, int t_num)
92 {
93     *val_ptr = token[t_num].l_val;
94 }
95
96
97 /* JW 20051126:
98  * Wrapper around const_express() called by try_to_get_string().
99  * Disallows top level + and - operators.
100  * This enables things like set xtics ('-\pi' -pi, '-\pi/2' -pi/2.)
101  */
102 struct value *
103 const_string_express(struct value *valptr)
104 {
105     string_result_only = TRUE;
106     const_express(valptr);
107     string_result_only = FALSE;
108     return (valptr);
109 }
110
111 struct value *
112 const_express(struct value *valptr)
113 {
114     int tkn = c_token;
115
116     if (END_OF_COMMAND)
117         int_error(c_token, "constant expression required");
118
119     /* div - no dummy variables in a constant expression */
120     dummy_func = NULL;
121
122     evaluate_at(temp_at(), valptr);     /* run it and send answer back */
123
124     if (undefined) {
125         int_error(tkn, "undefined value");
126     }
127     return (valptr);
128 }
129
130 /* Used by plot2d/plot3d/fit:
131  * Parse an expression that may return a string or may return a constant or may
132  * be a dummy function using dummy variables x, y, ...
133  * If any dummy variables are present, set (*atptr) to point to an action table
134  * corresponding to the parsed expression, and return NULL.
135  * Otherwise evaluate the expression and return a string if there is one.
136  * The return value "str" and "*atptr" both point to locally-managed memory,
137  * which must not be freed by the caller!
138  */
139 char*
140 string_or_express(struct at_type **atptr)
141 {
142     int i;
143     TBOOLEAN has_dummies;
144
145     static char* str = NULL;
146     free(str);
147     str = NULL;
148
149     if (END_OF_COMMAND)
150         int_error(c_token, "expression expected");
151
152 #ifndef GP_STRING_VARS
153     if (isstring(c_token)) {
154         if (atptr)
155             *atptr = NULL;
156         str = try_to_get_string();
157         return str;
158     }
159 #endif
160
161     /* parse expression */
162     temp_at();
163
164     /* check if any dummy variables are used */
165     has_dummies = FALSE;
166     for (i = 0; i < at->a_count; i++) {
167         enum operators op_index = at->actions[i].index;
168         if ( op_index == PUSHD1 || op_index == PUSHD2 || op_index == PUSHD ) {
169             has_dummies = TRUE;
170             break;
171         }
172     }
173
174     if (!has_dummies) {
175         /* no dummy variables: evaluate expression */
176         struct value val;
177
178         evaluate_at(at, &val);
179 #ifdef GP_STRING_VARS
180         if (!undefined && val.type == STRING)
181             str = val.v.string_val;
182 #endif
183     }
184
185     /* prepare return */
186     if (atptr)
187         *atptr  = at;
188     return str;
189 }
190
191
192 /* build an action table and return its pointer, but keep a pointer in at
193  * so that we can free it later if the caller hasn't taken over management
194  * of this table.
195  */
196
197 struct at_type *
198 temp_at()
199 {
200     if (at != NULL)
201         free_at(at);
202     
203     at = (struct at_type *) gp_alloc(sizeof(struct at_type), "action table");
204
205     memset(at, 0, sizeof(*at));         /* reset action table !!! */
206     at_size = MAX_AT_LEN;
207
208     parse_recursion_level = 0;
209     parse_expression();
210     return (at);
211 }
212
213
214 /* build an action table, put it in dynamic memory, and return its pointer */
215
216 struct at_type *
217 perm_at()
218 {
219     struct at_type *at_ptr;
220     size_t len;
221
222     (void) temp_at();
223     len = sizeof(struct at_type) +
224      (at->a_count - MAX_AT_LEN) * sizeof(struct at_entry);
225     at_ptr = (struct at_type *) gp_realloc(at, len, "perm_at");
226     at = NULL;                  /* invalidate at pointer */
227     return (at_ptr);
228 }
229
230 static void
231 extend_at()
232 {
233     size_t newsize = sizeof(struct at_type) + at_size * sizeof(struct at_entry);
234
235     at = gp_realloc(at, newsize, "extend_at");
236     at_size += MAX_AT_LEN;
237     FPRINTF((stderr, "Extending at size to %d\n", at_size));
238 }
239
240 /* Add function number <sf_index> to the current action table */
241 static union argument *
242 add_action(enum operators sf_index)
243 {
244     if (at->a_count >= at_size) {
245         extend_at();
246     }
247     at->actions[at->a_count].index = sf_index;
248     return (&(at->actions[at->a_count++].arg));
249 }
250
251
252 /* For external calls to parse_expressions() 
253  * parse_recursion_level is expected to be 0 */
254 static void
255 parse_expression()
256 {                               /* full expressions */
257     parse_recursion_level++;
258     accept_logical_OR_expression();
259     parse_conditional_expression();
260     parse_recursion_level--;
261 }
262
263 static void
264 accept_logical_OR_expression()
265 {                               /* ? : expressions */
266     accept_logical_AND_expression();
267     parse_logical_OR_expression();
268 }
269
270
271 static void
272 accept_logical_AND_expression()
273 {
274     accept_inclusive_OR_expression();
275     parse_logical_AND_expression();
276 }
277
278
279 static void
280 accept_inclusive_OR_expression()
281 {
282     accept_exclusive_OR_expression();
283     parse_inclusive_OR_expression();
284 }
285
286
287 static void
288 accept_exclusive_OR_expression()
289 {
290     accept_AND_expression();
291     parse_exclusive_OR_expression();
292 }
293
294
295 static void
296 accept_AND_expression()
297 {
298     accept_equality_expression();
299     parse_AND_expression();
300 }
301
302
303 static void
304 accept_equality_expression()
305 {
306     accept_relational_expression();
307     parse_equality_expression();
308 }
309
310
311 static void
312 accept_relational_expression()
313 {
314     accept_additive_expression();
315     parse_relational_expression();
316 }
317
318
319 static void
320 accept_additive_expression()
321 {
322     accept_multiplicative_expression();
323     parse_additive_expression();
324 }
325
326
327 static void
328 accept_multiplicative_expression()
329 {
330     parse_unary_expression();                   /* - things */
331     parse_multiplicative_expression();                  /* * / % */
332 }
333
334
335 /* add action table entries for primary expressions, i.e. either a
336  * parenthesized expression, a variable names, a numeric constant, a
337  * function evaluation, a power operator or postfix '!' (factorial)
338  * expression */
339 static void
340 parse_primary_expression()
341 {
342     if (equals(c_token, "(")) {
343         c_token++;
344         parse_expression();
345         if (!equals(c_token, ")"))
346             int_error(c_token, "')' expected");
347         c_token++;
348     } else if (equals(c_token, "$")) {
349         struct value a;
350
351         if (!isanumber(++c_token))
352             int_error(c_token, "Column number expected");
353         convert(&a, c_token++);
354         if (a.type != INTGR || a.v.int_val < 0)
355             int_error(c_token, "Positive integer expected");
356         if (at_highest_column_used < a.v.int_val)
357             at_highest_column_used = a.v.int_val;
358         add_action(DOLLARS)->v_arg = a;
359     } else if (isanumber(c_token)) {
360         /* work around HP 9000S/300 HP-UX 9.10 cc limitation ... */
361         /* HBB 20010724: use this code for all platforms, then */
362         union argument *foo = add_action(PUSHC);
363
364         convert(&(foo->v_arg), c_token);
365         c_token++;
366     } else if (isletter(c_token)) {
367         /* Found an identifier --- check whether its a function or a
368          * variable by looking for the parentheses of a function
369          * argument list */
370         if ((c_token + 1 < num_tokens) && equals(c_token + 1, "(")) {
371             enum operators whichfunc = is_builtin_function(c_token);
372             struct value num_params;
373             num_params.type = INTGR;
374
375             if (whichfunc) {
376 #ifdef BACKWARDS_COMPATIBLE
377                 /* Deprecated syntax:   if (defined(foo)) ...  */
378                 /* New syntax:          if (exists("foo")) ... */
379                 if (strcmp(ft[whichfunc].f_name,"defined")==0) {
380                     struct udvt_entry *udv = add_udv(c_token+2);
381                     union argument *foo = add_action(PUSHC);
382                     foo->v_arg.type = INTGR;
383                     foo->v_arg.v.int_val = udv->udv_undef ? 0 : 1;
384                     c_token += 4;  /* skip past "defined ( <foo> ) " */
385                     return;
386                 }
387 #endif
388                 c_token += 2;   /* skip fnc name and '(' */
389                 parse_expression(); /* parse fnc argument */
390                 num_params.v.int_val = 1;
391                 while (equals(c_token, ",")) {
392                     c_token++;
393                     num_params.v.int_val++;
394                     parse_expression();
395                 }
396
397                 if (!equals(c_token, ")"))
398                     int_error(c_token, "')' expected");
399                 c_token++;
400
401 #ifdef GP_STRING_VARS
402                 /* So far sprintf is the only built-in function */
403                 /* with a variable number of arguments.         */
404                 if (!strcmp(ft[whichfunc].f_name,"sprintf"))
405                     add_action(PUSHC)->v_arg = num_params;
406                 /* And "words(s)" is implemented as "word(s,-1)" */
407                 if (!strcmp(ft[whichfunc].f_name,"words")) {
408                     num_params.v.int_val = -1;
409                     add_action(PUSHC)->v_arg = num_params;
410                 }
411 #endif
412                 (void) add_action(whichfunc);
413
414             } else {
415                 /* it's a call to a user-defined function */
416                 enum operators call_type = (int) CALL;
417                 int tok = c_token;
418
419                 c_token += 2;   /* skip func name and '(' */
420                 parse_expression();
421                 if (equals(c_token, ",")) { /* more than 1 argument? */
422                     num_params.v.int_val = 1;
423                     while (equals(c_token, ",")) {
424                         num_params.v.int_val += 1;
425                         c_token += 1;
426                         parse_expression();
427                     }
428                     add_action(PUSHC)->v_arg = num_params;
429                     call_type = (int) CALLN;
430                 }
431                 if (!equals(c_token, ")"))
432                     int_error(c_token, "')' expected");
433                 c_token++;
434                 add_action(call_type)->udf_arg = add_udf(tok);
435             }
436             /* dummy_func==NULL is a flag to say no dummy variables active */
437         } else if (dummy_func) {
438             if (equals(c_token, c_dummy_var[0])) {
439                 c_token++;
440                 add_action(PUSHD1)->udf_arg = dummy_func;
441             } else if (equals(c_token, c_dummy_var[1])) {
442                 c_token++;
443                 add_action(PUSHD2)->udf_arg = dummy_func;
444             } else {
445                 int i, param = 0;
446
447                 for (i = 2; i < MAX_NUM_VAR; i++) {
448                     if (equals(c_token, c_dummy_var[i])) {
449                         struct value num_params;
450                         num_params.type = INTGR;
451                         num_params.v.int_val = i;
452                         param = 1;
453                         c_token++;
454                         add_action(PUSHC)->v_arg = num_params;
455                         add_action(PUSHD)->udf_arg = dummy_func;
456                         break;
457                     }
458                 }
459                 if (!param) {   /* defined variable */
460                     add_action(PUSH)->udv_arg = add_udv(c_token);
461                     c_token++;
462                 }
463             }
464             /* its a variable, with no dummies active - div */
465         } else {
466             add_action(PUSH)->udv_arg = add_udv(c_token);
467             c_token++;
468         }
469     }
470     /* end if letter */
471
472 #ifdef GP_STRING_VARS
473     /* Maybe it's a string constant */
474     else if (isstring(c_token)) {
475         union argument *foo = add_action(PUSHC);
476         foo->v_arg.type = STRING;
477         foo->v_arg.v.string_val = NULL;
478         /* this dynamically allocated string will be freed by free_at() */
479         m_quote_capture(&(foo->v_arg.v.string_val), c_token, c_token);
480         c_token++;
481     }
482 #endif
483
484     else
485         int_error(c_token, "invalid expression ");
486
487     /* add action code for ! (factorial) operator */
488     while (equals(c_token, "!")) {
489         c_token++;
490         (void) add_action(FACTORIAL);
491     }
492     /* add action code for ** operator */
493     if (equals(c_token, "**")) {
494         c_token++;
495         parse_unary_expression();
496         (void) add_action(POWER);
497     }
498 #ifdef GP_STRING_VARS
499     /* Parse and add actions for range specifier applying to previous entity.
500      * Currently only used to generate substrings, but could also be used to
501      * extract vector slices.
502      */
503     if (equals(c_token, "[")) {
504         /* handle '*' or empty start of range */
505         if (equals(++c_token,"*") || equals(c_token,":")) {
506             union argument *empty = add_action(PUSHC);
507             empty->v_arg.type = INTGR;
508             empty->v_arg.v.int_val = 1;
509             if (equals(c_token,"*"))
510                 c_token++;
511         } else
512             parse_expression();
513         if (!equals(c_token, ":"))
514             int_error(c_token, "':' expected");
515         /* handle '*' or empty end of range */
516         if (equals(++c_token,"*") || equals(c_token,"]")) {
517             union argument *empty = add_action(PUSHC);
518             empty->v_arg.type = INTGR;
519             empty->v_arg.v.int_val = 65535; /* should be MAXINT */
520             if (equals(c_token,"*"))
521                 c_token++;
522         } else
523             parse_expression();
524         if (!equals(c_token, "]"))
525             int_error(c_token, "']' expected");
526         c_token++;
527         (void) add_action(RANGE);
528     }
529 #endif
530 }
531
532
533 /* HBB 20010309: Here and below: can't store pointers into the middle
534  * of at->actions[]. That array may be realloc()ed by add_action() or
535  * express() calls!. Access via index savepc1/savepc2, instead. */
536
537 static void
538 parse_conditional_expression()
539 {
540     /* create action code for ? : expressions */
541
542     if (equals(c_token, "?")) {
543         int savepc1, savepc2;
544
545         /* Fake same recursion level for alternatives
546          *   set xlabel a>b ? 'foo' : 'bar' -1, 1
547          * FIXME: This won't work:
548          *   set xlabel a-b>c ? 'foo' : 'bar'  offset -1, 1
549          */
550         parse_recursion_level--;
551
552         c_token++;
553         savepc1 = at->a_count;
554         add_action(JTERN);
555         parse_expression();
556         if (!equals(c_token, ":"))
557             int_error(c_token, "expecting ':'");
558
559         c_token++;
560         savepc2 = at->a_count;
561         add_action(JUMP);
562         at->actions[savepc1].arg.j_arg = at->a_count - savepc1;
563         parse_expression();
564         at->actions[savepc2].arg.j_arg = at->a_count - savepc2;
565         parse_recursion_level++;
566     }
567 }
568
569
570 static void
571 parse_logical_OR_expression()
572 {
573     /* create action codes for || operator */
574
575     while (equals(c_token, "||")) {
576         int savepc;
577
578         c_token++;
579         savepc = at->a_count;
580         add_action(JUMPNZ);     /* short-circuit if already TRUE */
581         accept_logical_AND_expression();
582         /* offset for jump */
583         at->actions[savepc].arg.j_arg = at->a_count - savepc;
584         (void) add_action(BOOLE);
585     }
586 }
587
588
589 static void
590 parse_logical_AND_expression()
591 {
592     /* create action code for && operator */
593
594     while (equals(c_token, "&&")) {
595         int savepc;
596
597         c_token++;
598         savepc = at->a_count;
599         add_action(JUMPZ);      /* short-circuit if already FALSE */
600         accept_inclusive_OR_expression();
601         at->actions[savepc].arg.j_arg = at->a_count - savepc; /* offset for jump */
602         (void) add_action(BOOLE);
603     }
604 }
605
606
607 static void
608 parse_inclusive_OR_expression()
609 {
610     /* create action code for | operator */
611
612     while (equals(c_token, "|")) {
613         c_token++;
614         accept_exclusive_OR_expression();
615         (void) add_action(BOR);
616     }
617 }
618
619
620 static void
621 parse_exclusive_OR_expression()
622 {
623     /* create action code for ^ operator */
624
625     while (equals(c_token, "^")) {
626         c_token++;
627         accept_AND_expression();
628         (void) add_action(XOR);
629     }
630 }
631
632
633 static void
634 parse_AND_expression()
635 {
636     /* create action code for & operator */
637
638     while (equals(c_token, "&")) {
639         c_token++;
640         accept_equality_expression();
641         (void) add_action(BAND);
642     }
643 }
644
645
646 static void
647 parse_equality_expression()
648 {
649     /* create action codes for == and != numeric operators
650      * eq and ne string operators */
651
652     while (TRUE) {
653         if (equals(c_token, "==")) {
654             c_token++;
655             accept_relational_expression();
656             (void) add_action(EQ);
657         } else if (equals(c_token, "!=")) {
658             c_token++;
659             accept_relational_expression();
660             (void) add_action(NE);
661 #ifdef GP_STRING_VARS
662         } else if (equals(c_token, "eq")) {
663             c_token++;
664             accept_relational_expression();
665             (void) add_action(EQS);
666         } else if (equals(c_token, "ne")) {
667             c_token++;
668             accept_relational_expression();
669             (void) add_action(NES);
670 #endif
671         } else
672             break;
673     }
674 }
675
676
677 static void
678 parse_relational_expression()
679 {
680     /* create action code for < > >= or <=
681      * operators */
682
683     while (TRUE) {
684         /* I hate "else if" statements */
685         if (equals(c_token, ">")) {
686             c_token++;
687             accept_additive_expression();
688             (void) add_action(GT);
689         } else if (equals(c_token, "<")) {
690             c_token++;
691             accept_additive_expression();
692             (void) add_action(LT);
693         } else if (equals(c_token, ">=")) {
694             c_token++;
695             accept_additive_expression();
696             (void) add_action(GE);
697         } else if (equals(c_token, "<=")) {
698             c_token++;
699             accept_additive_expression();
700             (void) add_action(LE);
701         } else
702             break;
703     }
704
705 }
706
707
708
709 static void
710 parse_additive_expression()
711 {
712     /* create action codes for +, - and . operators */
713     while (TRUE) {
714 #ifdef GP_STRING_VARS
715         if (equals(c_token, ".")) {
716             c_token++;
717             accept_multiplicative_expression();
718             (void) add_action(CONCATENATE);
719         /* If only string results are wanted
720          * do not accept '-' or '+' at the top level. */
721         } else if (string_result_only && parse_recursion_level == 1)
722             break;
723         else
724 #endif
725         if (equals(c_token, "+")) {
726             c_token++;
727             accept_multiplicative_expression();
728             (void) add_action(PLUS);
729         } else if (equals(c_token, "-")) {
730             c_token++;
731             accept_multiplicative_expression();
732             (void) add_action(MINUS);
733         } else
734             break;
735     }
736 }
737
738
739 static void
740 parse_multiplicative_expression()
741 {
742     /* add action code for * / and % operators */
743
744     while (TRUE) {
745         if (equals(c_token, "*")) {
746             c_token++;
747             parse_unary_expression();
748             (void) add_action(MULT);
749         } else if (equals(c_token, "/")) {
750             c_token++;
751             parse_unary_expression();
752             (void) add_action(DIV);
753         } else if (equals(c_token, "%")) {
754             c_token++;
755             parse_unary_expression();
756             (void) add_action(MOD);
757         } else
758             break;
759     }
760 }
761
762
763 static void
764 parse_unary_expression()
765 {
766     /* add code for unary operators */
767
768     if (equals(c_token, "!")) {
769         c_token++;
770         parse_unary_expression();
771         (void) add_action(LNOT);
772     } else if (equals(c_token, "~")) {
773         c_token++;
774         parse_unary_expression();
775         (void) add_action(BNOT);
776     } else if (equals(c_token, "-")) {
777         c_token++;
778         parse_unary_expression();
779         (void) add_action(UMINUS);
780     } else if (equals(c_token, "+")) {  /* unary + is no-op */
781         c_token++;
782         parse_unary_expression();
783     } else
784         parse_primary_expression();
785 }
786
787 /* find or add value and return pointer */
788 struct udvt_entry *
789 add_udv(int t_num)
790 {
791     char varname[MAX_ID_LEN+1];
792     copy_str(varname, t_num, MAX_ID_LEN);
793     return add_udv_by_name(varname);
794 }
795
796
797 /* find or add function at index <t_num>, and return pointer */
798 struct udft_entry *
799 add_udf(int t_num)
800 {
801     struct udft_entry **udf_ptr = &first_udf;
802
803     int i;
804     while (*udf_ptr) {
805         if (equals(t_num, (*udf_ptr)->udf_name))
806             return (*udf_ptr);
807         udf_ptr = &((*udf_ptr)->next_udf);
808     }
809
810     /* get here => not found. udf_ptr points at first_udf or
811      * next_udf field of last udf
812      */
813
814     if (is_builtin_function(t_num))
815         int_warn(t_num, "Warning : udf shadowed by built-in function of the same name");
816
817     /* create and return a new udf slot */
818
819     *udf_ptr = (struct udft_entry *)
820         gp_alloc(sizeof(struct udft_entry), "function");
821     (*udf_ptr)->next_udf = (struct udft_entry *) NULL;
822     (*udf_ptr)->definition = NULL;
823     (*udf_ptr)->at = NULL;
824     (*udf_ptr)->udf_name = gp_alloc (token_len(t_num)+1, "user func");
825     copy_str((*udf_ptr)->udf_name, t_num, token_len(t_num)+1);
826     for (i = 0; i < MAX_NUM_VAR; i++)
827         (void) Ginteger(&((*udf_ptr)->dummy_values[i]), 0);
828     return (*udf_ptr);
829 }
830
831 /* return standard function index or 0 */
832 static int
833 is_builtin_function(int t_num)
834 {
835     int i;
836
837     for (i = (int) SF_START; ft[i].f_name != NULL; i++) {
838         if (equals(t_num, ft[i].f_name))
839             return (i);
840     }
841     return (0);
842 }
843
844 void
845 cleanup_udvlist()
846 {
847     struct udvt_entry *udv_ptr = first_udv;
848     struct udvt_entry *udv_dead;
849
850     while (udv_ptr->next_udv) {
851         if (udv_ptr->next_udv->udv_undef) {
852             udv_dead = udv_ptr->next_udv;
853             udv_ptr->next_udv = udv_dead->next_udv;
854             FPRINTF((stderr,"cleanup_udvlist: deleting %s\n",udv_dead->udv_name));
855             free(udv_dead->udv_name);
856             free(udv_dead);
857         } else
858             udv_ptr = udv_ptr->next_udv;
859     }
860 }