1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 #include "dictionary.h"
35 #include "debug-print.h"
39 Each loop causes 3 different transformations to be output. The
40 first two are output when the LOOP command is encountered; the last
41 is output when the END LOOP command is encountered.
43 The first to be output resets the pass number in the second
44 transformation to -1. This ensures that the pass number is set to
45 -1 every time the loop is encountered, before the first iteration.
47 The second transformation increments the pass number. If
48 there is no indexing or test clause on either LOOP or END
49 LOOP, then the pass number is checked against MXLOOPS and
50 control may pass out of the loop. Otherwise the indexing or
51 test clause(s) on LOOP are checked, and again control may pass
54 After the second transformation the body of the loop is
57 The last transformation checks the test clause if present and
58 either jumps back up to the second transformation or
63 1. LOOP. Sets pass number to -1 and continues to next
66 2. LOOP. Increments pass number. Tests optional indexing
67 clause and optional IF clause. If we're done with the
68 loop, we jump to the transformation just after LOOP
71 Otherwise, we continue through the transformations in the
74 3. END LOOP. We test the optional IF clause. If we need to
75 make another pass through the loop, we jump to LOOP
78 Otherwise, we continue with the transformation jump after
82 /* Types of limits on loop execution. */
85 LPC_INDEX = 001, /* Limited by indexing clause. */
86 LPC_COND = 002, /* Limited by IF clause. */
87 LPC_RINDEX = 004 /* Indexing clause counts downward, at least
88 for this pass thru the loop. */
91 /* LOOP transformation 1. */
96 struct loop_2_trns *two; /* Allows modification of associated
97 second transformation. */
99 struct expression *init; /* Starting index. */
100 struct expression *incr; /* Index increment. */
101 struct expression *term; /* Terminal index. */
104 /* LOOP transformation 2. */
107 struct trns_header h;
109 struct ctl_stmt ctl; /* Nesting control info. */
111 int flags; /* Types of limits on loop execution. */
112 int pass; /* Number of passes thru the loop so far. */
114 struct variable *index; /* Index variable. */
115 double curr; /* Current index. */
116 double incr; /* Increment. */
117 double term; /* Terminal index. */
119 struct expression *cond; /* Optional IF condition when non-NULL. */
121 int loop_term; /* 1+(t_trns[] index of transformation 3);
122 backpatched in by END LOOP. */
125 /* LOOP transformation 3. (Actually output by END LOOP.) */
128 struct trns_header h;
130 struct expression *cond; /* Optional IF condition when non-NULL. */
132 int loop_start; /* t_trns[] index of transformation 2. */
135 /* LOOP transformations being created. */
136 static struct loop_1_trns *one;
137 static struct loop_2_trns *two;
138 static struct loop_3_trns *thr;
140 static int internal_cmd_loop (void);
141 static int internal_cmd_end_loop (void);
142 static trns_proc_func break_trns_proc;
143 static trns_proc_func loop_1_trns_proc, loop_2_trns_proc, loop_3_trns_proc;
144 static trns_free_func loop_1_trns_free, loop_2_trns_free, loop_3_trns_free;
145 static void pop_ctl_stack (void);
149 /* Parses a LOOP command. Passes the real work off to
150 internal_cmd_loop(). */
154 if (!internal_cmd_loop ())
156 loop_1_trns_free ((struct trns_header *) one);
157 loop_2_trns_free ((struct trns_header *) two);
164 /* Parses a LOOP command, returns success. */
166 internal_cmd_loop (void)
168 /* Name of indexing variable if applicable. */
171 /* Create and initialize transformations to facilitate
173 two = xmalloc (sizeof *two);
174 two->h.proc = loop_2_trns_proc;
175 two->h.free = loop_2_trns_free;
179 one = xmalloc (sizeof *one);
180 one->h.proc = loop_1_trns_proc;
181 one->h.free = loop_1_trns_free;
182 one->init = one->incr = one->term = NULL;
185 /* Parse indexing clause. */
186 if (token == T_ID && lex_look_ahead () == '=')
188 struct variable *v = dict_lookup_var (default_dict, tokid);
190 two->flags |= LPC_INDEX;
192 if (v && v->type == ALPHA)
194 msg (SE, _("The index variable may not be a string variable."));
197 strcpy (name, tokid);
200 assert (token == '=');
203 one->init = expr_parse (EXPR_NUMERIC);
207 if (!lex_force_match (T_TO))
209 expr_free (one->init);
212 one->term = expr_parse (EXPR_NUMERIC);
215 expr_free (one->init);
219 if (lex_match (T_BY))
221 one->incr = expr_parse (EXPR_NUMERIC);
229 /* Parse IF clause. */
230 if (lex_match_id ("IF"))
232 two->flags |= LPC_COND;
234 two->cond = expr_parse (EXPR_BOOLEAN);
241 lex_error (_("expecting end of command"));
245 /* Find variable; create if necessary. */
248 two->index = dict_lookup_var (default_dict, name);
250 two->index = dict_create_var (default_dict, name, 0);
253 /* Push on control stack. */
254 two->ctl.down = ctl_stack;
255 two->ctl.type = CST_LOOP;
256 two->ctl.trns = (struct trns_header *) two;
258 ctl_stack = &two->ctl;
260 /* Dump out the transformations. */
261 add_transformation ((struct trns_header *) one);
262 add_transformation ((struct trns_header *) two);
267 /* Parses the END LOOP command by passing the buck off to
268 cmd_internal_end_loop(). */
272 if (!internal_cmd_end_loop ())
274 loop_3_trns_free ((struct trns_header *) thr);
275 if (ctl_stack && ctl_stack->type == CST_LOOP)
283 /* Parses the END LOOP command. */
285 internal_cmd_end_loop (void)
287 /* Backpatch pointer for BREAK commands. */
288 struct break_trns *brk;
290 /* Allocate, initialize transformation to facilitate
292 thr = xmalloc (sizeof *thr);
293 thr->h.proc = loop_3_trns_proc;
294 thr->h.free = loop_3_trns_free;
297 /* There must be a matching LOOP command. */
298 if (!ctl_stack || ctl_stack->type != CST_LOOP)
300 msg (SE, _("There is no LOOP command that corresponds to this "
304 thr->loop_start = ((struct loop_2_trns *) ctl_stack->trns)->h.index;
306 /* Parse the expression if any. */
307 if (lex_match_id ("IF"))
309 thr->cond = expr_parse (EXPR_BOOLEAN);
314 add_transformation ((struct trns_header *) thr);
317 ((struct loop_2_trns *) ctl_stack->trns)->loop_term = n_trns;
318 for (brk = ctl_stack->brk; brk; brk = brk->next)
319 brk->loop_term = n_trns;
321 /* Pop off the top of stack. */
322 ctl_stack = ctl_stack->down;
327 /* Performs transformation 1. */
329 loop_1_trns_proc (struct trns_header * trns, struct ccase * c,
332 struct loop_1_trns *one = (struct loop_1_trns *) trns;
333 struct loop_2_trns *two = one->two;
336 if (two->flags & LPC_INDEX)
338 union value t1, t2, t3;
340 expr_evaluate (one->init, c, case_num, &t1);
342 expr_evaluate (one->incr, c, case_num, &t2);
345 expr_evaluate (one->term, c, case_num, &t3);
347 /* Even if the loop is never entered, force the index variable
348 to assume the initial value. */
349 case_data_rw (c, two->index->fv)->f = t1.f;
351 /* Throw out various pathological cases. */
352 if (!finite (t1.f) || !finite (t2.f) || !finite (t3.f) || t2.f == 0.0)
353 return two->loop_term;
354 debug_printf (("LOOP %s=%g TO %g BY %g.\n", two->index->name,
358 /* Loop counts upward: I=1 TO 5 BY 1. */
359 two->flags &= ~LPC_RINDEX;
361 /* incr>0 but init>term */
363 return two->loop_term;
367 /* Loop counts downward: I=5 TO 1 BY -1. */
368 two->flags |= LPC_RINDEX;
370 /* incr<0 but init<term */
372 return two->loop_term;
383 /* Frees transformation 1. */
385 loop_1_trns_free (struct trns_header * trns)
387 struct loop_1_trns *one = (struct loop_1_trns *) trns;
389 expr_free (one->init);
390 expr_free (one->incr);
391 expr_free (one->term);
394 /* Performs transformation 2. */
396 loop_2_trns_proc (struct trns_header * trns, struct ccase * c,
399 struct loop_2_trns *two = (struct loop_2_trns *) trns;
401 /* MXLOOPS limiter. */
405 if (two->pass > get_mxloops() )
406 return two->loop_term;
409 /* Indexing clause limiter: counting downward. */
410 if (two->flags & LPC_RINDEX)
412 /* Test if we're at the end of the looping. */
413 if (two->curr < two->term)
414 return two->loop_term;
416 /* Set the current value into the case. */
417 case_data_rw (c, two->index->fv)->f = two->curr;
419 /* Decrement the current value. */
420 two->curr += two->incr;
422 /* Indexing clause limiter: counting upward. */
423 else if (two->flags & LPC_INDEX)
425 /* Test if we're at the end of the looping. */
426 if (two->curr > two->term)
427 return two->loop_term;
429 /* Set the current value into the case. */
430 case_data_rw (c, two->index->fv)->f = two->curr;
432 /* Increment the current value. */
433 two->curr += two->incr;
436 /* Conditional clause limiter. */
437 if ((two->flags & LPC_COND)
438 && expr_evaluate (two->cond, c, case_num, NULL) != 1.0)
439 return two->loop_term;
444 /* Frees transformation 2. */
446 loop_2_trns_free (struct trns_header * trns)
448 struct loop_2_trns *two = (struct loop_2_trns *) trns;
450 expr_free (two->cond);
453 /* Performs transformation 3. */
455 loop_3_trns_proc (struct trns_header * trns, struct ccase * c,
458 struct loop_3_trns *thr = (struct loop_3_trns *) trns;
460 /* Note that it breaks out of the loop if the expression is true *or
461 missing*. This is conformant. */
462 if (thr->cond && expr_evaluate (two->cond, c, case_num, NULL) != 0.0)
465 return thr->loop_start;
468 /* Frees transformation 3. */
470 loop_3_trns_free (struct trns_header * trns)
472 struct loop_3_trns *thr = (struct loop_3_trns *) trns;
474 expr_free (thr->cond);
479 /* Parses the BREAK command. */
483 /* Climbs down the stack to find a LOOP. */
484 struct ctl_stmt *loop;
486 /* New transformation. */
487 struct break_trns *t;
489 for (loop = ctl_stack; loop; loop = loop->down)
490 if (loop->type == CST_LOOP)
494 msg (SE, _("This command may only appear enclosed in a LOOP/"
495 "END LOOP control structure."));
499 if (ctl_stack->type != CST_DO_IF)
500 msg (SW, _("BREAK not enclosed in DO IF structure."));
502 t = xmalloc (sizeof *t);
503 t->h.proc = break_trns_proc;
507 add_transformation ((struct trns_header *) t);
509 return lex_end_of_command ();
513 break_trns_proc (struct trns_header * trns, struct ccase * c UNUSED,
516 return ((struct break_trns *) trns)->loop_term;
519 /* Control stack operations. */
521 /* Pops the top of stack element off of ctl_stack. Does not
522 check that ctl_stack is indeed non-NULL. */
526 switch (ctl_stack->type)
530 /* Pointer for chasing down and backpatching BREAKs. */
531 struct break_trns *brk;
533 /* Terminate the loop. */
534 thr = xmalloc (sizeof *thr);
535 thr->h.proc = loop_3_trns_proc;
536 thr->h.free = loop_3_trns_free;
538 thr->loop_start = ((struct loop_2_trns *) ctl_stack->trns)->h.index;
539 add_transformation ((struct trns_header *) thr);
542 ((struct loop_2_trns *) ctl_stack->trns)->loop_term = n_trns;
543 for (brk = ctl_stack->brk; brk; brk = brk->next)
544 brk->loop_term = n_trns;
550 struct do_if_trns *iter;
552 iter = ((struct do_if_trns *) ctl_stack->trns);
556 iter->brk->dest = n_trns;
557 iter->missing_jump = n_trns;
563 iter->false_jump = n_trns;
569 ctl_stack = ctl_stack->down;
572 /* Checks for unclosed LOOPs and DO IFs and closes them out. */
574 discard_ctl_stack (void)
578 msg (SE, _("%s without %s."), ctl_stack->type == CST_LOOP ? "LOOP" : "DO IF",
579 ctl_stack->type == CST_LOOP ? "END LOOP" : "END IF");