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