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
35 /* Target of a COMPUTE or IF assignment, either a variable or a
37 static struct lvalue *lvalue_parse (void);
38 static int lvalue_get_type (const struct lvalue *);
39 static int lvalue_is_vector (const struct lvalue *);
40 static void lvalue_finalize (struct lvalue *,
41 struct compute_trns *);
42 static void lvalue_destroy (struct lvalue *);
44 /* COMPUTE and IF transformation. */
49 /* Test expression (IF only). */
50 struct expression *test; /* Test expression. */
52 /* Variable lvalue, if variable != NULL. */
53 struct variable *variable; /* Destination variable, if any. */
54 int fv; /* `value' index of destination variable. */
55 int width; /* Lvalue string width; 0=numeric. */
57 /* Vector lvalue, if vector != NULL. */
58 const struct vector *vector; /* Destination vector, if any. */
59 struct expression *element; /* Destination vector element expr. */
62 struct expression *rvalue; /* Rvalue expression. */
65 static int parse_rvalue_expression (struct compute_trns *,
66 const struct lvalue *);
67 static struct compute_trns *compute_trns_create (void);
68 static void compute_trns_free (struct trns_header *);
75 struct lvalue *lvalue = NULL;
76 struct compute_trns *compute = NULL;
78 lex_match_id ("COMPUTE");
80 lvalue = lvalue_parse ();
84 compute = compute_trns_create ();
86 if (!lex_force_match ('=') || !parse_rvalue_expression (compute, lvalue))
89 lvalue_finalize (lvalue, compute);
91 add_transformation (&compute->h);
96 lvalue_destroy (lvalue);
99 compute_trns_free (&compute->h);
105 /* Transformation functions. */
108 compute_num (struct trns_header *compute_, struct ccase *c)
110 struct compute_trns *compute = (struct compute_trns *) compute_;
112 if (compute->test == NULL
113 || expr_evaluate (compute->test, c, NULL) == 1.0)
115 expr_evaluate (compute->rvalue, c, &c->data[compute->fv]);
122 compute_num_vec (struct trns_header *compute_, struct ccase *c)
124 struct compute_trns *compute = (struct compute_trns *) compute_;
126 if (compute->test == NULL
127 || expr_evaluate (compute->test, c, NULL) == 1.0)
129 /* Index into the vector. */
132 /* Rounded index value. */
135 expr_evaluate (compute->element, c, &index);
136 rindx = floor (index.f + EPSILON);
137 if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt)
139 if (index.f == SYSMIS)
140 msg (SW, _("When executing COMPUTE: SYSMIS is not a valid value as "
141 "an index into vector %s."), compute->vector->name);
143 msg (SW, _("When executing COMPUTE: %g is not a valid value as "
144 "an index into vector %s."),
145 index.f, compute->vector->name);
148 expr_evaluate (compute->rvalue, c,
149 &c->data[compute->vector->var[rindx - 1]->fv]);
156 compute_str (struct trns_header *compute_, struct ccase *c)
158 struct compute_trns *compute = (struct compute_trns *) compute_;
160 if (compute->test == NULL
161 || expr_evaluate (compute->test, c, NULL) == 1.0)
163 /* Temporary storage for string expression return value. */
166 expr_evaluate (compute->rvalue, c, &v);
167 st_bare_pad_len_copy (c->data[compute->fv].s, &v.c[1], compute->width,
175 compute_str_vec (struct trns_header *compute_, struct ccase *c)
177 struct compute_trns *compute = (struct compute_trns *) compute_;
179 if (compute->test == NULL
180 || expr_evaluate (compute->test, c, NULL) == 1.0)
182 /* Temporary storage for string expression return value. */
185 /* Index into the vector. */
188 /* Rounded index value. */
191 /* Variable reference by indexed vector. */
194 expr_evaluate (compute->element, c, &index);
195 rindx = floor (index.f + EPSILON);
196 if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt)
198 if (index.f == SYSMIS)
199 msg (SW, _("When executing COMPUTE: SYSMIS is not a valid "
200 "value as an index into vector %s."),
201 compute->vector->name);
203 msg (SW, _("When executing COMPUTE: %g is not a valid value as "
204 "an index into vector %s."),
205 index.f, compute->vector->name);
209 expr_evaluate (compute->rvalue, c, &v);
210 vr = compute->vector->var[rindx - 1];
211 st_bare_pad_len_copy (c->data[vr->fv].s, &v.c[1], vr->width, v.c[0]);
222 struct compute_trns *compute = NULL;
223 struct lvalue *lvalue = NULL;
226 compute = compute_trns_create ();
228 /* Test expression. */
229 compute->test = expr_parse (PXP_BOOLEAN);
230 if (compute->test == NULL)
233 /* Lvalue variable. */
234 lvalue = lvalue_parse ();
238 /* Rvalue expression. */
239 if (!lex_force_match ('=') || !parse_rvalue_expression (compute, lvalue))
242 lvalue_finalize (lvalue, compute);
244 add_transformation (&compute->h);
249 lvalue_destroy (lvalue);
252 compute_trns_free (&compute->h);
258 /* Code common to COMPUTE and IF. */
260 /* Checks for type mismatches on transformation C. Also checks for
261 command terminator, sets the case-handling proc from the array
264 parse_rvalue_expression (struct compute_trns *compute,
265 const struct lvalue *lvalue)
267 int type = lvalue_get_type (lvalue);
268 int vector = lvalue_is_vector (lvalue);
270 assert (type == NUMERIC || type == ALPHA);
272 compute->rvalue = expr_parse (type == ALPHA ? PXP_STRING : PXP_NUMERIC);
273 if (compute->rvalue == NULL)
277 compute->h.proc = vector ? compute_num_vec : compute_num;
279 compute->h.proc = vector ? compute_str_vec : compute_str;
283 lex_error (_("expecting end of command"));
290 /* Returns a new struct compute_trns after initializing its fields. */
291 static struct compute_trns *
292 compute_trns_create (void)
294 struct compute_trns *compute = xmalloc (sizeof *compute);
295 compute->h.proc = NULL;
296 compute->h.free = compute_trns_free;
297 compute->test = NULL;
298 compute->variable = NULL;
299 compute->vector = NULL;
300 compute->element = NULL;
301 compute->rvalue = NULL;
305 /* Deletes all the fields in COMPUTE. */
307 compute_trns_free (struct trns_header *compute_)
309 struct compute_trns *compute = (struct compute_trns *) compute_;
311 expr_free (compute->test);
312 expr_free (compute->element);
313 expr_free (compute->rvalue);
318 char var_name[9]; /* Destination variable name, or "". */
319 const struct vector *vector; /* Destination vector, if any, or NULL. */
320 struct expression *element; /* Destination vector element, or NULL. */
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 (PXP_NUMERIC);
351 if (lvalue->element == NULL)
353 if (!lex_force_match (')'))
359 strncpy (lvalue->var_name, tokid, 8);
360 lvalue->var_name[8] = '\0';
366 lvalue_destroy (lvalue);
371 lvalue_get_type (const struct lvalue *lvalue)
373 if (lvalue->vector == NULL)
376 = dict_lookup_var (default_dict, lvalue->var_name);
383 return lvalue->vector->var[0]->type;
387 lvalue_is_vector (const struct lvalue *lvalue)
389 return lvalue->vector != NULL;
393 lvalue_finalize (struct lvalue *lvalue,
394 struct compute_trns *compute)
396 if (lvalue->vector == NULL)
398 compute->variable = dict_lookup_var (default_dict, lvalue->var_name);
399 if (compute->variable == NULL)
401 struct fmt_spec input_spec = { 0,8,2 };
402 compute->variable = dict_create_var_assert (default_dict,
403 lvalue->var_name, 0);
405 convert_fmt_ItoO (&input_spec, &compute->variable->print);
406 compute->variable->write = compute->variable->print;
409 compute->fv = compute->variable->fv;
410 compute->width = compute->variable->width;
414 /* Goofy behavior, but compatible: Turn off LEAVE. */
415 if (dict_class_from_id (compute->variable->name) != DC_SCRATCH)
416 compute->variable->reinit = 1;
420 compute->vector = lvalue->vector;
421 compute->element = lvalue->element;
422 lvalue->element = NULL;
425 lvalue_destroy (lvalue);
429 lvalue_destroy (struct lvalue *lvalue)
431 expr_free (lvalue->element);
440 struct expression *expr;
442 lex_match_id ("EVALUATE");
443 expr = expr_parse (PXP_DUMP);
450 msg (SE, _("Extra characters after expression."));