Rename procedure.[ch] to dataset.[ch].
[pspp-builds.git] / src / language / control / repeat.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2007, 2009-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/dictionary.h"
23 #include "data/settings.h"
24 #include "language/command.h"
25 #include "language/lexer/lexer.h"
26 #include "language/lexer/segment.h"
27 #include "language/lexer/token.h"
28 #include "language/lexer/variable-parser.h"
29 #include "libpspp/cast.h"
30 #include "libpspp/hash-functions.h"
31 #include "libpspp/hmap.h"
32 #include "libpspp/message.h"
33 #include "libpspp/str.h"
34
35 #include "gl/ftoastr.h"
36 #include "gl/minmax.h"
37 #include "gl/xalloc.h"
38
39 #include "gettext.h"
40 #define _(msgid) gettext (msgid)
41
42 struct dummy_var
43   {
44     struct hmap_node hmap_node;
45     char *name;
46     char **values;
47     size_t n_values;
48   };
49
50 static bool parse_specification (struct lexer *, struct dictionary *,
51                                  struct hmap *dummies);
52 static bool parse_commands (struct lexer *, struct hmap *dummies);
53 static void destroy_dummies (struct hmap *dummies);
54
55 static bool parse_ids (struct lexer *, const struct dictionary *,
56                        struct dummy_var *);
57 static bool parse_numbers (struct lexer *, struct dummy_var *);
58 static bool parse_strings (struct lexer *, struct dummy_var *);
59
60 int
61 cmd_do_repeat (struct lexer *lexer, struct dataset *ds)
62 {
63   struct hmap dummies;
64   bool ok;
65
66   if (!parse_specification (lexer, dataset_dict (ds), &dummies))
67     return CMD_CASCADING_FAILURE;
68
69   ok = parse_commands (lexer, &dummies);
70
71   destroy_dummies (&dummies);
72
73   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
74 }
75
76 static unsigned int
77 hash_dummy (const char *name, size_t name_len)
78 {
79   return hash_case_bytes (name, name_len, 0);
80 }
81
82 static const struct dummy_var *
83 find_dummy_var (struct hmap *hmap, const char *name, size_t name_len)
84 {
85   const struct dummy_var *dv;
86
87   HMAP_FOR_EACH_WITH_HASH (dv, struct dummy_var, hmap_node,
88                            hash_dummy (name, name_len), hmap)
89     if (strcasecmp (dv->name, name))
90       return dv;
91
92   return NULL;
93 }
94
95 /* Parses the whole DO REPEAT command specification.
96    Returns success. */
97 static bool
98 parse_specification (struct lexer *lexer, struct dictionary *dict,
99                      struct hmap *dummies)
100 {
101   struct dummy_var *first_dv = NULL;
102
103   hmap_init (dummies);
104   do
105     {
106       struct dummy_var *dv;
107       const char *name;
108       bool ok;
109
110       /* Get a stand-in variable name and make sure it's unique. */
111       if (!lex_force_id (lexer))
112         goto error;
113       name = lex_tokcstr (lexer);
114       if (dict_lookup_var (dict, name))
115         msg (SW, _("Dummy variable name `%s' hides dictionary variable `%s'."),
116              name, name);
117       if (find_dummy_var (dummies, name, strlen (name)))
118         {
119           msg (SE, _("Dummy variable name `%s' is given twice."), name);
120           goto error;
121         }
122
123       /* Make a new macro. */
124       dv = xmalloc (sizeof *dv);
125       dv->name = xstrdup (name);
126       dv->values = NULL;
127       dv->n_values = 0;
128       hmap_insert (dummies, &dv->hmap_node, hash_dummy (name, strlen (name)));
129
130       /* Skip equals sign. */
131       lex_get (lexer);
132       if (!lex_force_match (lexer, T_EQUALS))
133         goto error;
134
135       /* Get the details of the variable's possible values. */
136       if (lex_token (lexer) == T_ID || lex_token (lexer) == T_ALL)
137         ok = parse_ids (lexer, dict, dv);
138       else if (lex_is_number (lexer))
139         ok = parse_numbers (lexer, dv);
140       else if (lex_is_string (lexer))
141         ok = parse_strings (lexer, dv);
142       else
143         {
144           lex_error (lexer, NULL);
145           goto error;
146         }
147       if (!ok)
148         goto error;
149       assert (dv->n_values > 0);
150       if (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
151         {
152           lex_error (lexer, NULL);
153           goto error;
154         }
155
156       /* If this is the first variable then it defines how many replacements
157          there must be; otherwise enforce this number of replacements. */
158       if (first_dv == NULL)
159         first_dv = dv;
160       else if (first_dv->n_values != dv->n_values)
161         {
162           msg (SE, _("Dummy variable `%s' had %d substitutions, so `%s' must "
163                      "also, but %d were specified."),
164                first_dv->name, first_dv->n_values,
165                dv->name, dv->n_values);
166           goto error;
167         }
168
169       lex_match (lexer, T_SLASH);
170     }
171   while (!lex_match (lexer, T_ENDCMD));
172
173   while (lex_match (lexer, T_ENDCMD))
174     continue;
175
176   return true;
177
178 error:
179   destroy_dummies (dummies);
180   return false;
181 }
182
183 static size_t
184 count_values (struct hmap *dummies)
185 {
186   const struct dummy_var *dv;
187   dv = HMAP_FIRST (struct dummy_var, hmap_node, dummies);
188   return dv->n_values;
189 }
190
191 static void
192 do_parse_commands (struct substring s, enum lex_syntax_mode syntax_mode,
193                    struct hmap *dummies,
194                    struct string *outputs, size_t n_outputs)
195 {
196   struct segmenter segmenter;
197
198   segmenter_init (&segmenter, syntax_mode);
199
200   while (!ss_is_empty (s))
201     {
202       enum segment_type type;
203       int n;
204
205       n = segmenter_push (&segmenter, s.string, s.length, &type);
206       assert (n >= 0);
207
208       if (type == SEG_DO_REPEAT_COMMAND)
209         {
210           for (;;)
211             {
212               int k;
213
214               k = segmenter_push (&segmenter, s.string + n, s.length - n,
215                                   &type);
216               if (type != SEG_NEWLINE && type != SEG_DO_REPEAT_COMMAND)
217                 break;
218
219               n += k;
220             }
221
222           do_parse_commands (ss_head (s, n), syntax_mode, dummies,
223                              outputs, n_outputs);
224         }
225       else if (type != SEG_END)
226         {
227           const struct dummy_var *dv;
228           size_t i;
229
230           dv = (type == SEG_IDENTIFIER
231                 ? find_dummy_var (dummies, s.string, n)
232                 : NULL);
233           for (i = 0; i < n_outputs; i++)
234             if (dv != NULL)
235               ds_put_cstr (&outputs[i], dv->values[i]);
236             else
237               ds_put_substring (&outputs[i], ss_head (s, n));
238         }
239
240       ss_advance (&s, n);
241     }
242 }
243
244 static bool
245 parse_commands (struct lexer *lexer, struct hmap *dummies)
246 {
247   struct string *outputs;
248   struct string input;
249   size_t input_len;
250   size_t n_values;
251   char *file_name;
252   int line_number;
253   bool ok;
254   size_t i;
255
256   if (lex_get_file_name (lexer) != NULL)
257     file_name = xstrdup (lex_get_file_name (lexer));
258   else
259     file_name = NULL;
260   line_number = lex_get_first_line_number (lexer, 0);
261
262   ds_init_empty (&input);
263   while (lex_is_string (lexer))
264     {
265       ds_put_substring (&input, lex_tokss (lexer));
266       ds_put_byte (&input, '\n');
267       lex_get (lexer);
268     }
269   if (ds_is_empty (&input))
270     ds_put_byte (&input, '\n');
271   ds_put_byte (&input, '\0');
272   input_len = ds_length (&input);
273
274   n_values = count_values (dummies);
275   outputs = xmalloc (n_values * sizeof *outputs);
276   for (i = 0; i < n_values; i++)
277     ds_init_empty (&outputs[i]);
278
279   do_parse_commands (ds_ss (&input), lex_get_syntax_mode (lexer),
280                      dummies, outputs, n_values);
281
282   ds_destroy (&input);
283
284   while (lex_match (lexer, T_ENDCMD))
285     continue;
286
287   ok = (lex_force_match_id (lexer, "END")
288         && lex_force_match_id (lexer, "REPEAT"));
289   if (ok)
290     lex_match_id (lexer, "PRINT"); /* XXX */
291
292   lex_discard_rest_of_command (lexer);
293
294   for (i = 0; i < n_values; i++)
295     {
296       struct string *output = &outputs[n_values - i - 1];
297       struct lex_reader *reader;
298
299       reader = lex_reader_for_substring_nocopy (ds_ss (output));
300       lex_reader_set_file_name (reader, file_name);
301       reader->line_number = line_number;
302       lex_include (lexer, reader);
303     }
304   free (file_name);
305
306   return ok;
307 }
308
309 static void
310 destroy_dummies (struct hmap *dummies)
311 {
312   struct dummy_var *dv, *next;
313
314   HMAP_FOR_EACH_SAFE (dv, next, struct dummy_var, hmap_node, dummies)
315     {
316       size_t i;
317
318       hmap_delete (dummies, &dv->hmap_node);
319
320       free (dv->name);
321       for (i = 0; i < dv->n_values; i++)
322         free (dv->values[i]);
323       free (dv->values);
324       free (dv);
325     }
326   hmap_destroy (dummies);
327 }
328
329 /* Parses a set of ids for DO REPEAT. */
330 static bool
331 parse_ids (struct lexer *lexer, const struct dictionary *dict,
332            struct dummy_var *dv)
333 {
334   return parse_mixed_vars (lexer, dict, &dv->values, &dv->n_values, PV_NONE);
335 }
336
337 /* Adds REPLACEMENT to MACRO's list of replacements, which has
338    *USED elements and has room for *ALLOCATED.  Allocates memory
339    from POOL. */
340 static void
341 add_replacement (struct dummy_var *dv, char *value, size_t *allocated)
342 {
343   if (dv->n_values == *allocated)
344     dv->values = x2nrealloc (dv->values, allocated, sizeof *dv->values);
345   dv->values[dv->n_values++] = value;
346 }
347
348 /* Parses a list or range of numbers for DO REPEAT. */
349 static bool
350 parse_numbers (struct lexer *lexer, struct dummy_var *dv)
351 {
352   size_t allocated = 0;
353
354   do
355     {
356       if (!lex_force_num (lexer))
357         return false;
358
359       if (lex_next_token (lexer, 1) == T_TO)
360         {
361           long int a, b;
362           long int i;
363
364           if (!lex_is_integer (lexer))
365             {
366               msg (SE, _("Ranges may only have integer bounds."));
367               return false;
368             }
369
370           a = lex_integer (lexer);
371           lex_get (lexer);
372           lex_get (lexer);
373
374           if (!lex_force_int (lexer))
375             return false;
376
377           b = lex_integer (lexer);
378           if (b < a)
379             {
380               msg (SE, _("%ld TO %ld is an invalid range."), a, b);
381               return false;
382             }
383           lex_get (lexer);
384
385           for (i = a; i <= b; i++)
386             add_replacement (dv, xasprintf ("%ld", i), &allocated);
387         }
388       else
389         {
390           char s[DBL_BUFSIZE_BOUND];
391
392           dtoastr (s, sizeof s, 0, 0, lex_number (lexer));
393           add_replacement (dv, xstrdup (s), &allocated);
394           lex_get (lexer);
395         }
396
397       lex_match (lexer, T_COMMA);
398     }
399   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD);
400
401   return true;
402 }
403
404 /* Parses a list of strings for DO REPEAT. */
405 static bool
406 parse_strings (struct lexer *lexer, struct dummy_var *dv)
407 {
408   size_t allocated = 0;
409
410   do
411     {
412       if (!lex_force_string (lexer))
413         {
414           msg (SE, _("String expected."));
415           return false;
416         }
417
418       add_replacement (dv, token_to_string (lex_next (lexer, 0)), &allocated);
419
420       lex_get (lexer);
421       lex_match (lexer, T_COMMA);
422     }
423   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD);
424
425   return true;
426 }
427 \f
428 int
429 cmd_end_repeat (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
430 {
431   msg (SE, _("No matching DO REPEAT."));
432   return CMD_CASCADING_FAILURE;
433 }