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
26 #include "dictionary.h"
28 #include "expressions/public.h"
35 #define _(msgid) gettext (msgid)
40 /* Target of a COMPUTE or IF assignment, either a variable or a
42 static struct lvalue *lvalue_parse (void);
43 static int lvalue_get_type (const struct lvalue *);
44 static int lvalue_is_vector (const struct lvalue *);
45 static void lvalue_finalize (struct lvalue *,
46 struct compute_trns *);
47 static void lvalue_destroy (struct lvalue *);
49 /* COMPUTE and IF transformation. */
54 /* Test expression (IF only). */
55 struct expression *test; /* Test expression. */
57 /* Variable lvalue, if variable != NULL. */
58 struct variable *variable; /* Destination variable, if any. */
59 int fv; /* `value' index of destination variable. */
60 int width; /* Lvalue string width; 0=numeric. */
62 /* Vector lvalue, if vector != NULL. */
63 const struct vector *vector; /* Destination vector, if any. */
64 struct expression *element; /* Destination vector element expr. */
67 struct expression *rvalue; /* Rvalue expression. */
70 static int parse_rvalue_expression (struct compute_trns *,
71 const struct lvalue *);
72 static struct compute_trns *compute_trns_create (void);
73 static void compute_trns_free (struct trns_header *);
80 struct lvalue *lvalue = NULL;
81 struct compute_trns *compute = NULL;
83 lvalue = lvalue_parse ();
87 compute = compute_trns_create ();
89 if (!lex_force_match ('=') || !parse_rvalue_expression (compute, lvalue))
92 lvalue_finalize (lvalue, compute);
94 add_transformation (&compute->h);
99 lvalue_destroy (lvalue);
102 compute_trns_free (&compute->h);
108 /* Transformation functions. */
110 /* Handle COMPUTE or IF with numeric target variable. */
112 compute_num (struct trns_header *compute_, struct ccase *c,
115 struct compute_trns *compute = (struct compute_trns *) compute_;
117 if (compute->test == NULL
118 || expr_evaluate_num (compute->test, c, case_num) == 1.0)
119 case_data_rw (c, compute->fv)->f = expr_evaluate_num (compute->rvalue, c,
125 /* Handle COMPUTE or IF with numeric vector element target
128 compute_num_vec (struct trns_header *compute_, struct ccase *c,
131 struct compute_trns *compute = (struct compute_trns *) compute_;
133 if (compute->test == NULL
134 || expr_evaluate_num (compute->test, c, case_num) == 1.0)
136 double index; /* Index into the vector. */
137 int rindx; /* Rounded index value. */
139 index = expr_evaluate_num (compute->element, c, case_num);
140 rindx = floor (index + EPSILON);
141 if (index == SYSMIS || rindx < 1 || rindx > compute->vector->cnt)
144 msg (SW, _("When executing COMPUTE: SYSMIS is not a valid value as "
145 "an index into vector %s."), compute->vector->name);
147 msg (SW, _("When executing COMPUTE: %g is not a valid value as "
148 "an index into vector %s."),
149 index, compute->vector->name);
152 case_data_rw (c, compute->vector->var[rindx - 1]->fv)->f
153 = expr_evaluate_num (compute->rvalue, c, case_num);
159 /* Handle COMPUTE or IF with string target variable. */
161 compute_str (struct trns_header *compute_, struct ccase *c,
164 struct compute_trns *compute = (struct compute_trns *) compute_;
166 if (compute->test == NULL
167 || expr_evaluate_num (compute->test, c, case_num) == 1.0)
168 expr_evaluate_str (compute->rvalue, c, case_num,
169 case_data_rw (c, compute->fv)->s, compute->width);
174 /* Handle COMPUTE or IF with string vector element target
177 compute_str_vec (struct trns_header *compute_, struct ccase *c,
180 struct compute_trns *compute = (struct compute_trns *) compute_;
182 if (compute->test == NULL
183 || expr_evaluate_num (compute->test, c, case_num) == 1.0)
185 double index; /* Index into the vector. */
186 int rindx; /* Rounded index value. */
187 struct variable *vr; /* Variable reference by indexed vector. */
189 index = expr_evaluate_num (compute->element, c, case_num);
190 rindx = floor (index + EPSILON);
193 msg (SW, _("When executing COMPUTE: SYSMIS is not a valid "
194 "value as an index into vector %s."),
195 compute->vector->name);
198 else if (rindx < 1 || rindx > compute->vector->cnt)
200 msg (SW, _("When executing COMPUTE: %g is not a valid value as "
201 "an index into vector %s."),
202 index, compute->vector->name);
206 vr = compute->vector->var[rindx - 1];
207 expr_evaluate_str (compute->rvalue, c, case_num,
208 case_data_rw (c, vr->fv)->s, vr->width);
219 struct compute_trns *compute = NULL;
220 struct lvalue *lvalue = NULL;
222 compute = compute_trns_create ();
224 /* Test expression. */
225 compute->test = expr_parse (default_dict, EXPR_BOOLEAN);
226 if (compute->test == NULL)
229 /* Lvalue variable. */
230 lvalue = lvalue_parse ();
234 /* Rvalue expression. */
235 if (!lex_force_match ('=') || !parse_rvalue_expression (compute, lvalue))
238 lvalue_finalize (lvalue, compute);
240 add_transformation (&compute->h);
245 lvalue_destroy (lvalue);
248 compute_trns_free (&compute->h);
254 /* Code common to COMPUTE and IF. */
256 /* Checks for type mismatches on transformation C. Also checks for
257 command terminator, sets the case-handling proc from the array
260 parse_rvalue_expression (struct compute_trns *compute,
261 const struct lvalue *lvalue)
263 int type = lvalue_get_type (lvalue);
264 int vector = lvalue_is_vector (lvalue);
266 assert (type == NUMERIC || type == ALPHA);
268 compute->rvalue = expr_parse (default_dict,
269 type == ALPHA ? EXPR_STRING : EXPR_NUMBER);
270 if (compute->rvalue == NULL)
274 compute->h.proc = vector ? compute_num_vec : compute_num;
276 compute->h.proc = vector ? compute_str_vec : compute_str;
280 lex_error (_("expecting end of command"));
287 /* Returns a new struct compute_trns after initializing its fields. */
288 static struct compute_trns *
289 compute_trns_create (void)
291 struct compute_trns *compute = xmalloc (sizeof *compute);
292 compute->h.proc = NULL;
293 compute->h.free = compute_trns_free;
294 compute->test = NULL;
295 compute->variable = NULL;
296 compute->vector = NULL;
297 compute->element = NULL;
298 compute->rvalue = NULL;
302 /* Deletes all the fields in COMPUTE. */
304 compute_trns_free (struct trns_header *compute_)
306 struct compute_trns *compute = (struct compute_trns *) compute_;
308 expr_free (compute->test);
309 expr_free (compute->element);
310 expr_free (compute->rvalue);
313 /* COMPUTE or IF target variable or vector element. */
316 char var_name[LONG_NAME_LEN + 1]; /* Destination variable name, or "". */
317 const struct vector *vector; /* Destination vector, if any, or NULL. */
318 struct expression *element; /* Destination vector element, or NULL. */
321 /* Parses the target variable or vector element into a new
322 `struct lvalue', which is returned. */
323 static struct lvalue *
326 struct lvalue *lvalue;
328 lvalue = xmalloc (sizeof *lvalue);
329 lvalue->var_name[0] = '\0';
330 lvalue->vector = NULL;
331 lvalue->element = NULL;
333 if (!lex_force_id ())
336 if (lex_look_ahead () == '(')
339 lvalue->vector = dict_lookup_vector (default_dict, tokid);
340 if (lvalue->vector == NULL)
342 msg (SE, _("There is no vector named %s."), tokid);
346 /* Vector element. */
348 if (!lex_force_match ('('))
350 lvalue->element = expr_parse (default_dict, EXPR_NUMBER);
351 if (lvalue->element == NULL)
353 if (!lex_force_match (')'))
359 str_copy_trunc (lvalue->var_name, sizeof lvalue->var_name, tokid);
365 lvalue_destroy (lvalue);
369 /* Returns the type (NUMERIC or ALPHA) of the target variable or
372 lvalue_get_type (const struct lvalue *lvalue)
374 if (lvalue->vector == NULL)
376 struct variable *var = dict_lookup_var (default_dict, lvalue->var_name);
383 return lvalue->vector->var[0]->type;
386 /* Returns nonzero if LVALUE has a vector as its target. */
388 lvalue_is_vector (const struct lvalue *lvalue)
390 return lvalue->vector != NULL;
393 /* Finalizes making LVALUE the target of COMPUTE, by creating the
394 target variable if necessary and setting fields in COMPUTE. */
396 lvalue_finalize (struct lvalue *lvalue,
397 struct compute_trns *compute)
399 if (lvalue->vector == NULL)
401 compute->variable = dict_lookup_var (default_dict, lvalue->var_name);
402 if (compute->variable == NULL)
403 compute->variable = dict_create_var_assert (default_dict,
404 lvalue->var_name, 0);
406 compute->fv = compute->variable->fv;
407 compute->width = compute->variable->width;
409 /* Goofy behavior, but compatible: Turn off LEAVE. */
410 if (dict_class_from_id (compute->variable->name) != DC_SCRATCH)
411 compute->variable->reinit = 1;
415 compute->vector = lvalue->vector;
416 compute->element = lvalue->element;
417 lvalue->element = NULL;
420 lvalue_destroy (lvalue);
423 /* Destroys LVALUE. */
425 lvalue_destroy (struct lvalue *lvalue)
430 expr_free (lvalue->element);