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., 51 Franklin Street, Fifth Floor, Boston, MA
25 #include "dictionary.h"
28 #include "expressions/public.h"
36 #define _(msgid) gettext (msgid)
38 #include "debug-print.h"
42 Each loop causes 3 different transformations to be output. The
43 first two are output when the LOOP command is encountered; the last
44 is output when the END LOOP command is encountered.
46 The first to be output resets the pass number in the second
47 transformation to -1. This ensures that the pass number is set to
48 -1 every time the loop is encountered, before the first iteration.
50 The second transformation increments the pass number. If
51 there is no indexing or test clause on either LOOP or END
52 LOOP, then the pass number is checked against MXLOOPS and
53 control may pass out of the loop. Otherwise the indexing or
54 test clause(s) on LOOP are checked, and again control may pass
57 After the second transformation the body of the loop is
60 The last transformation checks the test clause if present and
61 either jumps back up to the second transformation or
66 1. LOOP. Sets pass number to -1 and continues to next
69 2. LOOP. Increments pass number. Tests optional indexing
70 clause and optional IF clause. If we're done with the
71 loop, we jump to the transformation just after LOOP
74 Otherwise, we continue through the transformations in the
77 3. END LOOP. We test the optional IF clause. If we need to
78 make another pass through the loop, we jump to LOOP
81 Otherwise, we continue with the transformation jump after
85 /* Types of limits on loop execution. */
88 LPC_INDEX = 001, /* Limited by indexing clause. */
89 LPC_COND = 002, /* Limited by IF clause. */
90 LPC_RINDEX = 004 /* Indexing clause counts downward, at least
91 for this pass thru the loop. */
94 /* LOOP transformation 1. */
99 struct loop_2_trns *two; /* Allows modification of associated
100 second transformation. */
102 struct expression *init; /* Starting index. */
103 struct expression *incr; /* Index increment. */
104 struct expression *term; /* Terminal index. */
107 /* LOOP transformation 2. */
110 struct trns_header h;
112 struct ctl_stmt ctl; /* Nesting control info. */
114 int flags; /* Types of limits on loop execution. */
115 int pass; /* Number of passes thru the loop so far. */
117 struct variable *index; /* Index variable. */
118 double curr; /* Current index. */
119 double incr; /* Increment. */
120 double term; /* Terminal index. */
122 struct expression *cond; /* Optional IF condition when non-NULL. */
124 int loop_term; /* 1+(t_trns[] index of transformation 3);
125 backpatched in by END LOOP. */
128 /* LOOP transformation 3. (Actually output by END LOOP.) */
131 struct trns_header h;
133 struct expression *cond; /* Optional IF condition when non-NULL. */
135 int loop_start; /* t_trns[] index of transformation 2. */
138 /* LOOP transformations being created. */
139 static struct loop_1_trns *one;
140 static struct loop_2_trns *two;
141 static struct loop_3_trns *thr;
143 static int internal_cmd_loop (void);
144 static int internal_cmd_end_loop (void);
145 static trns_proc_func break_trns_proc;
146 static trns_proc_func loop_1_trns_proc, loop_2_trns_proc, loop_3_trns_proc;
147 static trns_free_func loop_1_trns_free, loop_2_trns_free, loop_3_trns_free;
148 static void pop_ctl_stack (void);
152 /* Parses a LOOP command. Passes the real work off to
153 internal_cmd_loop(). */
157 if (!internal_cmd_loop ())
159 loop_1_trns_free ((struct trns_header *) one);
160 loop_2_trns_free ((struct trns_header *) two);
167 /* Parses a LOOP command, returns success. */
169 internal_cmd_loop (void)
171 /* Name of indexing variable if applicable. */
172 char name[LONG_NAME_LEN + 1];
174 /* Create and initialize transformations to facilitate
176 two = xmalloc (sizeof *two);
177 two->h.proc = loop_2_trns_proc;
178 two->h.free = loop_2_trns_free;
182 one = xmalloc (sizeof *one);
183 one->h.proc = loop_1_trns_proc;
184 one->h.free = loop_1_trns_free;
185 one->init = one->incr = one->term = NULL;
188 /* Parse indexing clause. */
189 if (token == T_ID && lex_look_ahead () == '=')
191 struct variable *v = dict_lookup_var (default_dict, tokid);
193 two->flags |= LPC_INDEX;
195 if (v && v->type == ALPHA)
197 msg (SE, _("The index variable may not be a string variable."));
200 strcpy (name, tokid);
203 assert (token == '=');
206 one->init = expr_parse (default_dict, EXPR_NUMBER);
210 if (!lex_force_match (T_TO))
212 expr_free (one->init);
215 one->term = expr_parse (default_dict, EXPR_NUMBER);
218 expr_free (one->init);
222 if (lex_match (T_BY))
224 one->incr = expr_parse (default_dict, EXPR_NUMBER);
232 /* Parse IF clause. */
233 if (lex_match_id ("IF"))
235 two->flags |= LPC_COND;
237 two->cond = expr_parse (default_dict, EXPR_BOOLEAN);
244 lex_error (_("expecting end of command"));
248 /* Find variable; create if necessary. */
251 two->index = dict_lookup_var (default_dict, name);
253 two->index = dict_create_var (default_dict, name, 0);
256 /* Push on control stack. */
257 two->ctl.down = ctl_stack;
258 two->ctl.type = CST_LOOP;
259 two->ctl.trns = (struct trns_header *) two;
261 ctl_stack = &two->ctl;
263 /* Dump out the transformations. */
264 add_transformation ((struct trns_header *) one);
265 add_transformation ((struct trns_header *) two);
270 /* Parses the END LOOP command by passing the buck off to
271 cmd_internal_end_loop(). */
275 if (!internal_cmd_end_loop ())
277 loop_3_trns_free ((struct trns_header *) thr);
278 if (ctl_stack && ctl_stack->type == CST_LOOP)
286 /* Parses the END LOOP command. */
288 internal_cmd_end_loop (void)
290 /* Backpatch pointer for BREAK commands. */
291 struct break_trns *brk;
293 /* Allocate, initialize transformation to facilitate
295 thr = xmalloc (sizeof *thr);
296 thr->h.proc = loop_3_trns_proc;
297 thr->h.free = loop_3_trns_free;
300 /* There must be a matching LOOP command. */
301 if (!ctl_stack || ctl_stack->type != CST_LOOP)
303 msg (SE, _("There is no LOOP command that corresponds to this "
307 thr->loop_start = ((struct loop_2_trns *) ctl_stack->trns)->h.index;
309 /* Parse the expression if any. */
310 if (lex_match_id ("IF"))
312 thr->cond = expr_parse (default_dict, EXPR_BOOLEAN);
317 add_transformation ((struct trns_header *) thr);
320 ((struct loop_2_trns *) ctl_stack->trns)->loop_term = n_trns;
321 for (brk = ctl_stack->brk; brk; brk = brk->next)
322 brk->loop_term = n_trns;
324 /* Pop off the top of stack. */
325 ctl_stack = ctl_stack->down;
330 /* Performs transformation 1. */
332 loop_1_trns_proc (struct trns_header * trns, struct ccase * c,
335 struct loop_1_trns *one = (struct loop_1_trns *) trns;
336 struct loop_2_trns *two = one->two;
339 if (two->flags & LPC_INDEX)
343 t1 = expr_evaluate_num (one->init, c, case_num);
345 t2 = expr_evaluate_num (one->incr, c, case_num);
348 t3 = expr_evaluate_num (one->term, c, case_num);
350 /* Even if the loop is never entered, force the index variable
351 to assume the initial value. */
352 case_data_rw (c, two->index->fv)->f = t1;
354 /* Throw out various pathological cases. */
355 if (!finite (t1) || !finite (t2) || !finite (t3) || t2 == 0.0)
356 return two->loop_term;
357 debug_printf (("LOOP %s=%g TO %g BY %g.\n", two->index->name,
361 /* Loop counts upward: I=1 TO 5 BY 1. */
362 two->flags &= ~LPC_RINDEX;
364 /* incr>0 but init>term */
366 return two->loop_term;
370 /* Loop counts downward: I=5 TO 1 BY -1. */
371 two->flags |= LPC_RINDEX;
373 /* incr<0 but init<term */
375 return two->loop_term;
386 /* Frees transformation 1. */
388 loop_1_trns_free (struct trns_header * trns)
390 struct loop_1_trns *one = (struct loop_1_trns *) trns;
392 expr_free (one->init);
393 expr_free (one->incr);
394 expr_free (one->term);
397 /* Performs transformation 2. */
399 loop_2_trns_proc (struct trns_header * trns, struct ccase * c,
402 struct loop_2_trns *two = (struct loop_2_trns *) trns;
404 /* MXLOOPS limiter. */
408 if (two->pass > get_mxloops() )
409 return two->loop_term;
412 /* Indexing clause limiter: counting downward. */
413 if (two->flags & LPC_RINDEX)
415 /* Test if we're at the end of the looping. */
416 if (two->curr < two->term)
417 return two->loop_term;
419 /* Set the current value into the case. */
420 case_data_rw (c, two->index->fv)->f = two->curr;
422 /* Decrement the current value. */
423 two->curr += two->incr;
425 /* Indexing clause limiter: counting upward. */
426 else if (two->flags & LPC_INDEX)
428 /* Test if we're at the end of the looping. */
429 if (two->curr > two->term)
430 return two->loop_term;
432 /* Set the current value into the case. */
433 case_data_rw (c, two->index->fv)->f = two->curr;
435 /* Increment the current value. */
436 two->curr += two->incr;
439 /* Conditional clause limiter. */
440 if ((two->flags & LPC_COND)
441 && expr_evaluate_num (two->cond, c, case_num) != 1.0)
442 return two->loop_term;
447 /* Frees transformation 2. */
449 loop_2_trns_free (struct trns_header * trns)
451 struct loop_2_trns *two = (struct loop_2_trns *) trns;
453 expr_free (two->cond);
456 /* Performs transformation 3. */
458 loop_3_trns_proc (struct trns_header * trns, struct ccase * c,
461 struct loop_3_trns *thr = (struct loop_3_trns *) trns;
463 /* Note that it breaks out of the loop if the expression is true *or
464 missing*. This is conformant. */
465 if (thr->cond && expr_evaluate_num (two->cond, c, case_num) != 0.0)
468 return thr->loop_start;
471 /* Frees transformation 3. */
473 loop_3_trns_free (struct trns_header * trns)
475 struct loop_3_trns *thr = (struct loop_3_trns *) trns;
477 expr_free (thr->cond);
482 /* Parses the BREAK command. */
486 /* Climbs down the stack to find a LOOP. */
487 struct ctl_stmt *loop;
489 /* New transformation. */
490 struct break_trns *t;
492 for (loop = ctl_stack; loop; loop = loop->down)
493 if (loop->type == CST_LOOP)
497 msg (SE, _("This command may only appear enclosed in a LOOP/"
498 "END LOOP control structure."));
502 if (ctl_stack->type != CST_DO_IF)
503 msg (SW, _("BREAK not enclosed in DO IF structure."));
505 t = xmalloc (sizeof *t);
506 t->h.proc = break_trns_proc;
510 add_transformation ((struct trns_header *) t);
512 return lex_end_of_command ();
516 break_trns_proc (struct trns_header * trns, struct ccase * c UNUSED,
519 return ((struct break_trns *) trns)->loop_term;
522 /* Control stack operations. */
524 /* Pops the top of stack element off of ctl_stack. Does not
525 check that ctl_stack is indeed non-NULL. */
529 switch (ctl_stack->type)
533 /* Pointer for chasing down and backpatching BREAKs. */
534 struct break_trns *brk;
536 /* Terminate the loop. */
537 thr = xmalloc (sizeof *thr);
538 thr->h.proc = loop_3_trns_proc;
539 thr->h.free = loop_3_trns_free;
541 thr->loop_start = ((struct loop_2_trns *) ctl_stack->trns)->h.index;
542 add_transformation ((struct trns_header *) thr);
545 ((struct loop_2_trns *) ctl_stack->trns)->loop_term = n_trns;
546 for (brk = ctl_stack->brk; brk; brk = brk->next)
547 brk->loop_term = n_trns;
553 struct do_if_trns *iter;
555 iter = ((struct do_if_trns *) ctl_stack->trns);
559 iter->brk->dest = n_trns;
560 iter->missing_jump = n_trns;
566 iter->false_jump = n_trns;
572 ctl_stack = ctl_stack->down;
575 /* Checks for unclosed LOOPs and DO IFs and closes them out. */
577 discard_ctl_stack (void)
581 msg (SE, _("%s without %s."), ctl_stack->type == CST_LOOP ? "LOOP" : "DO IF",
582 ctl_stack->type == CST_LOOP ? "END LOOP" : "END IF");