Move var_set and variable parsing declarations into new header.
[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_dict_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 variable name in default_dict and returns the
91    variable if successful.  On failure emits an error message and
92    returns a null pointer. */
93 struct variable *
94 parse_variable (void)
95 {
96   return parse_dict_variable (default_dict);
97 }
98
99
100 /* Parses a set of variables from dictionary D given options
101    OPTS.  Resulting list of variables stored in *VAR and the
102    number of variables into *CNT.  Returns nonzero only if
103    successful. */
104 int
105 parse_variables (const struct dictionary *d, struct variable ***var,
106                  size_t *cnt, int opts) 
107 {
108   struct var_set *vs;
109   int success;
110
111   assert (d != NULL);
112   assert (var != NULL);
113   assert (cnt != NULL);
114
115   vs = var_set_create_from_dict (d);
116   success = parse_var_set_vars (vs, var, cnt, opts);
117   if ( success == 0 )
118      free ( *var ) ;
119   var_set_destroy (vs);
120   return success;
121 }
122
123 /* Parses a variable name from VS.  If successful, sets *IDX to
124    the variable's index in VS, *CLASS to the variable's
125    dictionary class, and returns nonzero.  Returns zero on
126    failure. */
127 static int
128 parse_var_idx_class (const struct var_set *vs, size_t *idx,
129                      enum dict_class *class)
130 {
131   if (!parse_vs_variable_idx (vs, idx))
132     return 0;
133
134   *class = dict_class_from_id (var_set_get_var (vs, *idx)->name);
135   return 1;
136 }
137
138 /* Add the variable from VS with index IDX to the list of
139    variables V that has *NV elements and room for *MV.
140    Uses and updates INCLUDED to avoid duplicates if indicated by
141    PV_OPTS, which also affects what variables are allowed in
142    appropriate ways. */
143 static void
144 add_variable (struct variable ***v, size_t *nv, size_t *mv,
145               char *included, int pv_opts,
146               const struct var_set *vs, size_t idx)
147 {
148   struct variable *add = var_set_get_var (vs, idx);
149
150   if ((pv_opts & PV_NUMERIC) && add->type != NUMERIC) 
151     msg (SW, _("%s is not a numeric variable.  It will not be "
152                "included in the variable list."), add->name);
153   else if ((pv_opts & PV_STRING) && add->type != ALPHA) 
154     msg (SE, _("%s is not a string variable.  It will not be "
155                "included in the variable list."), add->name);
156   else if ((pv_opts & PV_NO_SCRATCH)
157            && dict_class_from_id (add->name) == DC_SCRATCH)
158     msg (SE, _("Scratch variables (such as %s) are not allowed "
159                "here."), add->name);
160   else if ((pv_opts & PV_SAME_TYPE) && *nv && add->type != (*v)[0]->type) 
161     msg (SE, _("%s and %s are not the same type.  All variables in "
162                "this variable list must be of the same type.  %s "
163                "will be omitted from list."),
164          (*v)[0]->name, add->name, add->name);
165   else if ((pv_opts & PV_NO_DUPLICATE) && included[idx]) 
166     msg (SE, _("Variable %s appears twice in variable list."), add->name);
167   else 
168     {
169       if (*nv >= *mv)
170         {
171           *mv = 2 * (*nv + 1);
172           *v = xnrealloc (*v, *mv, sizeof **v);
173         }
174
175       if ((pv_opts & PV_DUPLICATE) || !included[idx])
176         {
177           (*v)[(*nv)++] = add;
178           if (!(pv_opts & PV_DUPLICATE))
179             included[idx] = 1;
180         }
181     }
182 }
183
184 /* Adds the variables in VS with indexes FIRST_IDX through
185    LAST_IDX, inclusive, to the list of variables V that has *NV
186    elements and room for *MV.  Uses and updates INCLUDED to avoid
187    duplicates if indicated by PV_OPTS, which also affects what
188    variables are allowed in appropriate ways. */
189 static void
190 add_variables (struct variable ***v, size_t *nv, size_t *mv, char *included,
191                int pv_opts,
192                const struct var_set *vs, int first_idx, int last_idx,
193                enum dict_class class) 
194 {
195   size_t i;
196   
197   for (i = first_idx; i <= last_idx; i++)
198     if (dict_class_from_id (var_set_get_var (vs, i)->name) == class)
199       add_variable (v, nv, mv, included, pv_opts, vs, i);
200 }
201
202 /* Note that if parse_variables() returns 0, *v is free()'d.
203    Conversely, if parse_variables() returns non-zero, then *nv is
204    nonzero and *v is non-NULL. */
205 int
206 parse_var_set_vars (const struct var_set *vs, 
207                     struct variable ***v, size_t *nv,
208                     int pv_opts)
209 {
210   size_t mv;
211   char *included;
212
213   assert (vs != NULL);
214   assert (v != NULL);
215   assert (nv != NULL);
216
217   /* At most one of PV_NUMERIC, PV_STRING, PV_SAME_TYPE may be
218      specified. */
219   assert ((((pv_opts & PV_NUMERIC) != 0)
220            + ((pv_opts & PV_STRING) != 0)
221            + ((pv_opts & PV_SAME_TYPE) != 0)) <= 1);
222
223   /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */
224   assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE));
225
226   if (!(pv_opts & PV_APPEND))
227     {
228       *v = NULL;
229       *nv = 0;
230       mv = 0;
231     }
232   else
233     mv = *nv;
234
235   if (!(pv_opts & PV_DUPLICATE))
236     {
237       size_t i;
238       
239       included = xcalloc (var_set_get_cnt (vs), sizeof *included);
240       for (i = 0; i < *nv; i++)
241         included[(*v)[i]->index] = 1;
242     }
243   else
244     included = NULL;
245
246   if (lex_match (T_ALL))
247     add_variables (v, nv, &mv, included, pv_opts,
248                    vs, 0, var_set_get_cnt (vs) - 1, DC_ORDINARY);
249   else 
250     {
251       do
252         {
253           enum dict_class class;
254           size_t first_idx;
255           
256           if (!parse_var_idx_class (vs, &first_idx, &class))
257             goto fail;
258
259           if (!lex_match (T_TO))
260             add_variable (v, nv, &mv, included, pv_opts, vs, first_idx);
261           else 
262             {
263               size_t last_idx;
264               enum dict_class last_class;
265               struct variable *first_var, *last_var;
266
267               if (!parse_var_idx_class (vs, &last_idx, &last_class))
268                 goto fail;
269
270               first_var = var_set_get_var (vs, first_idx);
271               last_var = var_set_get_var (vs, last_idx);
272
273               if (last_idx < first_idx)
274                 {
275                   msg (SE, _("%s TO %s is not valid syntax since %s "
276                              "precedes %s in the dictionary."),
277                        first_var->name, last_var->name,
278                        first_var->name, last_var->name);
279                   goto fail;
280                 }
281
282               if (class != last_class)
283                 {
284                   msg (SE, _("When using the TO keyword to specify several "
285                              "variables, both variables must be from "
286                              "the same variable dictionaries, of either "
287                              "ordinary, scratch, or system variables.  "
288                              "%s is a %s variable, whereas %s is %s."),
289                        first_var->name, dict_class_to_name (class),
290                        last_var->name, dict_class_to_name (last_class));
291                   goto fail;
292                 }
293
294               add_variables (v, nv, &mv, included, pv_opts,
295                              vs, first_idx, last_idx, class);
296             }
297           if (pv_opts & PV_SINGLE)
298             break;
299           lex_match (',');
300         }
301       while (token == T_ID && var_set_lookup_var (vs, tokid) != NULL);
302     }
303   
304   if (*nv == 0)
305     goto fail;
306
307   free (included);
308   return 1;
309
310 fail:
311   free (included);
312   free (*v);
313   *v = NULL;
314   *nv = 0;
315   return 0;
316 }
317
318 /* Extracts a numeric suffix from variable name S, copying it
319    into string R.  Sets *D to the length of R and *N to its
320    value. */
321 static int
322 extract_num (char *s, char *r, int *n, int *d)
323 {
324   char *cp;
325
326   /* Find first digit. */
327   cp = s + strlen (s) - 1;
328   while (isdigit ((unsigned char) *cp) && cp > s)
329     cp--;
330   cp++;
331
332   /* Extract root. */
333   strncpy (r, s, cp - s);
334   r[cp - s] = 0;
335
336   /* Count initial zeros. */
337   *n = *d = 0;
338   while (*cp == '0')
339     {
340       (*d)++;
341       cp++;
342     }
343
344   /* Extract value. */
345   while (isdigit ((unsigned char) *cp))
346     {
347       (*d)++;
348       *n = (*n * 10) + (*cp - '0');
349       cp++;
350     }
351
352   /* Sanity check. */
353   if (*n == 0 && *d == 0)
354     {
355       msg (SE, _("incorrect use of TO convention"));
356       return 0;
357     }
358   return 1;
359 }
360
361 /* Parses a list of variable names according to the DATA LIST version
362    of the TO convention.  */
363 int
364 parse_DATA_LIST_vars (char ***names, size_t *nnames, int pv_opts)
365 {
366   int n1, n2;
367   int d1, d2;
368   int n;
369   size_t nvar, mvar;
370   char name1[LONG_NAME_LEN + 1], name2[LONG_NAME_LEN + 1];
371   char root1[LONG_NAME_LEN + 1], root2[LONG_NAME_LEN + 1];
372   int success = 0;
373
374   assert (names != NULL);
375   assert (nnames != NULL);
376   assert ((pv_opts & ~(PV_APPEND | PV_SINGLE
377                        | PV_NO_SCRATCH | PV_NO_DUPLICATE)) == 0);
378   /* FIXME: PV_NO_DUPLICATE is not implemented. */
379
380   if (pv_opts & PV_APPEND)
381     nvar = mvar = *nnames;
382   else
383     {
384       nvar = mvar = 0;
385       *names = NULL;
386     }
387
388   do
389     {
390       if (token != T_ID)
391         {
392           lex_error ("expecting variable name");
393           goto fail;
394         }
395       if (dict_class_from_id (tokid) == DC_SCRATCH
396           && (pv_opts & PV_NO_SCRATCH))
397         {
398           msg (SE, _("Scratch variables not allowed here."));
399           goto fail;
400         }
401       strcpy (name1, tokid);
402       lex_get ();
403       if (token == T_TO)
404         {
405           lex_get ();
406           if (token != T_ID)
407             {
408               lex_error ("expecting variable name");
409               goto fail;
410             }
411           strcpy (name2, tokid);
412           lex_get ();
413
414           if (!extract_num (name1, root1, &n1, &d1)
415               || !extract_num (name2, root2, &n2, &d2))
416             goto fail;
417
418           if (strcasecmp (root1, root2))
419             {
420               msg (SE, _("Prefixes don't match in use of TO convention."));
421               goto fail;
422             }
423           if (n1 > n2)
424             {
425               msg (SE, _("Bad bounds in use of TO convention."));
426               goto fail;
427             }
428           if (d2 > d1)
429             d2 = d1;
430
431           if (mvar < nvar + (n2 - n1 + 1))
432             {
433               mvar += ROUND_UP (n2 - n1 + 1, 16);
434               *names = xnrealloc (*names, mvar, sizeof **names);
435             }
436
437           for (n = n1; n <= n2; n++)
438             {
439               char name[LONG_NAME_LEN + 1];
440               sprintf (name, "%s%0*d", root1, d1, n);
441               (*names)[nvar] = xstrdup (name);
442               nvar++;
443             }
444         }
445       else
446         {
447           if (nvar >= mvar)
448             {
449               mvar += 16;
450               *names = xnrealloc (*names, mvar, sizeof **names);
451             }
452           (*names)[nvar++] = xstrdup (name1);
453         }
454
455       lex_match (',');
456
457       if (pv_opts & PV_SINGLE)
458         break;
459     }
460   while (token == T_ID);
461   success = 1;
462
463 fail:
464   *nnames = nvar;
465   if (!success)
466     {
467       int i;
468       for (i = 0; i < nvar; i++)
469         free ((*names)[i]);
470       free (*names);
471       *names = NULL;
472       *nnames = 0;
473     }
474   return success;
475 }
476
477 /* Parses a list of variables where some of the variables may be
478    existing and the rest are to be created.  Same args as
479    parse_DATA_LIST_vars(). */
480 int
481 parse_mixed_vars (char ***names, size_t *nnames, int pv_opts)
482 {
483   size_t i;
484
485   assert (names != NULL);
486   assert (nnames != NULL);
487   assert ((pv_opts & ~PV_APPEND) == 0);
488
489   if (!(pv_opts & PV_APPEND))
490     {
491       *names = NULL;
492       *nnames = 0;
493     }
494   while (token == T_ID || token == T_ALL)
495     {
496       if (token == T_ALL || dict_lookup_var (default_dict, tokid) != NULL)
497         {
498           struct variable **v;
499           size_t nv;
500
501           if (!parse_variables (default_dict, &v, &nv, PV_NONE))
502             goto fail;
503           *names = xnrealloc (*names, *nnames + nv, sizeof **names);
504           for (i = 0; i < nv; i++)
505             (*names)[*nnames + i] = xstrdup (v[i]->name);
506           free (v);
507           *nnames += nv;
508         }
509       else if (!parse_DATA_LIST_vars (names, nnames, PV_APPEND))
510         goto fail;
511     }
512   return 1;
513
514 fail:
515   for (i = 0; i < *nnames; i++)
516     free ((*names)[i]);
517   free (*names);
518   *names = NULL;
519   *nnames = 0;
520   return 0;
521 }
522
523 /* Parses a list of variables where some of the variables may be
524    existing and the rest are to be created.  Same args as
525    parse_DATA_LIST_vars(), except that all allocations are taken
526    from the given POOL. */
527 int
528 parse_mixed_vars_pool (struct pool *pool,
529                        char ***names, size_t *nnames, int pv_opts)
530 {
531   int retval = parse_mixed_vars (names, nnames, pv_opts);
532   if (retval)
533     {
534       size_t i;
535
536       for (i = 0; i < *nnames; i++)
537         pool_register (pool, free, (*names)[i]);
538       pool_register (pool, free, *names);
539     }
540   return retval;
541 }
542
543 \f
544 /* A set of variables. */
545 struct var_set 
546   {
547     size_t (*get_cnt) (const struct var_set *);
548     struct variable *(*get_var) (const struct var_set *, size_t idx);
549     bool (*lookup_var_idx) (const struct var_set *, const char *, size_t *);
550     void (*destroy) (struct var_set *);
551     void *aux;
552   };
553
554 /* Returns the number of variables in VS. */
555 size_t
556 var_set_get_cnt (const struct var_set *vs) 
557 {
558   assert (vs != NULL);
559
560   return vs->get_cnt (vs);
561 }
562
563 /* Return variable with index IDX in VS.
564    IDX must be less than the number of variables in VS. */
565 struct variable *
566 var_set_get_var (const struct var_set *vs, size_t idx) 
567 {
568   assert (vs != NULL);
569   assert (idx < var_set_get_cnt (vs));
570
571   return vs->get_var (vs, idx);
572 }
573
574 /* Returns the variable in VS named NAME, or a null pointer if VS
575    contains no variable with that name. */
576 struct variable *
577 var_set_lookup_var (const struct var_set *vs, const char *name) 
578 {
579   size_t idx;
580   return (var_set_lookup_var_idx (vs, name, &idx)
581           ? var_set_get_var (vs, idx)
582           : NULL);
583 }
584
585 /* If VS contains a variable named NAME, sets *IDX to its index
586    and returns true.  Otherwise, returns false. */
587 bool
588 var_set_lookup_var_idx (const struct var_set *vs, const char *name,
589                         size_t *idx)
590 {
591   assert (vs != NULL);
592   assert (name != NULL);
593   assert (strlen (name) <= LONG_NAME_LEN);
594
595   return vs->lookup_var_idx (vs, name, idx);
596 }
597
598 /* Destroys VS. */
599 void
600 var_set_destroy (struct var_set *vs) 
601 {
602   if (vs != NULL)
603     vs->destroy (vs);
604 }
605 \f
606 /* Returns the number of variables in VS. */
607 static size_t
608 dict_var_set_get_cnt (const struct var_set *vs) 
609 {
610   struct dictionary *d = vs->aux;
611
612   return dict_get_var_cnt (d);
613 }
614
615 /* Return variable with index IDX in VS.
616    IDX must be less than the number of variables in VS. */
617 static struct variable *
618 dict_var_set_get_var (const struct var_set *vs, size_t idx) 
619 {
620   struct dictionary *d = vs->aux;
621
622   return dict_get_var (d, idx);
623 }
624
625 /* If VS contains a variable named NAME, sets *IDX to its index
626    and returns true.  Otherwise, returns false. */
627 static bool
628 dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
629                              size_t *idx) 
630 {
631   struct dictionary *d = vs->aux;
632   struct variable *v = dict_lookup_var (d, name);
633   if (v != NULL) 
634     {
635       *idx = v->index;
636       return true;
637     }
638   else
639     return false;
640 }
641
642 /* Destroys VS. */
643 static void
644 dict_var_set_destroy (struct var_set *vs) 
645 {
646   free (vs);
647 }
648
649 /* Returns a variable set based on D. */
650 struct var_set *
651 var_set_create_from_dict (const struct dictionary *d) 
652 {
653   struct var_set *vs = xmalloc (sizeof *vs);
654   vs->get_cnt = dict_var_set_get_cnt;
655   vs->get_var = dict_var_set_get_var;
656   vs->lookup_var_idx = dict_var_set_lookup_var_idx;
657   vs->destroy = dict_var_set_destroy;
658   vs->aux = (void *) d;
659   return vs;
660 }
661 \f
662 /* A variable set based on an array. */
663 struct array_var_set 
664   {
665     struct variable *const *var;/* Array of variables. */
666     size_t var_cnt;             /* Number of elements in var. */
667     struct hsh_table *name_tab; /* Hash from variable names to variables. */
668   };
669
670 /* Returns the number of variables in VS. */
671 static size_t
672 array_var_set_get_cnt (const struct var_set *vs) 
673 {
674   struct array_var_set *avs = vs->aux;
675
676   return avs->var_cnt;
677 }
678
679 /* Return variable with index IDX in VS.
680    IDX must be less than the number of variables in VS. */
681 static struct variable *
682 array_var_set_get_var (const struct var_set *vs, size_t idx) 
683 {
684   struct array_var_set *avs = vs->aux;
685
686   return (struct variable *) avs->var[idx];
687 }
688
689 /* If VS contains a variable named NAME, sets *IDX to its index
690    and returns true.  Otherwise, returns false. */
691 static bool
692 array_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
693                               size_t *idx) 
694 {
695   struct array_var_set *avs = vs->aux;
696   struct variable v, *vp, *const *vpp;
697
698   strcpy (v.name, name);
699   vp = &v;
700   vpp = hsh_find (avs->name_tab, &vp);
701   if (vpp != NULL) 
702     {
703       *idx = vpp - avs->var;
704       return true;
705     }
706   else
707     return false;
708 }
709
710 /* Destroys VS. */
711 static void
712 array_var_set_destroy (struct var_set *vs) 
713 {
714   struct array_var_set *avs = vs->aux;
715
716   hsh_destroy (avs->name_tab);
717   free (avs);
718   free (vs);
719 }
720
721 /* Returns a variable set based on the VAR_CNT variables in
722    VAR. */
723 struct var_set *
724 var_set_create_from_array (struct variable *const *var, size_t var_cnt) 
725 {
726   struct var_set *vs;
727   struct array_var_set *avs;
728   size_t i;
729
730   vs = xmalloc (sizeof *vs);
731   vs->get_cnt = array_var_set_get_cnt;
732   vs->get_var = array_var_set_get_var;
733   vs->lookup_var_idx = array_var_set_lookup_var_idx;
734   vs->destroy = array_var_set_destroy;
735   vs->aux = avs = xmalloc (sizeof *avs);
736   avs->var = var;
737   avs->var_cnt = var_cnt;
738   avs->name_tab = hsh_create (2 * var_cnt,
739                               compare_var_ptr_names, hash_var_ptr_name, NULL,
740                               NULL);
741   for (i = 0; i < var_cnt; i++)
742     if (hsh_insert (avs->name_tab, (void *) &var[i]) != NULL) 
743       {
744         var_set_destroy (vs);
745         return NULL;
746       }
747   
748   return vs;
749 }