GLM: Prepare the lexer to accept nested variables
[pspp] / src / language / dictionary / vector.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2010, 2011 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 <stdlib.h>
20
21 #include "data/dataset.h"
22 #include "data/format.h"
23 #include "data/dictionary.h"
24 #include "data/variable.h"
25 #include "language/command.h"
26 #include "language/lexer/format-parser.h"
27 #include "language/lexer/lexer.h"
28 #include "language/lexer/variable-parser.h"
29 #include "libpspp/assertion.h"
30 #include "libpspp/message.h"
31 #include "libpspp/misc.h"
32 #include "libpspp/pool.h"
33 #include "libpspp/str.h"
34
35 #include "gl/intprops.h"
36 #include "gl/xalloc.h"
37
38 #include "gettext.h"
39 #define _(msgid) gettext (msgid)
40
41 int
42 cmd_vector (struct lexer *lexer, struct dataset *ds)
43 {
44   struct dictionary *dict = dataset_dict (ds);
45   struct pool *pool = pool_create ();
46
47   do
48     {
49       char **vectors;
50       size_t vector_cnt, vector_cap;
51
52       /* Get the name(s) of the new vector(s). */
53       if (!lex_force_id (lexer)
54           || !dict_id_is_valid (dict, lex_tokcstr (lexer), true))
55         return CMD_CASCADING_FAILURE;
56
57       vectors = NULL;
58       vector_cnt = vector_cap = 0;
59       while (lex_token (lexer) == T_ID)
60         {
61           size_t i;
62
63           if (dict_lookup_vector (dict, lex_tokcstr (lexer)))
64             {
65               msg (SE, _("A vector named %s already exists."),
66                    lex_tokcstr (lexer));
67               goto fail;
68             }
69
70           for (i = 0; i < vector_cnt; i++)
71             if (!strcasecmp (vectors[i], lex_tokcstr (lexer)))
72               {
73                 msg (SE, _("Vector name %s is given twice."),
74                      lex_tokcstr (lexer));
75                 goto fail;
76               }
77
78           if (vector_cnt == vector_cap)
79             vectors = pool_2nrealloc (pool,
80                                        vectors, &vector_cap, sizeof *vectors);
81           vectors[vector_cnt++] = pool_strdup (pool, lex_tokcstr (lexer));
82
83           lex_get (lexer);
84           lex_match (lexer, T_COMMA);
85         }
86
87       /* Now that we have the names it's time to check for the short
88          or long forms. */
89       if (lex_match (lexer, T_EQUALS))
90         {
91           /* Long form. */
92           struct variable **v;
93           size_t nv;
94
95           if (vector_cnt > 1)
96             {
97               msg (SE, _("A slash must separate each vector "
98                          "specification in VECTOR's long form."));
99               goto fail;
100             }
101
102           if (!parse_variables_pool (lexer, pool, dict, &v, &nv,
103                                      PV_SAME_WIDTH | PV_DUPLICATE))
104             goto fail;
105
106           dict_create_vector (dict, vectors[0], v, nv);
107         }
108       else if (lex_match (lexer, T_LPAREN))
109         {
110           /* Short form. */
111           struct fmt_spec format;
112           bool seen_format = false;
113
114           struct variable **vars;
115           int var_cnt;
116
117           size_t i;
118
119           var_cnt = 0;
120           format = fmt_for_output (FMT_F, 8, 2);
121           seen_format = false;
122           while (!lex_match (lexer, T_RPAREN))
123             {
124               if (lex_is_integer (lexer) && var_cnt == 0)
125                 {
126                   var_cnt = lex_integer (lexer);
127                   lex_get (lexer);
128                   if (var_cnt <= 0)
129                     {
130                       msg (SE, _("Vectors must have at least one element."));
131                       goto fail;
132                     }
133                 }
134               else if (lex_token (lexer) == T_ID && !seen_format)
135                 {
136                   seen_format = true;
137                   if (!parse_format_specifier (lexer, &format)
138                       || !fmt_check_output (&format)
139                       || !fmt_check_type_compat (&format, VAL_NUMERIC))
140                     goto fail;
141                 }
142               else
143                 {
144                   lex_error (lexer, NULL);
145                   goto fail;
146                 }
147               lex_match (lexer, T_COMMA);
148             }
149           if (var_cnt == 0)
150             {
151               lex_error (lexer, _("expecting vector length"));
152               goto fail;
153             }
154
155           /* Check that none of the variables exist and that their names are
156              not excessively long. */
157           for (i = 0; i < vector_cnt; i++)
158             {
159               int j;
160               for (j = 0; j < var_cnt; j++)
161                 {
162                   char *name = xasprintf ("%s%d", vectors[i], j + 1);
163                   if (!dict_id_is_valid (dict, name, true))
164                     {
165                       free (name);
166                       goto fail;
167                     }
168                   if (dict_lookup_var (dict, name))
169                     {
170                       free (name);
171                       msg (SE, _("%s is an existing variable name."), name);
172                       goto fail;
173                     }
174                   free (name);
175                 }
176             }
177
178           /* Finally create the variables and vectors. */
179           vars = pool_nmalloc (pool, var_cnt, sizeof *vars);
180           for (i = 0; i < vector_cnt; i++)
181             {
182               int j;
183               for (j = 0; j < var_cnt; j++)
184                 {
185                   char *name = xasprintf ("%s%d", vectors[i], j + 1);
186                   vars[j] = dict_create_var_assert (dict, name, 0);
187                   var_set_both_formats (vars[j], &format);
188                   free (name);
189                 }
190               dict_create_vector_assert (dict, vectors[i], vars, var_cnt);
191             }
192         }
193       else
194         {
195           lex_error (lexer, NULL);
196           goto fail;
197         }
198     }
199   while (lex_match (lexer, T_SLASH));
200
201   pool_destroy (pool);
202   return CMD_SUCCESS;
203
204 fail:
205   pool_destroy (pool);
206   return CMD_FAILURE;
207 }