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
32 /*#define DEBUGGING 1*/
33 #include "debug-print.h"
40 /* Description of DO IF transformations:
42 DO IF has two transformations. One is a conditional jump around
43 a false condition. The second is an unconditional jump around
44 the rest of the code after a true condition. Both of these types
45 have their destinations backpatched in by the next clause (ELSE IF,
48 The characters `^V<>' are meant to represent arrows.
53 V *. Transformations executed when the condition on DO IF is true.
55 V 2. GOTO>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>V
60 V *. Transformations executed when condition on 1st ELSE IF is true. V
62 V 2. GOTO>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>V
67 V *. Transformations executed when condition on 2nd ELSE IF is true. V
69 V 2. GOTO>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>V
71 >>*. Transformations executed when no condition is true. (ELSE) V
73 *. Transformations after DO IF structure.<<<<<<<<<<<<<<<<<<<<<<<<<<<<
80 static struct do_if_trns *parse_do_if (void);
81 static void add_ELSE_IF (struct do_if_trns *);
82 static int goto_trns_proc (struct trns_header *, struct ccase *);
83 static int do_if_trns_proc (struct trns_header *, struct ccase *);
84 static void do_if_trns_free (struct trns_header *);
92 /* Parse the transformation. */
97 /* Finish up the transformation, add to control stack, add to
98 transformation list. */
100 t->ctl.type = CST_DO_IF;
101 t->ctl.down = ctl_stack;
102 t->ctl.trns = (struct trns_header *) t;
106 add_transformation ((struct trns_header *) t);
115 /* Transformation created. */
116 struct do_if_trns *t;
118 /* Check that we're in a pleasing situation. */
119 if (!ctl_stack || ctl_stack->type != CST_DO_IF)
121 msg (SE, _("There is no DO IF to match with this ELSE IF."));
124 if (((struct do_if_trns *) ctl_stack->trns)->has_else)
126 msg (SE, _("The ELSE command must follow all ELSE IF commands "
127 "in a DO IF structure."));
131 /* Parse the transformation. */
136 /* Stick in the breakout transformation. */
137 t->brk = xmalloc (sizeof *t->brk);
138 t->brk->h.proc = goto_trns_proc;
139 t->brk->h.free = NULL;
141 /* Add to list of transformations, add to string of ELSE IFs. */
142 add_transformation ((struct trns_header *) t->brk);
143 add_transformation ((struct trns_header *) t);
149 msg (SE, _("End of command expected."));
150 return CMD_TRAILING_GARBAGE;
160 struct do_if_trns *t;
162 lex_match_id ("ELSE");
164 /* Check that we're in a pleasing situation. */
165 if (!ctl_stack || ctl_stack->type != CST_DO_IF)
167 msg (SE, _("There is no DO IF to match with this ELSE."));
171 if (((struct do_if_trns *) ctl_stack->trns)->has_else)
173 msg (SE, _("There may be at most one ELSE clause in each DO IF "
174 "structure. It must be the last clause."));
178 /* Note that the ELSE transformation is *not* added to the list of
179 transformations. That's because it doesn't need to do anything.
180 Its goto transformation *is* added, because that's necessary.
181 The main DO IF do_if_trns is the destructor for this ELSE
183 t = xmalloc (sizeof *t);
185 t->brk = xmalloc (sizeof *t->brk);
186 t->brk->h.proc = goto_trns_proc;
187 t->brk->h.free = NULL;
189 add_transformation ((struct trns_header *) t->brk);
190 t->h.index = t->brk->h.index + 1;
192 /* Add to string of ELSE IFs. */
195 return lex_end_of_command ();
203 struct do_if_trns *iter;
207 /* Check that we're in a pleasing situation. */
208 if (!ctl_stack || ctl_stack->type != CST_DO_IF)
210 msg (SE, _("There is no DO IF to match with this END IF."));
214 /* Chain down the list, backpatching destinations for gotos. */
215 iter = (struct do_if_trns *) ctl_stack->trns;
219 iter->brk->dest = n_trns;
220 iter->missing_jump = n_trns;
226 iter->false_jump = n_trns;
228 /* Pop control stack. */
229 ctl_stack = ctl_stack->down;
231 return lex_end_of_command ();
234 /* Adds an ELSE IF or ELSE to the chain of them that hangs off the
237 add_ELSE_IF (struct do_if_trns * t)
240 struct do_if_trns *iter;
242 iter = (struct do_if_trns *) ctl_stack->trns;
245 assert (iter != NULL);
248 iter->false_jump = t->h.index;
251 /* Parses a DO IF or ELSE IF command and returns a pointer to a mostly
252 filled in transformation. */
253 static struct do_if_trns *
256 struct do_if_trns *t;
257 struct expression *e;
261 e = expr_parse (PXP_BOOLEAN);
267 lex_error (_("expecting end of command"));
271 t = xmalloc (sizeof *t);
272 t->h.proc = do_if_trns_proc;
273 t->h.free = do_if_trns_free;
280 /* Executes a goto transformation. */
282 goto_trns_proc (struct trns_header * t, struct ccase * c unused)
284 return ((struct goto_trns *) t)->dest;
288 do_if_trns_proc (struct trns_header * trns, struct ccase * c)
290 struct do_if_trns *t = (struct do_if_trns *) trns;
293 expr_evaluate (t->cond, c, &bool);
296 debug_printf ((_("DO IF %d: true\n"), t->h.index));
299 else if (bool.f == 0.0)
301 debug_printf ((_("DO IF %d: false\n"), t->h.index));
302 return t->false_jump;
306 debug_printf ((_("DO IF %d: missing\n"), t->h.index));
307 return t->missing_jump;
312 do_if_trns_free (struct trns_header * trns)
314 struct do_if_trns *t = (struct do_if_trns *) trns;
317 /* If brk is NULL then this is the main DO IF; therefore we
318 need to chain down to the ELSE and delete it. */
321 struct do_if_trns *iter = t->next;
326 /* This is the ELSE. */