Eliminated global variable current_dataset.
[pspp-builds.git] / src / language / lexer / variable-parser.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21
22 #include <language/lexer/variable-parser.h>
23
24 #include <ctype.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27
28 #include "lexer.h"
29 #include <data/dictionary.h>
30 #include <data/procedure.h>
31 #include <data/variable.h>
32 #include <libpspp/alloc.h>
33 #include <libpspp/bit-vector.h>
34 #include <libpspp/hash.h>
35 #include <libpspp/message.h>
36 #include <libpspp/misc.h>
37 #include <libpspp/pool.h>
38 #include <libpspp/str.h>
39
40 #include "gettext.h"
41 #define _(msgid) gettext (msgid)
42
43 /* Parses a name as a variable within VS.  Sets *IDX to the
44    variable's index and returns true if successful.  On failure
45    emits an error message and returns false. */
46 static bool
47 parse_vs_variable_idx (const struct var_set *vs, size_t *idx)
48 {
49   assert (idx != NULL);
50   
51   if (token != T_ID)
52     {
53       lex_error (_("expecting variable name"));
54       return false;
55     }
56   else if (var_set_lookup_var_idx (vs, tokid, idx)) 
57     {
58       lex_get ();
59       return true;
60     }
61   else 
62     {
63       msg (SE, _("%s is not a variable name."), tokid);
64       return false;
65     }
66 }
67
68 /* Parses a name as a variable within VS and returns the variable
69    if successful.  On failure emits an error message and returns
70    a null pointer. */
71 static struct variable *
72 parse_vs_variable (const struct var_set *vs)
73 {
74   size_t idx;
75   return parse_vs_variable_idx (vs, &idx) ? var_set_get_var (vs, idx) : NULL;
76 }
77
78 /* Parses a variable name in dictionary D and returns the
79    variable if successful.  On failure emits an error message and
80    returns a null pointer. */
81 struct variable *
82 parse_variable (const struct dictionary *d) 
83 {
84   struct var_set *vs = var_set_create_from_dict (d);
85   struct variable *var = parse_vs_variable (vs);
86   var_set_destroy (vs);
87   return var;
88 }
89
90 /* Parses a set of variables from dictionary D given options
91    OPTS.  Resulting list of variables stored in *VAR and the
92    number of variables into *CNT.  Returns true only if
93    successful. */
94 bool
95 parse_variables (const struct dictionary *d, struct variable ***var,
96                  size_t *cnt, int opts) 
97 {
98   struct var_set *vs;
99   int success;
100
101   assert (d != NULL);
102   assert (var != NULL);
103   assert (cnt != NULL);
104
105   vs = var_set_create_from_dict (d);
106   success = parse_var_set_vars (vs, var, cnt, opts);
107   if ( success == 0 )
108      free ( *var ) ;
109   var_set_destroy (vs);
110   return success;
111 }
112
113 /* Parses a set of variables from dictionary D given options
114    OPTS.  Resulting list of variables stored in *VARS and the
115    number of variables into *VAR_CNT.  Returns true only if
116    successful.  Same behavior as parse_variables, except that all
117    allocations are taken from the given POOL. */
118 bool
119 parse_variables_pool (struct pool *pool, const struct dictionary *dict,
120                       struct variable ***vars, size_t *var_cnt, int opts) 
121 {
122   int retval;
123
124   /* PV_APPEND is unsafe because parse_variables would free the
125      existing names on failure, but those names are presumably
126      already in the pool, which would attempt to re-free it
127      later. */
128   assert (!(opts & PV_APPEND));
129   
130   retval = parse_variables (dict, vars, var_cnt, opts);
131   if (retval)
132     pool_register (pool, free, *vars);
133   return retval;
134 }
135
136 /* Parses a variable name from VS.  If successful, sets *IDX to
137    the variable's index in VS, *CLASS to the variable's
138    dictionary class, and returns true.  Returns false on
139    failure. */
140 static bool
141 parse_var_idx_class (const struct var_set *vs, size_t *idx,
142                      enum dict_class *class)
143 {
144   if (!parse_vs_variable_idx (vs, idx))
145     return false;
146
147   *class = dict_class_from_id (var_set_get_var (vs, *idx)->name);
148   return true;
149 }
150
151 /* Add the variable from VS with index IDX to the list of
152    variables V that has *NV elements and room for *MV.
153    Uses and updates INCLUDED to avoid duplicates if indicated by
154    PV_OPTS, which also affects what variables are allowed in
155    appropriate ways. */
156 static void
157 add_variable (struct variable ***v, size_t *nv, size_t *mv,
158               char *included, int pv_opts,
159               const struct var_set *vs, size_t idx)
160 {
161   struct variable *add = var_set_get_var (vs, idx);
162
163   if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC) 
164     msg (SW, _("%s is not a numeric variable.  It will not be "
165                "included in the variable list."), add->name);
166   else if ((pv_opts & PV_STRING) && add->type != ALPHA) 
167     msg (SE, _("%s is not a string variable.  It will not be "
168                "included in the variable list."), add->name);
169   else if ((pv_opts & PV_NO_SCRATCH)
170            && dict_class_from_id (add->name) == DC_SCRATCH)
171     msg (SE, _("Scratch variables (such as %s) are not allowed "
172                "here."), add->name);
173   else if ((pv_opts & PV_SAME_TYPE) && *nv && add->type != (*v)[0]->type) 
174     msg (SE, _("%s and %s are not the same type.  All variables in "
175                "this variable list must be of the same type.  %s "
176                "will be omitted from list."),
177          (*v)[0]->name, add->name, add->name);
178   else if ((pv_opts & PV_NO_DUPLICATE) && included[idx]) 
179     msg (SE, _("Variable %s appears twice in variable list."), add->name);
180   else if ((pv_opts & PV_DUPLICATE) || !included[idx])
181     {
182       if (*nv >= *mv)
183         {
184           *mv = 2 * (*nv + 1);
185           *v = xnrealloc (*v, *mv, sizeof **v);
186         }
187       (*v)[(*nv)++] = add;
188       if (included != NULL)
189         included[idx] = 1;
190     }
191 }
192
193 /* Adds the variables in VS with indexes FIRST_IDX through
194    LAST_IDX, inclusive, to the list of variables V that has *NV
195    elements and room for *MV.  Uses and updates INCLUDED to avoid
196    duplicates if indicated by PV_OPTS, which also affects what
197    variables are allowed in appropriate ways. */
198 static void
199 add_variables (struct variable ***v, size_t *nv, size_t *mv, char *included,
200                int pv_opts,
201                const struct var_set *vs, int first_idx, int last_idx,
202                enum dict_class class) 
203 {
204   size_t i;
205   
206   for (i = first_idx; i <= last_idx; i++)
207     if (dict_class_from_id (var_set_get_var (vs, i)->name) == class)
208       add_variable (v, nv, mv, included, pv_opts, vs, i);
209 }
210
211 /* Note that if parse_variables() returns false, *v is free()'d.
212    Conversely, if parse_variables() returns true, then *nv is
213    nonzero and *v is non-NULL. */
214 bool
215 parse_var_set_vars (const struct var_set *vs, 
216                     struct variable ***v, size_t *nv,
217                     int pv_opts)
218 {
219   size_t mv;
220   char *included;
221
222   assert (vs != NULL);
223   assert (v != NULL);
224   assert (nv != NULL);
225
226   /* At most one of PV_NUMERIC, PV_STRING, PV_SAME_TYPE may be
227      specified. */
228   assert ((((pv_opts & PV_NUMERIC) != 0)
229            + ((pv_opts & PV_STRING) != 0)
230            + ((pv_opts & PV_SAME_TYPE) != 0)) <= 1);
231
232   /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */
233   assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE));
234
235   if (!(pv_opts & PV_APPEND))
236     {
237       *v = NULL;
238       *nv = 0;
239       mv = 0;
240     }
241   else
242     mv = *nv;
243
244   if (!(pv_opts & PV_DUPLICATE))
245     {
246       size_t i;
247       
248       included = xcalloc (var_set_get_cnt (vs), sizeof *included);
249       for (i = 0; i < *nv; i++)
250         included[(*v)[i]->index] = 1;
251     }
252   else
253     included = NULL;
254
255   do
256     {
257       if (lex_match (T_ALL))
258         add_variables (v, nv, &mv, included, pv_opts,
259                        vs, 0, var_set_get_cnt (vs) - 1, DC_ORDINARY);
260       else 
261         {
262           enum dict_class class;
263           size_t first_idx;
264
265           if (!parse_var_idx_class (vs, &first_idx, &class))
266             goto fail;
267
268           if (!lex_match (T_TO))
269             add_variable (v, nv, &mv, included, pv_opts, vs, first_idx);
270           else 
271             {
272               size_t last_idx;
273               enum dict_class last_class;
274               struct variable *first_var, *last_var;
275
276               if (!parse_var_idx_class (vs, &last_idx, &last_class))
277                 goto fail;
278
279               first_var = var_set_get_var (vs, first_idx);
280               last_var = var_set_get_var (vs, last_idx);
281
282               if (last_idx < first_idx)
283                 {
284                   msg (SE, _("%s TO %s is not valid syntax since %s "
285                              "precedes %s in the dictionary."),
286                        first_var->name, last_var->name,
287                        first_var->name, last_var->name);
288                   goto fail;
289                 }
290
291               if (class != last_class)
292                 {
293                   msg (SE, _("When using the TO keyword to specify several "
294                              "variables, both variables must be from "
295                              "the same variable dictionaries, of either "
296                              "ordinary, scratch, or system variables.  "
297                              "%s is a %s variable, whereas %s is %s."),
298                        first_var->name, dict_class_to_name (class),
299                        last_var->name, dict_class_to_name (last_class));
300                   goto fail;
301                 }
302
303               add_variables (v, nv, &mv, included, pv_opts,
304                              vs, first_idx, last_idx, class);
305             } 
306         }
307
308       if (pv_opts & PV_SINGLE)
309         break;
310       lex_match (',');
311     }
312   while (token == T_ALL
313          || (token == T_ID && var_set_lookup_var (vs, tokid) != NULL));
314   
315   if (*nv == 0)
316     goto fail;
317
318   free (included);
319   return 1;
320
321 fail:
322   free (included);
323   free (*v);
324   *v = NULL;
325   *nv = 0;
326   return 0;
327 }
328
329 /* Extracts a numeric suffix from variable name S, copying it
330    into string R.  Sets *D to the length of R and *N to its
331    value. */
332 static int
333 extract_num (char *s, char *r, int *n, int *d)
334 {
335   char *cp;
336
337   /* Find first digit. */
338   cp = s + strlen (s) - 1;
339   while (isdigit ((unsigned char) *cp) && cp > s)
340     cp--;
341   cp++;
342
343   /* Extract root. */
344   strncpy (r, s, cp - s);
345   r[cp - s] = 0;
346
347   /* Count initial zeros. */
348   *n = *d = 0;
349   while (*cp == '0')
350     {
351       (*d)++;
352       cp++;
353     }
354
355   /* Extract value. */
356   while (isdigit ((unsigned char) *cp))
357     {
358       (*d)++;
359       *n = (*n * 10) + (*cp - '0');
360       cp++;
361     }
362
363   /* Sanity check. */
364   if (*n == 0 && *d == 0)
365     {
366       msg (SE, _("incorrect use of TO convention"));
367       return 0;
368     }
369   return 1;
370 }
371
372 /* Parses a list of variable names according to the DATA LIST version
373    of the TO convention.  */
374 bool
375 parse_DATA_LIST_vars (char ***names, size_t *nnames, int pv_opts)
376 {
377   int n1, n2;
378   int d1, d2;
379   int n;
380   size_t nvar, mvar;
381   char name1[LONG_NAME_LEN + 1], name2[LONG_NAME_LEN + 1];
382   char root1[LONG_NAME_LEN + 1], root2[LONG_NAME_LEN + 1];
383   int success = 0;
384
385   assert (names != NULL);
386   assert (nnames != NULL);
387   assert ((pv_opts & ~(PV_APPEND | PV_SINGLE
388                        | PV_NO_SCRATCH | PV_NO_DUPLICATE)) == 0);
389   /* FIXME: PV_NO_DUPLICATE is not implemented. */
390
391   if (pv_opts & PV_APPEND)
392     nvar = mvar = *nnames;
393   else
394     {
395       nvar = mvar = 0;
396       *names = NULL;
397     }
398
399   do
400     {
401       if (token != T_ID)
402         {
403           lex_error ("expecting variable name");
404           goto fail;
405         }
406       if (dict_class_from_id (tokid) == DC_SCRATCH
407           && (pv_opts & PV_NO_SCRATCH))
408         {
409           msg (SE, _("Scratch variables not allowed here."));
410           goto fail;
411         }
412       strcpy (name1, tokid);
413       lex_get ();
414       if (token == T_TO)
415         {
416           lex_get ();
417           if (token != T_ID)
418             {
419               lex_error ("expecting variable name");
420               goto fail;
421             }
422           strcpy (name2, tokid);
423           lex_get ();
424
425           if (!extract_num (name1, root1, &n1, &d1)
426               || !extract_num (name2, root2, &n2, &d2))
427             goto fail;
428
429           if (strcasecmp (root1, root2))
430             {
431               msg (SE, _("Prefixes don't match in use of TO convention."));
432               goto fail;
433             }
434           if (n1 > n2)
435             {
436               msg (SE, _("Bad bounds in use of TO convention."));
437               goto fail;
438             }
439           if (d2 > d1)
440             d2 = d1;
441
442           if (mvar < nvar + (n2 - n1 + 1))
443             {
444               mvar += ROUND_UP (n2 - n1 + 1, 16);
445               *names = xnrealloc (*names, mvar, sizeof **names);
446             }
447
448           for (n = n1; n <= n2; n++)
449             {
450               char name[LONG_NAME_LEN + 1];
451               sprintf (name, "%s%0*d", root1, d1, n);
452               (*names)[nvar] = xstrdup (name);
453               nvar++;
454             }
455         }
456       else
457         {
458           if (nvar >= mvar)
459             {
460               mvar += 16;
461               *names = xnrealloc (*names, mvar, sizeof **names);
462             }
463           (*names)[nvar++] = xstrdup (name1);
464         }
465
466       lex_match (',');
467
468       if (pv_opts & PV_SINGLE)
469         break;
470     }
471   while (token == T_ID);
472   success = 1;
473
474 fail:
475   *nnames = nvar;
476   if (!success)
477     {
478       int i;
479       for (i = 0; i < nvar; i++)
480         free ((*names)[i]);
481       free (*names);
482       *names = NULL;
483       *nnames = 0;
484     }
485   return success;
486 }
487
488 /* Registers each of the NAMES[0...NNAMES - 1] in POOL, as well
489    as NAMES itself. */
490 static void
491 register_vars_pool (struct pool *pool, char **names, size_t nnames)
492 {
493   size_t i;
494
495   for (i = 0; i < nnames; i++)
496     pool_register (pool, free, names[i]);
497   pool_register (pool, free, names);
498 }
499
500 /* Parses a list of variable names according to the DATA LIST
501    version of the TO convention.  Same args as
502    parse_DATA_LIST_vars(), except that all allocations are taken
503    from the given POOL. */
504 bool
505 parse_DATA_LIST_vars_pool (struct pool *pool,
506                            char ***names, size_t *nnames, int pv_opts)
507 {
508   int retval;
509
510   /* PV_APPEND is unsafe because parse_DATA_LIST_vars would free
511      the existing names on failure, but those names are
512      presumably already in the pool, which would attempt to
513      re-free it later. */
514   assert (!(pv_opts & PV_APPEND));
515   
516   retval = parse_DATA_LIST_vars (names, nnames, pv_opts);
517   if (retval)
518     register_vars_pool (pool, *names, *nnames);
519   return retval;
520 }
521
522 /* Parses a list of variables where some of the variables may be
523    existing and the rest are to be created.  Same args as
524    parse_DATA_LIST_vars(). */
525 bool
526 parse_mixed_vars (const struct dictionary *dict, 
527                   char ***names, size_t *nnames, int pv_opts)
528 {
529   size_t i;
530
531   assert (names != NULL);
532   assert (nnames != NULL);
533   assert ((pv_opts & ~PV_APPEND) == 0);
534
535   if (!(pv_opts & PV_APPEND))
536     {
537       *names = NULL;
538       *nnames = 0;
539     }
540   while (token == T_ID || token == T_ALL)
541     {
542       if (token == T_ALL || dict_lookup_var (dict, tokid) != NULL)
543         {
544           struct variable **v;
545           size_t nv;
546
547           if (!parse_variables (dict, &v, &nv, PV_NONE))
548             goto fail;
549           *names = xnrealloc (*names, *nnames + nv, sizeof **names);
550           for (i = 0; i < nv; i++)
551             (*names)[*nnames + i] = xstrdup (v[i]->name);
552           free (v);
553           *nnames += nv;
554         }
555       else if (!parse_DATA_LIST_vars (names, nnames, PV_APPEND))
556         goto fail;
557     }
558   return 1;
559
560 fail:
561   for (i = 0; i < *nnames; i++)
562     free ((*names)[i]);
563   free (*names);
564   *names = NULL;
565   *nnames = 0;
566   return 0;
567 }
568
569 /* Parses a list of variables where some of the variables may be
570    existing and the rest are to be created.  Same args as
571    parse_mixed_vars(), except that all allocations are taken
572    from the given POOL. */
573 bool
574 parse_mixed_vars_pool (const struct dictionary *dict, struct pool *pool,
575                        char ***names, size_t *nnames, int pv_opts)
576 {
577   int retval;
578
579   /* PV_APPEND is unsafe because parse_mixed_vars_pool would free
580      the existing names on failure, but those names are
581      presumably already in the pool, which would attempt to
582      re-free it later. */
583   assert (!(pv_opts & PV_APPEND));
584
585   retval = parse_mixed_vars (dict, names, nnames, pv_opts);
586   if (retval)
587     register_vars_pool (pool, *names, *nnames);
588   return retval;
589 }
590 \f
591 /* A set of variables. */
592 struct var_set 
593   {
594     size_t (*get_cnt) (const struct var_set *);
595     struct variable *(*get_var) (const struct var_set *, size_t idx);
596     bool (*lookup_var_idx) (const struct var_set *, const char *, size_t *);
597     void (*destroy) (struct var_set *);
598     void *aux;
599   };
600
601 /* Returns the number of variables in VS. */
602 size_t
603 var_set_get_cnt (const struct var_set *vs) 
604 {
605   assert (vs != NULL);
606
607   return vs->get_cnt (vs);
608 }
609
610 /* Return variable with index IDX in VS.
611    IDX must be less than the number of variables in VS. */
612 struct variable *
613 var_set_get_var (const struct var_set *vs, size_t idx) 
614 {
615   assert (vs != NULL);
616   assert (idx < var_set_get_cnt (vs));
617
618   return vs->get_var (vs, idx);
619 }
620
621 /* Returns the variable in VS named NAME, or a null pointer if VS
622    contains no variable with that name. */
623 struct variable *
624 var_set_lookup_var (const struct var_set *vs, const char *name) 
625 {
626   size_t idx;
627   return (var_set_lookup_var_idx (vs, name, &idx)
628           ? var_set_get_var (vs, idx)
629           : NULL);
630 }
631
632 /* If VS contains a variable named NAME, sets *IDX to its index
633    and returns true.  Otherwise, returns false. */
634 bool
635 var_set_lookup_var_idx (const struct var_set *vs, const char *name,
636                         size_t *idx)
637 {
638   assert (vs != NULL);
639   assert (name != NULL);
640   assert (strlen (name) <= LONG_NAME_LEN);
641
642   return vs->lookup_var_idx (vs, name, idx);
643 }
644
645 /* Destroys VS. */
646 void
647 var_set_destroy (struct var_set *vs) 
648 {
649   if (vs != NULL)
650     vs->destroy (vs);
651 }
652 \f
653 /* Returns the number of variables in VS. */
654 static size_t
655 dict_var_set_get_cnt (const struct var_set *vs) 
656 {
657   struct dictionary *d = vs->aux;
658
659   return dict_get_var_cnt (d);
660 }
661
662 /* Return variable with index IDX in VS.
663    IDX must be less than the number of variables in VS. */
664 static struct variable *
665 dict_var_set_get_var (const struct var_set *vs, size_t idx) 
666 {
667   struct dictionary *d = vs->aux;
668
669   return dict_get_var (d, idx);
670 }
671
672 /* If VS contains a variable named NAME, sets *IDX to its index
673    and returns true.  Otherwise, returns false. */
674 static bool
675 dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
676                              size_t *idx) 
677 {
678   struct dictionary *d = vs->aux;
679   struct variable *v = dict_lookup_var (d, name);
680   if (v != NULL) 
681     {
682       *idx = v->index;
683       return true;
684     }
685   else
686     return false;
687 }
688
689 /* Destroys VS. */
690 static void
691 dict_var_set_destroy (struct var_set *vs) 
692 {
693   free (vs);
694 }
695
696 /* Returns a variable set based on D. */
697 struct var_set *
698 var_set_create_from_dict (const struct dictionary *d) 
699 {
700   struct var_set *vs = xmalloc (sizeof *vs);
701   vs->get_cnt = dict_var_set_get_cnt;
702   vs->get_var = dict_var_set_get_var;
703   vs->lookup_var_idx = dict_var_set_lookup_var_idx;
704   vs->destroy = dict_var_set_destroy;
705   vs->aux = (void *) d;
706   return vs;
707 }
708 \f
709 /* A variable set based on an array. */
710 struct array_var_set 
711   {
712     struct variable *const *var;/* Array of variables. */
713     size_t var_cnt;             /* Number of elements in var. */
714     struct hsh_table *name_tab; /* Hash from variable names to variables. */
715   };
716
717 /* Returns the number of variables in VS. */
718 static size_t
719 array_var_set_get_cnt (const struct var_set *vs) 
720 {
721   struct array_var_set *avs = vs->aux;
722
723   return avs->var_cnt;
724 }
725
726 /* Return variable with index IDX in VS.
727    IDX must be less than the number of variables in VS. */
728 static struct variable *
729 array_var_set_get_var (const struct var_set *vs, size_t idx) 
730 {
731   struct array_var_set *avs = vs->aux;
732
733   return (struct variable *) avs->var[idx];
734 }
735
736 /* If VS contains a variable named NAME, sets *IDX to its index
737    and returns true.  Otherwise, returns false. */
738 static bool
739 array_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
740                               size_t *idx) 
741 {
742   struct array_var_set *avs = vs->aux;
743   struct variable v, *vp, *const *vpp;
744
745   strcpy (v.name, name);
746   vp = &v;
747   vpp = hsh_find (avs->name_tab, &vp);
748   if (vpp != NULL) 
749     {
750       *idx = vpp - avs->var;
751       return true;
752     }
753   else
754     return false;
755 }
756
757 /* Destroys VS. */
758 static void
759 array_var_set_destroy (struct var_set *vs) 
760 {
761   struct array_var_set *avs = vs->aux;
762
763   hsh_destroy (avs->name_tab);
764   free (avs);
765   free (vs);
766 }
767
768 /* Returns a variable set based on the VAR_CNT variables in
769    VAR. */
770 struct var_set *
771 var_set_create_from_array (struct variable *const *var, size_t var_cnt) 
772 {
773   struct var_set *vs;
774   struct array_var_set *avs;
775   size_t i;
776
777   vs = xmalloc (sizeof *vs);
778   vs->get_cnt = array_var_set_get_cnt;
779   vs->get_var = array_var_set_get_var;
780   vs->lookup_var_idx = array_var_set_lookup_var_idx;
781   vs->destroy = array_var_set_destroy;
782   vs->aux = avs = xmalloc (sizeof *avs);
783   avs->var = var;
784   avs->var_cnt = var_cnt;
785   avs->name_tab = hsh_create (2 * var_cnt,
786                               compare_var_ptr_names, hash_var_ptr_name, NULL,
787                               NULL);
788   for (i = 0; i < var_cnt; i++)
789     if (hsh_insert (avs->name_tab, (void *) &var[i]) != NULL) 
790       {
791         var_set_destroy (vs);
792         return NULL;
793       }
794   
795   return vs;
796 }