1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include "control-stack.h"
22 #include <data/case.h>
23 #include <data/dictionary.h>
24 #include <data/procedure.h>
25 #include <data/settings.h>
26 #include <data/transformations.h>
27 #include <data/variable.h>
28 #include <language/command.h>
29 #include <language/expressions/public.h>
30 #include <language/lexer/lexer.h>
31 #include <libpspp/alloc.h>
32 #include <libpspp/compiler.h>
33 #include <libpspp/message.h>
34 #include <libpspp/misc.h>
35 #include <libpspp/pool.h>
36 #include <libpspp/str.h>
39 #define _(msgid) gettext (msgid)
41 /* LOOP outputs a transformation that is executed only on the
42 first pass through the loop. On this trip, it initializes for
43 the first pass by resetting the pass number, setting up the
44 indexing clause, and testing the LOOP IF clause. If the loop
45 is not to be entered at all, it jumps forward just past the
46 END LOOP transformation; otherwise, it continues to the
47 transformation following LOOP.
49 END LOOP outputs a transformation that executes at the end of
50 each trip through the loop. It checks the END LOOP IF clause,
51 then updates the pass number, increments the indexing clause,
52 and tests the LOOP IF clause. If another pass through the
53 loop is due, it jumps backward to just after the LOOP
54 transformation; otherwise, it continues to the transformation
55 following END LOOP. */
62 /* Iteration limit. */
63 int max_pass_count; /* Maximum number of passes (-1=unlimited). */
64 int pass; /* Number of passes thru the loop so far. */
66 /* a=a TO b [BY c]. */
67 struct variable *index_var; /* Index variable. */
68 struct expression *first_expr; /* Starting index. */
69 struct expression *by_expr; /* Index increment (default 1.0 if null). */
70 struct expression *last_expr; /* Terminal index. */
71 double cur, by, last; /* Current value, increment, last value. */
73 /* IF condition for LOOP or END LOOP. */
74 struct expression *loop_condition;
75 struct expression *end_loop_condition;
77 /* Transformation indexes. */
78 int past_LOOP_index; /* Just past LOOP transformation. */
79 int past_END_LOOP_index; /* Just past END LOOP transformation. */
82 static const struct ctl_class loop_class;
84 static trns_finalize_func loop_trns_finalize;
85 static trns_proc_func loop_trns_proc, end_loop_trns_proc, break_trns_proc;
86 static trns_free_func loop_trns_free;
88 static struct loop_trns *create_loop_trns (struct dataset *);
89 static bool parse_if_clause (struct lexer *, struct loop_trns *, struct expression **);
90 static bool parse_index_clause (struct lexer *, struct loop_trns *, char index_var_name[]);
91 static void close_loop (void *);
97 cmd_loop (struct lexer *lexer, struct dataset *ds)
99 struct loop_trns *loop;
100 char index_var_name[LONG_NAME_LEN + 1];
103 loop = create_loop_trns (ds);
104 while (lex_token (lexer) != '.' && ok)
106 if (lex_match_id (lexer, "IF"))
107 ok = parse_if_clause (lexer, loop, &loop->loop_condition);
109 ok = parse_index_clause (lexer, loop, index_var_name);
112 /* Find index variable and create if necessary. */
113 if (ok && index_var_name[0] != '\0')
115 loop->index_var = dict_lookup_var (dataset_dict (ds), index_var_name);
116 if (loop->index_var == NULL)
117 loop->index_var = dict_create_var (dataset_dict (ds),
122 loop->max_pass_count = 0;
123 return ok ? CMD_SUCCESS : CMD_FAILURE;
126 /* Parses END LOOP. */
128 cmd_end_loop (struct lexer *lexer, struct dataset *ds)
130 struct loop_trns *loop;
133 loop = ctl_stack_top (&loop_class);
135 return CMD_CASCADING_FAILURE;
137 assert (loop->ds == ds);
140 if (lex_match_id (lexer, "IF"))
141 ok = parse_if_clause (lexer, loop, &loop->end_loop_condition);
143 ok = lex_end_of_command (lexer) == CMD_SUCCESS;
146 loop->max_pass_count = 0;
148 ctl_stack_pop (loop);
150 return ok ? CMD_SUCCESS : CMD_FAILURE;
155 cmd_break (struct lexer *lexer, struct dataset *ds)
157 struct ctl_stmt *loop = ctl_stack_search (&loop_class);
159 return CMD_CASCADING_FAILURE;
161 add_transformation (ds, break_trns_proc, NULL, loop);
163 return lex_end_of_command (lexer);
166 /* Closes a LOOP construct by emitting the END LOOP
167 transformation and finalizing its members appropriately. */
169 close_loop (void *loop_)
171 struct loop_trns *loop = loop_;
173 add_transformation (loop->ds, end_loop_trns_proc, NULL, loop);
174 loop->past_END_LOOP_index = next_transformation (loop->ds);
176 /* If there's nothing else limiting the number of loops, use
177 MXLOOPS as a limit. */
178 if (loop->max_pass_count == -1
179 && loop->index_var == NULL
180 && loop->loop_condition == NULL
181 && loop->end_loop_condition == NULL)
182 loop->max_pass_count = get_mxloops ();
185 /* Parses an IF clause for LOOP or END LOOP and stores the
186 resulting expression to *CONDITION.
187 Returns true if successful, false on failure. */
189 parse_if_clause (struct lexer *lexer,
190 struct loop_trns *loop, struct expression **condition)
192 *condition = expr_parse_pool (lexer, loop->pool, loop->ds, EXPR_BOOLEAN);
193 return *condition != NULL;
196 /* Parses an indexing clause into LOOP.
197 Stores the index variable's name in INDEX_VAR_NAME[].
198 Returns true if successful, false on failure. */
200 parse_index_clause (struct lexer *lexer, struct loop_trns *loop, char index_var_name[])
202 if (lex_token (lexer) != T_ID)
204 lex_error (lexer, NULL);
207 strcpy (index_var_name, lex_tokid (lexer));
210 if (!lex_force_match (lexer, '='))
213 loop->first_expr = expr_parse_pool (lexer, loop->pool,
214 loop->ds, EXPR_NUMBER);
215 if (loop->first_expr == NULL)
220 struct expression **e;
221 if (lex_match (lexer, T_TO))
222 e = &loop->last_expr;
223 else if (lex_match (lexer, T_BY))
230 lex_sbc_only_once (e == &loop->last_expr ? "TO" : "BY");
233 *e = expr_parse_pool (lexer, loop->pool, loop->ds, EXPR_NUMBER);
237 if (loop->last_expr == NULL)
239 lex_sbc_missing (lexer, "TO");
242 if (loop->by_expr == NULL)
248 /* Creates, initializes, and returns a new loop_trns. */
249 static struct loop_trns *
250 create_loop_trns (struct dataset *ds)
252 struct loop_trns *loop = pool_create_container (struct loop_trns, pool);
253 loop->max_pass_count = -1;
255 loop->index_var = NULL;
256 loop->first_expr = loop->by_expr = loop->last_expr = NULL;
257 loop->loop_condition = loop->end_loop_condition = NULL;
260 add_transformation_with_finalizer (ds, loop_trns_finalize,
261 loop_trns_proc, loop_trns_free, loop);
262 loop->past_LOOP_index = next_transformation (ds);
264 ctl_stack_push (&loop_class, loop);
269 /* Finalizes LOOP by clearing the control stack, thus ensuring
270 that all open LOOPs are closed. */
272 loop_trns_finalize (void *do_if_ UNUSED)
274 /* This will be called multiple times if multiple LOOPs were
275 executed, which is slightly unclean, but at least it's
280 /* Sets up LOOP for the first pass. */
282 loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num)
284 struct loop_trns *loop = loop_;
286 if (loop->index_var != NULL)
288 /* Evaluate loop index expressions. */
289 loop->cur = expr_evaluate_num (loop->first_expr, c, case_num);
290 if (loop->by_expr != NULL)
291 loop->by = expr_evaluate_num (loop->by_expr, c, case_num);
292 loop->last = expr_evaluate_num (loop->last_expr, c, case_num);
294 /* Even if the loop is never entered, set the index
295 variable to the initial value. */
296 case_data_rw (c, loop->index_var)->f = loop->cur;
298 /* Throw out pathological cases. */
299 if (!finite (loop->cur) || !finite (loop->by) || !finite (loop->last)
301 || (loop->by > 0.0 && loop->cur > loop->last)
302 || (loop->by < 0.0 && loop->cur < loop->last))
306 /* Initialize pass count. */
308 if (loop->max_pass_count >= 0 && loop->pass >= loop->max_pass_count)
311 /* Check condition. */
312 if (loop->loop_condition != NULL
313 && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
316 return loop->past_LOOP_index;
319 return loop->past_END_LOOP_index;
324 loop_trns_free (void *loop_)
326 struct loop_trns *loop = loop_;
328 pool_destroy (loop->pool);
332 /* Finishes a pass through the loop and starts the next. */
334 end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED)
336 struct loop_trns *loop = loop_;
338 if (loop->end_loop_condition != NULL
339 && expr_evaluate_num (loop->end_loop_condition, c, case_num) != 1.0)
342 /* MXLOOPS limiter. */
343 if (loop->max_pass_count >= 0)
345 if (loop->pass >= loop->max_pass_count)
350 /* Indexing clause limiter: counting downward. */
351 if (loop->index_var != NULL)
353 loop->cur += loop->by;
354 if ((loop->by > 0.0 && loop->cur > loop->last)
355 || (loop->by < 0.0 && loop->cur < loop->last))
357 case_data_rw (c, loop->index_var)->f = loop->cur;
360 if (loop->loop_condition != NULL
361 && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
364 return loop->past_LOOP_index;
367 return loop->past_END_LOOP_index;
370 /* Executes BREAK. */
372 break_trns_proc (void *loop_, struct ccase *c UNUSED, casenumber case_num UNUSED)
374 struct loop_trns *loop = loop_;
376 return loop->past_END_LOOP_index;
379 /* LOOP control structure class definition. */
380 static const struct ctl_class loop_class =