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
26 #include "dictionary.h"
37 /* Target of a COMPUTE or IF assignment, either a variable or a
39 static struct lvalue *lvalue_parse (void);
40 static int lvalue_get_type (const struct lvalue *);
41 static int lvalue_is_vector (const struct lvalue *);
42 static void lvalue_finalize (struct lvalue *,
43 struct compute_trns *);
44 static void lvalue_destroy (struct lvalue *);
46 /* COMPUTE and IF transformation. */
51 /* Test expression (IF only). */
52 struct expression *test; /* Test expression. */
54 /* Variable lvalue, if variable != NULL. */
55 struct variable *variable; /* Destination variable, if any. */
56 int fv; /* `value' index of destination variable. */
57 int width; /* Lvalue string width; 0=numeric. */
59 /* Vector lvalue, if vector != NULL. */
60 const struct vector *vector; /* Destination vector, if any. */
61 struct expression *element; /* Destination vector element expr. */
64 struct expression *rvalue; /* Rvalue expression. */
67 static int parse_rvalue_expression (struct compute_trns *,
68 const struct lvalue *);
69 static struct compute_trns *compute_trns_create (void);
70 static void compute_trns_free (struct trns_header *);
77 struct lvalue *lvalue = NULL;
78 struct compute_trns *compute = NULL;
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. */
107 /* Handle COMPUTE or IF with numeric target variable. */
109 compute_num (struct trns_header *compute_, struct ccase *c,
112 struct compute_trns *compute = (struct compute_trns *) compute_;
114 if (compute->test == NULL
115 || expr_evaluate (compute->test, c, case_num, NULL) == 1.0)
117 expr_evaluate (compute->rvalue, c, case_num,
118 case_data_rw (c, compute->fv));
124 /* Handle COMPUTE or IF with numeric vector element target
127 compute_num_vec (struct trns_header *compute_, struct ccase *c,
130 struct compute_trns *compute = (struct compute_trns *) compute_;
132 if (compute->test == NULL
133 || expr_evaluate (compute->test, c, case_num, NULL) == 1.0)
135 /* Index into the vector. */
138 /* Rounded index value. */
141 expr_evaluate (compute->element, c, case_num, &index);
142 rindx = floor (index.f + EPSILON);
143 if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt)
145 if (index.f == SYSMIS)
146 msg (SW, _("When executing COMPUTE: SYSMIS is not a valid value as "
147 "an index into vector %s."), compute->vector->name);
149 msg (SW, _("When executing COMPUTE: %g is not a valid value as "
150 "an index into vector %s."),
151 index.f, compute->vector->name);
154 expr_evaluate (compute->rvalue, c, case_num,
155 case_data_rw (c, compute->vector->var[rindx - 1]->fv));
161 /* Handle COMPUTE or IF with string target variable. */
163 compute_str (struct trns_header *compute_, struct ccase *c,
166 struct compute_trns *compute = (struct compute_trns *) compute_;
168 if (compute->test == NULL
169 || expr_evaluate (compute->test, c, case_num, NULL) == 1.0)
171 /* Temporary storage for string expression return value. */
174 expr_evaluate (compute->rvalue, c, case_num, &v);
175 st_bare_pad_len_copy (case_data_rw (c, compute->fv)->s,
176 &v.c[1], compute->width, v.c[0]);
182 /* Handle COMPUTE or IF with string vector element target
185 compute_str_vec (struct trns_header *compute_, struct ccase *c,
188 struct compute_trns *compute = (struct compute_trns *) compute_;
190 if (compute->test == NULL
191 || expr_evaluate (compute->test, c, case_num, NULL) == 1.0)
193 /* Temporary storage for string expression return value. */
196 /* Index into the vector. */
199 /* Rounded index value. */
202 /* Variable reference by indexed vector. */
205 expr_evaluate (compute->element, c, case_num, &index);
206 rindx = floor (index.f + EPSILON);
207 if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt)
209 if (index.f == SYSMIS)
210 msg (SW, _("When executing COMPUTE: SYSMIS is not a valid "
211 "value as an index into vector %s."),
212 compute->vector->name);
214 msg (SW, _("When executing COMPUTE: %g is not a valid value as "
215 "an index into vector %s."),
216 index.f, compute->vector->name);
220 expr_evaluate (compute->rvalue, c, case_num, &v);
221 vr = compute->vector->var[rindx - 1];
222 st_bare_pad_len_copy (case_data_rw (c, vr->fv)->s,
223 &v.c[1], vr->width, v.c[0]);
234 struct compute_trns *compute = NULL;
235 struct lvalue *lvalue = NULL;
237 compute = compute_trns_create ();
239 /* Test expression. */
240 compute->test = expr_parse (EXPR_BOOLEAN);
241 if (compute->test == NULL)
244 /* Lvalue variable. */
245 lvalue = lvalue_parse ();
249 /* Rvalue expression. */
250 if (!lex_force_match ('=') || !parse_rvalue_expression (compute, lvalue))
253 lvalue_finalize (lvalue, compute);
255 add_transformation (&compute->h);
260 lvalue_destroy (lvalue);
263 compute_trns_free (&compute->h);
269 /* Code common to COMPUTE and IF. */
271 /* Checks for type mismatches on transformation C. Also checks for
272 command terminator, sets the case-handling proc from the array
275 parse_rvalue_expression (struct compute_trns *compute,
276 const struct lvalue *lvalue)
278 int type = lvalue_get_type (lvalue);
279 int vector = lvalue_is_vector (lvalue);
281 assert (type == NUMERIC || type == ALPHA);
283 compute->rvalue = expr_parse (type == ALPHA ? EXPR_STRING : EXPR_NUMERIC);
284 if (compute->rvalue == NULL)
288 compute->h.proc = vector ? compute_num_vec : compute_num;
290 compute->h.proc = vector ? compute_str_vec : compute_str;
294 lex_error (_("expecting end of command"));
301 /* Returns a new struct compute_trns after initializing its fields. */
302 static struct compute_trns *
303 compute_trns_create (void)
305 struct compute_trns *compute = xmalloc (sizeof *compute);
306 compute->h.proc = NULL;
307 compute->h.free = compute_trns_free;
308 compute->test = NULL;
309 compute->variable = NULL;
310 compute->vector = NULL;
311 compute->element = NULL;
312 compute->rvalue = NULL;
316 /* Deletes all the fields in COMPUTE. */
318 compute_trns_free (struct trns_header *compute_)
320 struct compute_trns *compute = (struct compute_trns *) compute_;
322 expr_free (compute->test);
323 expr_free (compute->element);
324 expr_free (compute->rvalue);
327 /* COMPUTE or IF target variable or vector element. */
330 char var_name[9]; /* Destination variable name, or "". */
331 const struct vector *vector; /* Destination vector, if any, or NULL. */
332 struct expression *element; /* Destination vector element, or NULL. */
335 /* Parses the target variable or vector elector into a new
336 `struct lvalue', which is returned. */
337 static struct lvalue *
340 struct lvalue *lvalue;
342 lvalue = xmalloc (sizeof *lvalue);
343 lvalue->var_name[0] = '\0';
344 lvalue->vector = NULL;
345 lvalue->element = NULL;
347 if (!lex_force_id ())
350 if (lex_look_ahead () == '(')
353 lvalue->vector = dict_lookup_vector (default_dict, tokid);
354 if (lvalue->vector == NULL)
356 msg (SE, _("There is no vector named %s."), tokid);
360 /* Vector element. */
362 if (!lex_force_match ('('))
364 lvalue->element = expr_parse (EXPR_NUMERIC);
365 if (lvalue->element == NULL)
367 if (!lex_force_match (')'))
373 strncpy (lvalue->var_name, tokid, 8);
374 lvalue->var_name[8] = '\0';
380 lvalue_destroy (lvalue);
384 /* Returns the type (NUMERIC or ALPHA) of the target variable or
387 lvalue_get_type (const struct lvalue *lvalue)
389 if (lvalue->vector == NULL)
392 = dict_lookup_var (default_dict, lvalue->var_name);
399 return lvalue->vector->var[0]->type;
402 /* Returns nonzero if LVALUE has a vector as its target. */
404 lvalue_is_vector (const struct lvalue *lvalue)
406 return lvalue->vector != NULL;
409 /* Finalizes making LVALUE the target of COMPUTE, by creating the
410 target variable if necessary and setting fields in COMPUTE. */
412 lvalue_finalize (struct lvalue *lvalue,
413 struct compute_trns *compute)
415 if (lvalue->vector == NULL)
417 compute->variable = dict_lookup_var (default_dict, lvalue->var_name);
418 if (compute->variable == NULL)
419 compute->variable = dict_create_var_assert (default_dict,
420 lvalue->var_name, 0);
422 compute->fv = compute->variable->fv;
423 compute->width = compute->variable->width;
425 /* Goofy behavior, but compatible: Turn off LEAVE. */
426 if (dict_class_from_id (compute->variable->name) != DC_SCRATCH)
427 compute->variable->reinit = 1;
431 compute->vector = lvalue->vector;
432 compute->element = lvalue->element;
433 lvalue->element = NULL;
436 lvalue_destroy (lvalue);
439 /* Destroys LVALUE. */
441 lvalue_destroy (struct lvalue *lvalue)
443 expr_free (lvalue->element);