Some variables are ordinal.
[pspp] / src / language / lexer / variable-parser.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012, 2020 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "language/lexer/variable-parser.h"
20
21 #include <ctype.h>
22 #include <limits.h>
23 #include <stdbool.h>
24 #include <stdlib.h>
25
26 #include "data/dataset.h"
27 #include "data/dictionary.h"
28 #include "data/variable.h"
29 #include "language/lexer/lexer.h"
30 #include "libpspp/assertion.h"
31 #include "libpspp/cast.h"
32 #include "libpspp/hash-functions.h"
33 #include "libpspp/i18n.h"
34 #include "libpspp/hmapx.h"
35 #include "libpspp/message.h"
36 #include "libpspp/misc.h"
37 #include "libpspp/pool.h"
38 #include "libpspp/str.h"
39 #include "libpspp/stringi-set.h"
40
41 #include "math/interaction.h"
42
43 #include "gl/c-ctype.h"
44 #include "gl/xalloc.h"
45
46 #include "gettext.h"
47 #define _(msgid) gettext (msgid)
48
49 static struct variable *var_set_get_var (const struct var_set *, size_t);
50 static struct variable *var_set_lookup_var (const struct var_set *,
51                                             const char *);
52 static bool var_set_lookup_var_idx (const struct var_set *, const char *,
53                                     size_t *);
54 static bool var_set_get_names_must_be_ids (const struct var_set *);
55
56 static bool
57 is_name_token (const struct lexer *lexer, bool names_must_be_ids)
58 {
59   return (lex_token (lexer) == T_ID
60           || (!names_must_be_ids && lex_token (lexer) == T_STRING));
61 }
62
63 static bool
64 is_vs_name_token (const struct lexer *lexer, const struct var_set *vs)
65 {
66   return is_name_token (lexer, var_set_get_names_must_be_ids (vs));
67 }
68
69 static bool
70 is_dict_name_token (const struct lexer *lexer, const struct dictionary *d)
71 {
72   return is_name_token (lexer, dict_get_names_must_be_ids (d));
73 }
74
75 /* Parses a name as a variable within VS.  Sets *IDX to the
76    variable's index and returns true if successful.  On failure
77    emits an error message and returns false. */
78 static bool
79 parse_vs_variable_idx (struct lexer *lexer, const struct var_set *vs,
80                        size_t *idx)
81 {
82   assert (idx != NULL);
83
84   if (!is_vs_name_token (lexer, vs))
85     {
86       lex_error (lexer, _("expecting variable name"));
87       return false;
88     }
89   else if (var_set_lookup_var_idx (vs, lex_tokcstr (lexer), idx))
90     {
91       lex_get (lexer);
92       return true;
93     }
94   else
95     {
96       msg (SE, _("%s is not a variable name."), lex_tokcstr (lexer));
97       return false;
98     }
99 }
100
101 /* Parses a name as a variable within VS and returns the variable
102    if successful.  On failure emits an error message and returns
103    a null pointer. */
104 static struct variable *
105 parse_vs_variable (struct lexer *lexer, const struct var_set *vs)
106 {
107   size_t idx;
108   return parse_vs_variable_idx (lexer, vs, &idx) ? var_set_get_var (vs, idx) : NULL;
109 }
110
111 /* Parses a variable name in dictionary D and returns the
112    variable if successful.  On failure emits an error message and
113    returns a null pointer. */
114 struct variable *
115 parse_variable (struct lexer *lexer, const struct dictionary *d)
116 {
117   struct var_set *vs = var_set_create_from_dict (d);
118   struct variable *var = parse_vs_variable (lexer, vs);
119   var_set_destroy (vs);
120   return var;
121 }
122
123 /* Parses a set of variables from dictionary D given options
124    OPTS.  Resulting list of variables stored in *VAR and the
125    number of variables into *N.  Returns true only if
126    successful.  The dictionary D must contain at least one
127    variable.  */
128 bool
129 parse_variables (struct lexer *lexer, const struct dictionary *d,
130                  struct variable ***var,
131                  size_t *n, int opts)
132 {
133   struct var_set *vs;
134   int success;
135
136   assert (d != NULL);
137   assert (var != NULL);
138   assert (n != NULL);
139
140   vs = var_set_create_from_dict (d);
141   if (var_set_get_n (vs) == 0)
142     {
143       *n = 0;
144       var_set_destroy (vs);
145       return false;
146     }
147   success = parse_var_set_vars (lexer, vs, var, n, opts);
148   var_set_destroy (vs);
149   return success;
150 }
151
152 /* Parses a set of variables from dictionary D given options
153    OPTS.  Resulting list of variables stored in *VARS and the
154    number of variables into *N_VARS.  Returns true only if
155    successful.  Same behavior as parse_variables, except that all
156    allocations are taken from the given POOL. */
157 bool
158 parse_variables_pool (struct lexer *lexer, struct pool *pool,
159                 const struct dictionary *dict,
160                 struct variable ***vars, size_t *n_vars, int opts)
161 {
162   int retval;
163
164   /* PV_APPEND is unsafe because parse_variables would free the
165      existing names on failure, but those names are presumably
166      already in the pool, which would attempt to re-free it
167      later. */
168   assert (!(opts & PV_APPEND));
169
170   retval = parse_variables (lexer, dict, vars, n_vars, opts);
171   if (retval)
172     pool_register (pool, free, *vars);
173   return retval;
174 }
175
176 /* Parses a variable name from VS.  If successful, sets *IDX to
177    the variable's index in VS, *CLASS to the variable's
178    dictionary class, and returns true.  Returns false on
179    failure. */
180 static bool
181 parse_var_idx_class (struct lexer *lexer, const struct var_set *vs,
182                         size_t *idx,
183                         enum dict_class *class)
184 {
185   if (!parse_vs_variable_idx (lexer, vs, idx))
186     return false;
187
188   *class = dict_class_from_id (var_get_name (var_set_get_var (vs, *idx)));
189   return true;
190 }
191
192 /* Add the variable from VS with index IDX to the list of
193    variables V that has *NV elements and room for *MV.
194    Uses and updates INCLUDED to avoid duplicates if indicated by
195    PV_OPTS, which also affects what variables are allowed in
196    appropriate ways. */
197 static void
198 add_variable (struct variable ***v, size_t *nv, size_t *mv,
199               char *included, int pv_opts,
200               const struct var_set *vs, size_t idx)
201 {
202   struct variable *add = var_set_get_var (vs, idx);
203   const char *add_name = var_get_name (add);
204
205   if ((pv_opts & PV_NUMERIC) && !var_is_numeric (add))
206     msg (SW, _("%s is not a numeric variable.  It will not be "
207                "included in the variable list."), add_name);
208   else if ((pv_opts & PV_STRING) && !var_is_alpha (add))
209     msg (SE, _("%s is not a string variable.  It will not be "
210                "included in the variable list."), add_name);
211   else if ((pv_opts & PV_NO_SCRATCH)
212            && dict_class_from_id (add_name) == DC_SCRATCH)
213     msg (SE, _("Scratch variables (such as %s) are not allowed "
214                "here."), add_name);
215   else if ((pv_opts & (PV_SAME_TYPE | PV_SAME_WIDTH)) && *nv
216            && var_get_type (add) != var_get_type ((*v)[0]))
217     msg (SE, _("%s and %s are not the same type.  All variables in "
218                "this variable list must be of the same type.  %s "
219                "will be omitted from the list."),
220          var_get_name ((*v)[0]), add_name, add_name);
221   else if ((pv_opts & PV_SAME_WIDTH) && *nv
222            && var_get_width (add) != var_get_width ((*v)[0]))
223     msg (SE, _("%s and %s are string variables with different widths.  "
224                "All variables in this variable list must have the "
225                "same width.  %s will be omitted from the list."),
226          var_get_name ((*v)[0]), add_name, add_name);
227   else if ((pv_opts & PV_NO_DUPLICATE) && included && included[idx])
228     msg (SE, _("Variable %s appears twice in variable list."), add_name);
229   else if ((pv_opts & PV_DUPLICATE) || !included || !included[idx])
230     {
231       if (*nv >= *mv)
232         {
233           *mv = 2 * (*nv + 1);
234           *v = xnrealloc (*v, *mv, sizeof **v);
235         }
236       (*v)[(*nv)++] = add;
237       if (included != NULL)
238         included[idx] = 1;
239     }
240 }
241
242 /* Adds the variables in VS with indexes FIRST_IDX through
243    LAST_IDX, inclusive, to the list of variables V that has *NV
244    elements and room for *MV.  Uses and updates INCLUDED to avoid
245    duplicates if indicated by PV_OPTS, which also affects what
246    variables are allowed in appropriate ways. */
247 static void
248 add_variables (struct variable ***v, size_t *nv, size_t *mv, char *included,
249                int pv_opts,
250                const struct var_set *vs, int first_idx, int last_idx,
251                enum dict_class class)
252 {
253   size_t i;
254
255   for (i = first_idx; i <= last_idx; i++)
256     if (dict_class_from_id (var_get_name (var_set_get_var (vs, i))) == class)
257       add_variable (v, nv, mv, included, pv_opts, vs, i);
258 }
259
260 /* Note that if parse_variables() returns false, *v is free()'d.
261    Conversely, if parse_variables() returns true, then *nv is
262    nonzero and *v is non-NULL. */
263 bool
264 parse_var_set_vars (struct lexer *lexer, const struct var_set *vs,
265                     struct variable ***v, size_t *nv,
266                     int pv_opts)
267 {
268   size_t mv;
269   char *included;
270
271   assert (vs != NULL);
272   assert (v != NULL);
273   assert (nv != NULL);
274
275   /* At most one of PV_NUMERIC, PV_STRING, PV_SAME_TYPE,
276      PV_SAME_WIDTH may be specified. */
277   assert (((pv_opts & PV_NUMERIC) != 0)
278           + ((pv_opts & PV_STRING) != 0)
279           + ((pv_opts & PV_SAME_TYPE) != 0)
280           + ((pv_opts & PV_SAME_WIDTH) != 0) <= 1);
281
282   /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */
283   assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE));
284
285   if (!(pv_opts & PV_APPEND))
286     {
287       *v = NULL;
288       *nv = 0;
289       mv = 0;
290     }
291   else
292     mv = *nv;
293
294   if (!(pv_opts & PV_DUPLICATE))
295     {
296       size_t i;
297
298       included = xcalloc (var_set_get_n (vs), sizeof *included);
299       for (i = 0; i < *nv; i++)
300         {
301           size_t index;
302           if (!var_set_lookup_var_idx (vs, var_get_name ((*v)[i]), &index))
303             NOT_REACHED ();
304           included[index] = 1;
305         }
306     }
307   else
308     included = NULL;
309
310   do
311     {
312       if (lex_match (lexer, T_ALL))
313         add_variables (v, nv, &mv, included, pv_opts,
314                        vs, 0, var_set_get_n (vs) - 1, DC_ORDINARY);
315       else
316         {
317           enum dict_class class;
318           size_t first_idx;
319
320           if (!parse_var_idx_class (lexer, vs, &first_idx, &class))
321             goto fail;
322
323           if (!lex_match (lexer, T_TO))
324             add_variable (v, nv, &mv, included, pv_opts, vs, first_idx);
325           else
326             {
327               size_t last_idx;
328               enum dict_class last_class;
329               struct variable *first_var, *last_var;
330
331               if (!parse_var_idx_class (lexer, vs, &last_idx, &last_class))
332                 goto fail;
333
334               first_var = var_set_get_var (vs, first_idx);
335               last_var = var_set_get_var (vs, last_idx);
336
337               if (last_idx < first_idx)
338                 {
339                   const char *first_name = var_get_name (first_var);
340                   const char *last_name = var_get_name (last_var);
341                   msg (SE, _("%s TO %s is not valid syntax since %s "
342                              "precedes %s in the dictionary."),
343                        first_name, last_name, first_name, last_name);
344                   goto fail;
345                 }
346
347               if (class != last_class)
348                 {
349                   msg (SE, _("When using the TO keyword to specify several "
350                              "variables, both variables must be from "
351                              "the same variable dictionaries, of either "
352                              "ordinary, scratch, or system variables.  "
353                              "%s is a %s variable, whereas %s is %s."),
354                        var_get_name (first_var), dict_class_to_name (class),
355                        var_get_name (last_var),
356                        dict_class_to_name (last_class));
357                   goto fail;
358                 }
359
360               add_variables (v, nv, &mv, included, pv_opts,
361                              vs, first_idx, last_idx, class);
362             }
363         }
364
365       if (pv_opts & PV_SINGLE)
366         break;
367       lex_match (lexer, T_COMMA);
368     }
369   while (lex_token (lexer) == T_ALL
370          || (is_vs_name_token (lexer, vs)
371              && var_set_lookup_var (vs, lex_tokcstr (lexer)) != NULL));
372
373   if (*nv == 0)
374     goto fail;
375
376   free (included);
377   return 1;
378
379 fail:
380   free (included);
381   free (*v);
382   *v = NULL;
383   *nv = 0;
384   return 0;
385 }
386
387 char *
388 parse_DATA_LIST_var (struct lexer *lexer, const struct dictionary *d)
389 {
390   if (!is_dict_name_token (lexer, d))
391     {
392       lex_error (lexer, "expecting variable name");
393       return NULL;
394     }
395   if (!dict_id_is_valid (d, lex_tokcstr (lexer), true))
396     return NULL;
397
398   char *name = xstrdup (lex_tokcstr (lexer));
399   lex_get (lexer);
400   return name;
401 }
402
403 /* Attempts to break UTF-8 encoded NAME into a root (whose contents are
404    arbitrary except that it does not end in a digit) followed by an integer
405    numeric suffix.  On success, stores the value of the suffix into *NUMBERP,
406    the number of digits in the suffix into *N_DIGITSP, and returns the number
407    of bytes in the root.  On failure, returns 0. */
408 static int
409 extract_numeric_suffix (const char *name,
410                         unsigned long int *numberp, int *n_digitsp)
411 {
412   size_t root_len, n_digits;
413   size_t i;
414
415   /* Count length of root. */
416   root_len = 1;                 /* Valid identifier never starts with digit. */
417   for (i = 1; name[i] != '\0'; i++)
418     if (!c_isdigit (name[i]))
419       root_len = i + 1;
420   n_digits = i - root_len;
421
422   if (n_digits == 0)
423     {
424       msg (SE, _("`%s' cannot be used with TO because it does not end in "
425                  "a digit."), name);
426       return 0;
427     }
428
429   *numberp = strtoull (name + root_len, NULL, 10);
430   if (*numberp == ULONG_MAX)
431     {
432       msg (SE, _("Numeric suffix on `%s' is larger than supported with TO."),
433            name);
434       return 0;
435     }
436   *n_digitsp = n_digits;
437   return root_len;
438 }
439
440 static bool
441 add_var_name (char *name,
442               char ***names, size_t *n_vars, size_t *allocated_vars,
443               struct stringi_set *set, int pv_opts)
444 {
445   if (pv_opts & PV_NO_DUPLICATE && !stringi_set_insert (set, name))
446     {
447       msg (SE, _("Variable %s appears twice in variable list."),
448            name);
449       return false;
450     }
451
452   if (*n_vars >= *allocated_vars)
453     *names = x2nrealloc (*names, allocated_vars, sizeof **names);
454   (*names)[(*n_vars)++] = name;
455   return true;
456 }
457
458 /* Parses a list of variable names according to the DATA LIST version
459    of the TO convention.  */
460 bool
461 parse_DATA_LIST_vars (struct lexer *lexer, const struct dictionary *dict,
462                       char ***namesp, size_t *n_varsp, int pv_opts)
463 {
464   char **names;
465   size_t n_vars;
466   size_t allocated_vars;
467
468   struct stringi_set set;
469
470   char *name1 = NULL;
471   char *name2 = NULL;
472
473   bool ok = false;
474
475   assert ((pv_opts & ~(PV_APPEND | PV_SINGLE
476                        | PV_NO_SCRATCH | PV_NO_DUPLICATE)) == 0);
477   stringi_set_init (&set);
478
479   if (pv_opts & PV_APPEND)
480     {
481       n_vars = allocated_vars = *n_varsp;
482       names = *namesp;
483
484       if (pv_opts & PV_NO_DUPLICATE)
485         {
486           size_t i;
487
488           for (i = 0; i < n_vars; i++)
489             stringi_set_insert (&set, names[i]);
490         }
491     }
492   else
493     {
494       n_vars = allocated_vars = 0;
495       names = NULL;
496     }
497
498   do
499     {
500       name1 = parse_DATA_LIST_var (lexer, dict);
501       if (!name1)
502         goto exit;
503       if (dict_class_from_id (name1) == DC_SCRATCH && pv_opts & PV_NO_SCRATCH)
504         {
505           msg (SE, _("Scratch variables not allowed here."));
506           goto exit;
507         }
508       if (lex_match (lexer, T_TO))
509         {
510           unsigned long int num1, num2;
511           int n_digits1, n_digits2;
512           int root_len1, root_len2;
513           unsigned long int number;
514
515           name2 = parse_DATA_LIST_var (lexer, dict);
516           if (!name2)
517             goto exit;
518
519           root_len1 = extract_numeric_suffix (name1, &num1, &n_digits1);
520           if (root_len1 == 0)
521             goto exit;
522
523           root_len2 = extract_numeric_suffix (name2, &num2, &n_digits2);
524           if (root_len2 == 0)
525             goto exit;
526
527           if (root_len1 != root_len2 || memcasecmp (name1, name2, root_len1))
528             {
529               msg (SE, _("Prefixes don't match in use of TO convention."));
530               goto exit;
531             }
532           if (num1 > num2)
533             {
534               msg (SE, _("Bad bounds in use of TO convention."));
535               goto exit;
536             }
537
538           for (number = num1; number <= num2; number++)
539             {
540               char *name = xasprintf ("%.*s%0*lu",
541                                       root_len1, name1,
542                                       n_digits1, number);
543               if (!add_var_name (name, &names, &n_vars, &allocated_vars,
544                                  &set, pv_opts))
545                 {
546                   free (name);
547                   goto exit;
548                 }
549             }
550
551           free (name1);
552           name1 = NULL;
553           free (name2);
554           name2 = NULL;
555         }
556       else
557         {
558           if (!add_var_name (name1, &names, &n_vars, &allocated_vars,
559                              &set, pv_opts))
560             goto exit;
561           name1 = NULL;
562         }
563
564       lex_match (lexer, T_COMMA);
565
566       if (pv_opts & PV_SINGLE)
567         break;
568     }
569   while (lex_token (lexer) == T_ID);
570   ok = true;
571
572 exit:
573   stringi_set_destroy (&set);
574   if (ok)
575     {
576       *namesp = names;
577       *n_varsp = n_vars;
578     }
579   else
580     {
581       int i;
582       for (i = 0; i < n_vars; i++)
583         free (names[i]);
584       free (names);
585       *namesp = NULL;
586       *n_varsp = 0;
587
588       free (name1);
589       free (name2);
590     }
591   return ok;
592 }
593
594 /* Registers each of the NAMES[0...NNAMES - 1] in POOL, as well
595    as NAMES itself. */
596 static void
597 register_vars_pool (struct pool *pool, char **names, size_t nnames)
598 {
599   size_t i;
600
601   for (i = 0; i < nnames; i++)
602     pool_register (pool, free, names[i]);
603   pool_register (pool, free, names);
604 }
605
606 /* Parses a list of variable names according to the DATA LIST
607    version of the TO convention.  Same args as
608    parse_DATA_LIST_vars(), except that all allocations are taken
609    from the given POOL. */
610 bool
611 parse_DATA_LIST_vars_pool (struct lexer *lexer, const struct dictionary *dict,
612                            struct pool *pool,
613                            char ***names, size_t *nnames, int pv_opts)
614 {
615   int retval;
616
617   /* PV_APPEND is unsafe because parse_DATA_LIST_vars would free
618      the existing names on failure, but those names are
619      presumably already in the pool, which would attempt to
620      re-free it later. */
621   assert (!(pv_opts & PV_APPEND));
622
623   retval = parse_DATA_LIST_vars (lexer, dict, names, nnames, pv_opts);
624   if (retval)
625     register_vars_pool (pool, *names, *nnames);
626   return retval;
627 }
628
629 /* Parses a list of variables where some of the variables may be
630    existing and the rest are to be created.  Same args as
631    parse_DATA_LIST_vars(). */
632 bool
633 parse_mixed_vars (struct lexer *lexer, const struct dictionary *dict,
634                   char ***names, size_t *nnames, int pv_opts)
635 {
636   size_t i;
637
638   assert (names != NULL);
639   assert (nnames != NULL);
640
641   if (!(pv_opts & PV_APPEND))
642     {
643       *names = NULL;
644       *nnames = 0;
645     }
646   while (is_dict_name_token (lexer, dict) || lex_token (lexer) == T_ALL)
647     {
648       if (lex_token (lexer) == T_ALL || dict_lookup_var (dict, lex_tokcstr (lexer)) != NULL)
649         {
650           struct variable **v;
651           size_t nv;
652
653           if (!parse_variables (lexer, dict, &v, &nv, pv_opts))
654             goto fail;
655           *names = xnrealloc (*names, *nnames + nv, sizeof **names);
656           for (i = 0; i < nv; i++)
657             (*names)[*nnames + i] = xstrdup (var_get_name (v[i]));
658           free (v);
659           *nnames += nv;
660         }
661       else if (!parse_DATA_LIST_vars (lexer, dict, names, nnames, PV_APPEND | pv_opts))
662         goto fail;
663     }
664   if (*nnames == 0)
665     goto fail;
666
667   return true;
668
669 fail:
670   for (i = 0; i < *nnames; i++)
671     free ((*names)[i]);
672   free (*names);
673   *names = NULL;
674   *nnames = 0;
675   return false;
676 }
677
678 /* Parses a list of variables where some of the variables may be
679    existing and the rest are to be created.  Same args as
680    parse_mixed_vars(), except that all allocations are taken
681    from the given POOL. */
682 bool
683 parse_mixed_vars_pool (struct lexer *lexer, const struct dictionary *dict, struct pool *pool,
684                        char ***names, size_t *nnames, int pv_opts)
685 {
686   int retval;
687
688   /* PV_APPEND is unsafe because parse_mixed_vars_pool would free
689      the existing names on failure, but those names are
690      presumably already in the pool, which would attempt to
691      re-free it later. */
692   assert (!(pv_opts & PV_APPEND));
693
694   retval = parse_mixed_vars (lexer, dict, names, nnames, pv_opts);
695   if (retval)
696     register_vars_pool (pool, *names, *nnames);
697   return retval;
698 }
699 \f
700 /* Frees the N var_syntax structures in VS, as well as VS itself. */
701 void
702 var_syntax_destroy (struct var_syntax *vs, size_t n)
703 {
704   for (size_t i = 0; i < n; i++)
705     {
706       free (vs[i].first);
707       free (vs[i].last);
708     }
709   free (vs);
710 }
711
712 /* Parses syntax for variables and variable ranges from LEXER.  If successful,
713    initializes *VS to the beginning of an array of var_syntax structs and *N_VS
714    to the number of elements in the array and returns true.  On error, sets *VS
715    to NULL and *N_VS to 0 and returns false. */
716 bool
717 var_syntax_parse (struct lexer *lexer, struct var_syntax **vs, size_t *n_vs)
718 {
719   *vs = NULL;
720   *n_vs = 0;
721
722   if (lex_token (lexer) != T_ID)
723     {
724       lex_error (lexer, _("expecting variable name"));
725       goto error;
726     }
727
728   size_t allocated_vs = 0;
729   do
730     {
731       if (allocated_vs >= *n_vs)
732         *vs = x2nrealloc (*vs, &allocated_vs, sizeof **vs);
733       struct var_syntax *new = &(*vs)[(*n_vs)++];
734       *new = (struct var_syntax) { .first = ss_xstrdup (lex_tokss (lexer)) };
735       lex_get (lexer);
736
737       if (lex_match (lexer, T_TO))
738         {
739           if (lex_token (lexer) != T_ID)
740             {
741               lex_error (lexer, _("expecting variable name"));
742               goto error;
743             }
744
745           new->last = ss_xstrdup (lex_tokss (lexer));
746           lex_get (lexer);
747         }
748     }
749   while (lex_token (lexer) == T_ID);
750   return true;
751
752 error:
753   var_syntax_destroy (*vs, *n_vs);
754   *vs = NULL;
755   *n_vs = 0;
756   return false;
757 }
758
759 /* Looks up the N_VS var syntax structs in VS in DICT, translating them to an
760    array of variables.  If successful, initializes *VARS to the beginning of an
761    array of pointers to variables and *N_VARS to the length of the array and
762    returns true.  On error, sets *VARS to NULL and *N_VARS to 0.
763
764    For the moment, only honors PV_NUMERIC in OPTS. */
765 bool
766 var_syntax_evaluate (const struct var_syntax *vs, size_t n_vs,
767                      const struct dictionary *dict,
768                      struct variable ***vars, size_t *n_vars, int opts)
769 {
770   assert (!(opts & ~PV_NUMERIC));
771
772   *vars = NULL;
773   *n_vars = 0;
774
775   size_t allocated_vars = 0;
776   for (size_t i = 0; i < n_vs; i++)
777     {
778       struct variable *first = dict_lookup_var (dict, vs[i].first);
779       if (!first)
780         {
781           msg (SE, _("%s is not a variable name."), vs[i].first);
782           goto error;
783         }
784
785       struct variable *last = (vs[i].last
786                                ? dict_lookup_var (dict, vs[i].last)
787                                : first);
788       if (!last)
789         {
790           msg (SE, _("%s is not a variable name."), vs[i].last);
791           goto error;
792         }
793
794       size_t first_idx = var_get_dict_index (first);
795       size_t last_idx = var_get_dict_index (last);
796       if (last_idx < first_idx)
797         {
798           msg (SE, _("%s TO %s is not valid syntax since %s "
799                      "precedes %s in the dictionary."),
800                vs[i].first, vs[i].last,
801                vs[i].first, vs[i].last);
802           goto error;
803         }
804
805       for (size_t j = first_idx; j <= last_idx; j++)
806         {
807           struct variable *v = dict_get_var (dict, j);
808           if (opts & PV_NUMERIC && !var_is_numeric (v))
809             {
810               msg (SW, _("%s is not a numeric variable."), var_get_name (v));
811               goto error;
812             }
813
814           if (*n_vars >= allocated_vars)
815             *vars = x2nrealloc (*vars, &allocated_vars, sizeof **vars);
816           (*vars)[(*n_vars)++] = v;
817         }
818     }
819
820   return true;
821
822 error:
823   free (*vars);
824   *vars = NULL;
825   *n_vars = 0;
826   return false;
827 }
828 \f
829 /* A set of variables. */
830 struct var_set
831   {
832     bool names_must_be_ids;
833     size_t (*get_n) (const struct var_set *);
834     struct variable *(*get_var) (const struct var_set *, size_t idx);
835     bool (*lookup_var_idx) (const struct var_set *, const char *, size_t *);
836     void (*destroy) (struct var_set *);
837     void *aux;
838   };
839
840 /* Returns the number of variables in VS. */
841 size_t
842 var_set_get_n (const struct var_set *vs)
843 {
844   assert (vs != NULL);
845
846   return vs->get_n (vs);
847 }
848
849 /* Return variable with index IDX in VS.
850    IDX must be less than the number of variables in VS. */
851 static struct variable *
852 var_set_get_var (const struct var_set *vs, size_t idx)
853 {
854   assert (vs != NULL);
855   assert (idx < var_set_get_n (vs));
856
857   return vs->get_var (vs, idx);
858 }
859
860 /* Returns the variable in VS named NAME, or a null pointer if VS
861    contains no variable with that name. */
862 struct variable *
863 var_set_lookup_var (const struct var_set *vs, const char *name)
864 {
865   size_t idx;
866   return (var_set_lookup_var_idx (vs, name, &idx)
867           ? var_set_get_var (vs, idx)
868           : NULL);
869 }
870
871 /* If VS contains a variable named NAME, sets *IDX to its index
872    and returns true.  Otherwise, returns false. */
873 bool
874 var_set_lookup_var_idx (const struct var_set *vs, const char *name,
875                         size_t *idx)
876 {
877   assert (vs != NULL);
878   assert (name != NULL);
879
880   return vs->lookup_var_idx (vs, name, idx);
881 }
882
883 /* Destroys VS. */
884 void
885 var_set_destroy (struct var_set *vs)
886 {
887   if (vs != NULL)
888     vs->destroy (vs);
889 }
890
891 static bool
892 var_set_get_names_must_be_ids (const struct var_set *vs)
893 {
894   return vs->names_must_be_ids;
895 }
896 \f
897 /* Returns the number of variables in VS. */
898 static size_t
899 dict_var_set_get_n (const struct var_set *vs)
900 {
901   struct dictionary *d = vs->aux;
902
903   return dict_get_n_vars (d);
904 }
905
906 /* Return variable with index IDX in VS.
907    IDX must be less than the number of variables in VS. */
908 static struct variable *
909 dict_var_set_get_var (const struct var_set *vs, size_t idx)
910 {
911   struct dictionary *d = vs->aux;
912
913   return dict_get_var (d, idx);
914 }
915
916 /* If VS contains a variable named NAME, sets *IDX to its index
917    and returns true.  Otherwise, returns false. */
918 static bool
919 dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
920                              size_t *idx)
921 {
922   struct dictionary *d = vs->aux;
923   struct variable *v = dict_lookup_var (d, name);
924   if (v != NULL)
925     {
926       *idx = var_get_dict_index (v);
927       return true;
928     }
929   else
930     return false;
931 }
932
933 /* Destroys VS. */
934 static void
935 dict_var_set_destroy (struct var_set *vs)
936 {
937   free (vs);
938 }
939
940 /* Returns a variable set based on D. */
941 struct var_set *
942 var_set_create_from_dict (const struct dictionary *d)
943 {
944   struct var_set *vs = xmalloc (sizeof *vs);
945   vs->names_must_be_ids = dict_get_names_must_be_ids (d);
946   vs->get_n = dict_var_set_get_n;
947   vs->get_var = dict_var_set_get_var;
948   vs->lookup_var_idx = dict_var_set_lookup_var_idx;
949   vs->destroy = dict_var_set_destroy;
950   vs->aux = (void *) d;
951   return vs;
952 }
953 \f
954 /* A variable set based on an array. */
955 struct array_var_set
956   {
957     struct variable *const *var;/* Array of variables. */
958     size_t n_vars;              /* Number of elements in var. */
959     struct hmapx vars_by_name;  /* Variables hashed by name. */
960   };
961
962 /* Returns the number of variables in VS. */
963 static size_t
964 array_var_set_get_n (const struct var_set *vs)
965 {
966   struct array_var_set *avs = vs->aux;
967
968   return avs->n_vars;
969 }
970
971 /* Return variable with index IDX in VS.
972    IDX must be less than the number of variables in VS. */
973 static struct variable *
974 array_var_set_get_var (const struct var_set *vs, size_t idx)
975 {
976   struct array_var_set *avs = vs->aux;
977
978   return CONST_CAST (struct variable *, avs->var[idx]);
979 }
980
981 /* If VS contains a variable named NAME, sets *IDX to its index
982    and returns true.  Otherwise, returns false. */
983 static bool
984 array_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
985                               size_t *idx)
986 {
987   struct array_var_set *avs = vs->aux;
988   struct hmapx_node *node;
989   struct variable **varp;
990
991   HMAPX_FOR_EACH_WITH_HASH (varp, node, utf8_hash_case_string (name, 0),
992                             &avs->vars_by_name)
993     if (!utf8_strcasecmp (name, var_get_name (*varp)))
994       {
995         *idx = varp - avs->var;
996         return true;
997       }
998
999   return false;
1000 }
1001
1002 /* Destroys VS. */
1003 static void
1004 array_var_set_destroy (struct var_set *vs)
1005 {
1006   struct array_var_set *avs = vs->aux;
1007
1008   hmapx_destroy (&avs->vars_by_name);
1009   free (avs);
1010   free (vs);
1011 }
1012
1013 /* Returns a variable set based on the N_VARS variables in VAR. */
1014 struct var_set *
1015 var_set_create_from_array (struct variable *const *var, size_t n_vars)
1016 {
1017   struct var_set *vs;
1018   struct array_var_set *avs;
1019   size_t i;
1020
1021   vs = xmalloc (sizeof *vs);
1022   vs->names_must_be_ids = true;
1023   vs->get_n = array_var_set_get_n;
1024   vs->get_var = array_var_set_get_var;
1025   vs->lookup_var_idx = array_var_set_lookup_var_idx;
1026   vs->destroy = array_var_set_destroy;
1027   vs->aux = avs = xmalloc (sizeof *avs);
1028   avs->var = var;
1029   avs->n_vars = n_vars;
1030   hmapx_init (&avs->vars_by_name);
1031   for (i = 0; i < n_vars; i++)
1032     {
1033       const char *name = var_get_name (var[i]);
1034       size_t idx;
1035
1036       if (array_var_set_lookup_var_idx (vs, name, &idx))
1037         {
1038           var_set_destroy (vs);
1039           return NULL;
1040         }
1041       hmapx_insert (&avs->vars_by_name, CONST_CAST (void *, &avs->var[i]),
1042                     utf8_hash_case_string (name, 0));
1043     }
1044
1045   return vs;
1046 }
1047
1048
1049 /* Match a variable.
1050    If the match succeeds, the variable will be placed in VAR.
1051    Returns true if successful */
1052 bool
1053 lex_match_variable (struct lexer *lexer, const struct dictionary *dict, const struct variable **var)
1054 {
1055   if (lex_token (lexer) !=  T_ID)
1056     return false;
1057
1058   *var = parse_variable_const  (lexer, dict);
1059
1060   if (*var == NULL)
1061     return false;
1062   return true;
1063 }
1064
1065 /* An interaction is a variable followed by {*, BY} followed by an interaction */
1066 static bool
1067 parse_internal_interaction (struct lexer *lexer, const struct dictionary *dict, struct interaction **iact, struct interaction **it)
1068 {
1069   const struct variable *v = NULL;
1070   assert (iact);
1071
1072   switch  (lex_next_token (lexer, 1))
1073     {
1074     case T_ENDCMD:
1075     case T_SLASH:
1076     case T_COMMA:
1077     case T_ID:
1078     case T_BY:
1079     case T_ASTERISK:
1080       break;
1081     default:
1082       return false;
1083       break;
1084     }
1085
1086   if (! lex_match_variable (lexer, dict, &v))
1087     {
1088       if (it)
1089         interaction_destroy (*it);
1090       *iact = NULL;
1091       return false;
1092     }
1093
1094   assert (v);
1095
1096   if (*iact == NULL)
1097     *iact = interaction_create (v);
1098   else
1099     interaction_add_variable (*iact, v);
1100
1101   if (lex_match (lexer, T_ASTERISK) || lex_match (lexer, T_BY))
1102     {
1103       return parse_internal_interaction (lexer, dict, iact, iact);
1104     }
1105
1106   return true;
1107 }
1108
1109 bool
1110 parse_design_interaction (struct lexer *lexer, const struct dictionary *dict, struct interaction **iact)
1111 {
1112   return parse_internal_interaction (lexer, dict, iact, NULL);
1113 }
1114