1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "control-stack.h"
20 #include <data/case.h>
21 #include <data/dictionary.h>
22 #include <data/procedure.h>
23 #include <data/settings.h>
24 #include <data/transformations.h>
25 #include <data/variable.h>
26 #include <language/command.h>
27 #include <language/expressions/public.h>
28 #include <language/lexer/lexer.h>
29 #include <libpspp/compiler.h>
30 #include <libpspp/message.h>
31 #include <libpspp/misc.h>
32 #include <libpspp/pool.h>
33 #include <libpspp/str.h>
38 #define _(msgid) gettext (msgid)
40 /* LOOP outputs a transformation that is executed only on the
41 first pass through the loop. On this trip, it initializes for
42 the first pass by resetting the pass number, setting up the
43 indexing clause, and testing the LOOP IF clause. If the loop
44 is not to be entered at all, it jumps forward just past the
45 END LOOP transformation; otherwise, it continues to the
46 transformation following LOOP.
48 END LOOP outputs a transformation that executes at the end of
49 each trip through the loop. It checks the END LOOP IF clause,
50 then updates the pass number, increments the indexing clause,
51 and tests the LOOP IF clause. If another pass through the
52 loop is due, it jumps backward to just after the LOOP
53 transformation; otherwise, it continues to the transformation
54 following END LOOP. */
61 /* Iteration limit. */
62 int max_pass_count; /* Maximum number of passes (-1=unlimited). */
63 int pass; /* Number of passes thru the loop so far. */
65 /* a=a TO b [BY c]. */
66 struct variable *index_var; /* Index variable. */
67 struct expression *first_expr; /* Starting index. */
68 struct expression *by_expr; /* Index increment (default 1.0 if null). */
69 struct expression *last_expr; /* Terminal index. */
70 double cur, by, last; /* Current value, increment, last value. */
72 /* IF condition for LOOP or END LOOP. */
73 struct expression *loop_condition;
74 struct expression *end_loop_condition;
76 /* Transformation indexes. */
77 int past_LOOP_index; /* Just past LOOP transformation. */
78 int past_END_LOOP_index; /* Just past END LOOP transformation. */
81 static const struct ctl_class loop_class;
83 static trns_finalize_func loop_trns_finalize;
84 static trns_proc_func loop_trns_proc, end_loop_trns_proc, break_trns_proc;
85 static trns_free_func loop_trns_free;
87 static struct loop_trns *create_loop_trns (struct dataset *);
88 static bool parse_if_clause (struct lexer *,
89 struct loop_trns *, struct expression **);
90 static bool parse_index_clause (struct dataset *, struct lexer *,
91 struct loop_trns *, bool *created_index_var);
92 static void close_loop (void *);
98 cmd_loop (struct lexer *lexer, struct dataset *ds)
100 struct loop_trns *loop;
101 bool created_index_var = false;
104 loop = create_loop_trns (ds);
105 while (lex_token (lexer) != '.' && ok)
107 if (lex_match_id (lexer, "IF"))
108 ok = parse_if_clause (lexer, loop, &loop->loop_condition);
110 ok = parse_index_clause (ds, lexer, loop, &created_index_var);
113 /* Clean up if necessary. */
116 loop->max_pass_count = 0;
117 if (loop->index_var != NULL && created_index_var)
119 dict_delete_var (dataset_dict (ds), loop->index_var);
120 loop->index_var = NULL;
124 return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
127 /* Parses END LOOP. */
129 cmd_end_loop (struct lexer *lexer, struct dataset *ds)
131 struct loop_trns *loop;
134 loop = ctl_stack_top (&loop_class);
136 return CMD_CASCADING_FAILURE;
138 assert (loop->ds == ds);
141 if (lex_match_id (lexer, "IF"))
142 ok = parse_if_clause (lexer, loop, &loop->end_loop_condition);
144 ok = lex_end_of_command (lexer) == CMD_SUCCESS;
147 loop->max_pass_count = 0;
149 ctl_stack_pop (loop);
151 return ok ? CMD_SUCCESS : CMD_FAILURE;
156 cmd_break (struct lexer *lexer, struct dataset *ds)
158 struct ctl_stmt *loop = ctl_stack_search (&loop_class);
160 return CMD_CASCADING_FAILURE;
162 add_transformation (ds, break_trns_proc, NULL, loop);
164 return lex_end_of_command (lexer);
167 /* Closes a LOOP construct by emitting the END LOOP
168 transformation and finalizing its members appropriately. */
170 close_loop (void *loop_)
172 struct loop_trns *loop = loop_;
174 add_transformation (loop->ds, end_loop_trns_proc, NULL, loop);
175 loop->past_END_LOOP_index = next_transformation (loop->ds);
177 /* If there's nothing else limiting the number of loops, use
178 MXLOOPS as a limit. */
179 if (loop->max_pass_count == -1
180 && loop->index_var == NULL
181 && loop->loop_condition == NULL
182 && loop->end_loop_condition == NULL)
183 loop->max_pass_count = get_mxloops ();
186 /* Parses an IF clause for LOOP or END LOOP and stores the
187 resulting expression to *CONDITION.
188 Returns true if successful, false on failure. */
190 parse_if_clause (struct lexer *lexer,
191 struct loop_trns *loop, struct expression **condition)
193 if (*condition != NULL)
195 lex_sbc_only_once ("IF");
199 *condition = expr_parse_pool (lexer, loop->pool, loop->ds, EXPR_BOOLEAN);
200 return *condition != NULL;
203 /* Parses an indexing clause into LOOP.
204 Stores true in *CREATED_INDEX_VAR if the index clause created
205 a new variable, false otherwise.
206 Returns true if successful, false on failure. */
208 parse_index_clause (struct dataset *ds, struct lexer *lexer,
209 struct loop_trns *loop, bool *created_index_var)
211 if (loop->index_var != NULL)
213 msg (SE, _("Only one index clause may be specified."));
217 if (lex_token (lexer) != T_ID)
219 lex_error (lexer, NULL);
223 loop->index_var = dict_lookup_var (dataset_dict (ds), lex_tokid (lexer));
224 if (loop->index_var != NULL)
225 *created_index_var = false;
228 loop->index_var = dict_create_var_assert (dataset_dict (ds),
229 lex_tokid (lexer), 0);
230 *created_index_var = true;
234 if (!lex_force_match (lexer, '='))
237 loop->first_expr = expr_parse_pool (lexer, loop->pool,
238 loop->ds, EXPR_NUMBER);
239 if (loop->first_expr == NULL)
244 struct expression **e;
245 if (lex_match (lexer, T_TO))
246 e = &loop->last_expr;
247 else if (lex_match (lexer, T_BY))
254 lex_sbc_only_once (e == &loop->last_expr ? "TO" : "BY");
257 *e = expr_parse_pool (lexer, loop->pool, loop->ds, EXPR_NUMBER);
261 if (loop->last_expr == NULL)
263 lex_sbc_missing (lexer, "TO");
266 if (loop->by_expr == NULL)
272 /* Creates, initializes, and returns a new loop_trns. */
273 static struct loop_trns *
274 create_loop_trns (struct dataset *ds)
276 struct loop_trns *loop = pool_create_container (struct loop_trns, pool);
277 loop->max_pass_count = -1;
279 loop->index_var = NULL;
280 loop->first_expr = loop->by_expr = loop->last_expr = NULL;
281 loop->loop_condition = loop->end_loop_condition = NULL;
284 add_transformation_with_finalizer (ds, loop_trns_finalize,
285 loop_trns_proc, loop_trns_free, loop);
286 loop->past_LOOP_index = next_transformation (ds);
288 ctl_stack_push (&loop_class, loop);
293 /* Finalizes LOOP by clearing the control stack, thus ensuring
294 that all open LOOPs are closed. */
296 loop_trns_finalize (void *do_if_ UNUSED)
298 /* This will be called multiple times if multiple LOOPs were
299 executed, which is slightly unclean, but at least it's
304 /* Sets up LOOP for the first pass. */
306 loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num)
308 struct loop_trns *loop = loop_;
310 if (loop->index_var != NULL)
312 /* Evaluate loop index expressions. */
313 loop->cur = expr_evaluate_num (loop->first_expr, c, case_num);
314 if (loop->by_expr != NULL)
315 loop->by = expr_evaluate_num (loop->by_expr, c, case_num);
316 loop->last = expr_evaluate_num (loop->last_expr, c, case_num);
318 /* Even if the loop is never entered, set the index
319 variable to the initial value. */
320 case_data_rw (c, loop->index_var)->f = loop->cur;
322 /* Throw out pathological cases. */
323 if (!finite (loop->cur) || !finite (loop->by) || !finite (loop->last)
325 || (loop->by > 0.0 && loop->cur > loop->last)
326 || (loop->by < 0.0 && loop->cur < loop->last))
330 /* Initialize pass count. */
332 if (loop->max_pass_count >= 0 && loop->pass >= loop->max_pass_count)
335 /* Check condition. */
336 if (loop->loop_condition != NULL
337 && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
340 return loop->past_LOOP_index;
343 return loop->past_END_LOOP_index;
348 loop_trns_free (void *loop_)
350 struct loop_trns *loop = loop_;
352 pool_destroy (loop->pool);
356 /* Finishes a pass through the loop and starts the next. */
358 end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED)
360 struct loop_trns *loop = loop_;
362 if (loop->end_loop_condition != NULL
363 && expr_evaluate_num (loop->end_loop_condition, c, case_num) != 0.0)
366 /* MXLOOPS limiter. */
367 if (loop->max_pass_count >= 0)
369 if (loop->pass >= loop->max_pass_count)
374 /* Indexing clause limiter: counting downward. */
375 if (loop->index_var != NULL)
377 loop->cur += loop->by;
378 if ((loop->by > 0.0 && loop->cur > loop->last)
379 || (loop->by < 0.0 && loop->cur < loop->last))
381 case_data_rw (c, loop->index_var)->f = loop->cur;
384 if (loop->loop_condition != NULL
385 && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
388 return loop->past_LOOP_index;
391 return loop->past_END_LOOP_index;
394 /* Executes BREAK. */
396 break_trns_proc (void *loop_, struct ccase *c UNUSED, casenumber case_num UNUSED)
398 struct loop_trns *loop = loop_;
400 return loop->past_END_LOOP_index;
403 /* LOOP control structure class definition. */
404 static const struct ctl_class loop_class =