Fix rest of PR 13054.
[pspp] / src / expressions / evaluate.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
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.
9
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.
14
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
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "private.h"
22
23 #if TIME_WITH_SYS_TIME
24 #include <sys/time.h>
25 #include <time.h>
26 #else
27 #if HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #else
30 #include <time.h>
31 #endif
32 #endif
33
34 #include <ctype.h>
35 #include "alloc.h"
36 #include "error.h"
37 #include "helpers.h"
38 #include "evaluate.h"
39 #include "pool.h"
40
41 static void
42 expr_evaluate (struct expression *e, const struct ccase *c, int case_idx,
43                void *result)
44 {
45   union operation_data *op = e->ops;
46
47   double *ns = e->number_stack;
48   struct fixed_string *ss = e->string_stack;
49
50   assert ((c != NULL) == (e->dict != NULL));
51   pool_clear (e->eval_pool);
52
53   for (;;)
54     {
55       assert (op < e->ops + e->op_cnt);
56       switch (op++->operation)
57         {
58         case OP_number:
59         case OP_boolean:
60           *ns++ = op++->number;
61           break;
62
63         case OP_string:
64           {
65             const struct fixed_string *s = &op++->string;
66             *ss++ = copy_string (e, s->string, s->length);
67           }
68           break;
69
70         case OP_return_number:
71           *(double *) result = finite (ns[-1]) ? ns[-1] : SYSMIS;
72           return;
73
74         case OP_return_string:
75           *(struct fixed_string *) result = ss[-1];
76           return;
77
78 #include "evaluate.inc"
79           
80         default:
81           abort ();
82         }
83     }
84 }
85
86 double
87 expr_evaluate_num (struct expression *e, const struct ccase *c, int case_idx)
88 {
89   double d;
90
91   assert (e->type == OP_number || e->type == OP_boolean);
92   expr_evaluate (e, c, case_idx, &d);
93   return d;
94 }
95
96 void
97 expr_evaluate_str (struct expression *e, const struct ccase *c, int case_idx,
98                    char *dst, size_t dst_size) 
99 {
100   struct fixed_string s;
101
102   assert (e->type == OP_string);
103   assert ((dst == NULL) == (dst_size == 0));
104   expr_evaluate (e, c, case_idx, &s);
105   buf_copy_rpad (dst, dst_size, s.string, s.length);
106 }
107 \f
108 #include "lexer.h"
109 #include "command.h"
110
111 int
112 cmd_debug_evaluate (void)
113 {
114   bool optimize = true;
115   int retval = CMD_FAILURE;
116   bool dump_postfix = false;
117   struct dictionary *d = NULL;
118   struct ccase *c = NULL;
119
120   struct expression *expr;
121
122   for (;;) 
123     {
124       if (lex_match_id ("NOOPTIMIZE"))
125         optimize = 0;
126       else if (lex_match_id ("POSTFIX"))
127         dump_postfix = 1;
128       else if (lex_match ('('))
129         {
130           char name[LONG_NAME_LEN + 1];
131           struct variable *v;
132           size_t old_value_cnt;
133           int width;
134
135           if (!lex_force_id ())
136             goto done;
137           strcpy (name, tokid);
138
139           lex_get ();
140           if (!lex_force_match ('='))
141             goto done;
142
143           if (lex_is_number ())
144             {
145               width = 0;
146               fprintf (stderr, "(%s = %.2f)", name, tokval); 
147             }
148           else if (token == T_STRING) 
149             {
150               width = ds_length (&tokstr);
151               fprintf (stderr, "(%s = \"%.2s\")", name, ds_c_str (&tokstr)); 
152             }
153           else
154             {
155               lex_error (_("expecting number or string"));
156               goto done;
157             }
158
159           if (d == NULL)
160             d = dict_create ();
161           
162           old_value_cnt = dict_get_next_value_idx (d);
163           v = dict_create_var (d, name, width);
164           if (v == NULL)
165             {
166               msg (SE, _("Duplicate variable name %s."), name);
167               goto done;
168             }
169
170           if (c == NULL) 
171             {
172               c = xmalloc (sizeof *c);
173               case_nullify (c);
174             }
175           case_resize (c, old_value_cnt, dict_get_next_value_idx (d));
176
177           if (lex_is_number ())
178             case_data_rw (c, v->fv)->f = tokval;
179           else
180             memcpy (case_data_rw (c, v->fv)->s, ds_data (&tokstr),
181                     v->width);
182           lex_get ();
183
184           if (!lex_force_match (')'))
185             goto done;
186         }
187       else 
188         break;
189     }
190   if (token != '/') 
191     {
192       lex_force_match ('/');
193       goto done;
194     }
195   if (d != NULL)
196     fprintf (stderr, "; ");
197   fprintf (stderr, "%s => ", lex_rest_of_line (NULL));
198   lex_get ();
199
200   expr = expr_parse_any (d, optimize);
201   if (!expr || lex_end_of_command () != CMD_SUCCESS)
202     {
203       if (expr != NULL)
204         expr_free (expr);
205       fprintf (stderr, "error\n");
206       goto done;
207     }
208
209   if (dump_postfix) 
210     expr_debug_print_postfix (expr);
211   else 
212     switch (expr->type) 
213       {
214       case OP_number: 
215         {
216           double d = expr_evaluate_num (expr, c, 0);
217           if (d == SYSMIS)
218             fprintf (stderr, "sysmis\n");
219           else
220             fprintf (stderr, "%.2f\n", d); 
221         }
222         break;
223       
224       case OP_boolean: 
225         {
226           double b = expr_evaluate_num (expr, c, 0);
227           fprintf (stderr, "%s\n",
228                    b == SYSMIS ? "sysmis" : b == 0.0 ? "false" : "true"); 
229         }
230         break;
231
232       case OP_string: 
233         {
234           struct fixed_string s;
235           expr_evaluate (expr, c, 0, &s);
236
237           fputc ('"', stderr);
238           fwrite (s.string, s.length, 1, stderr);
239           fputs ("\"\n", stderr);
240           break; 
241         }
242
243       default:
244         assert (0);
245       }
246
247   expr_free (expr);
248   retval = CMD_SUCCESS;
249
250  done:
251   if (c != NULL) 
252     {
253       case_destroy (c);
254       free (c); 
255     }
256   dict_destroy (d);
257   return retval;
258 }
259
260 void
261 expr_debug_print_postfix (const struct expression *e) 
262 {
263   size_t i;
264
265   for (i = 0; i < e->op_cnt; i++) 
266     {
267       union operation_data *op = &e->ops[i];
268       if (i > 0)
269         putc (' ', stderr);
270       switch (e->op_types[i]) 
271         {
272         case OP_operation:
273           if (op->operation == OP_return_number)
274             fprintf (stderr, "return_number");
275           else if (op->operation == OP_return_string)
276             fprintf (stderr, "return_string");
277           else if (is_function (op->operation)) 
278             fprintf (stderr, "%s", operations[op->operation].prototype);
279           else if (is_composite (op->operation)) 
280             fprintf (stderr, "%s", operations[op->operation].name);
281           else
282             fprintf (stderr, "%s:", operations[op->operation].name);
283           break;
284         case OP_number:
285           if (op->number != SYSMIS)
286             fprintf (stderr, "n<%g>", op->number);
287           else
288             fprintf (stderr, "n<SYSMIS>");
289           break;
290         case OP_string:
291           fprintf (stderr, "s<%.*s>",
292                    (int) op->string.length, op->string.string);
293           break;
294         case OP_format:
295           fprintf (stderr, "f<%s%d.%d>",
296                   formats[op->format->type].name,
297                   op->format->w, op->format->d);
298           break;
299         case OP_variable:
300           fprintf (stderr, "v<%s>", op->variable->name);
301           break;
302         case OP_vector:
303           fprintf (stderr, "vec<%s>", op->vector->name);
304           break;
305         case OP_integer:
306           fprintf (stderr, "i<%d>", op->integer);
307           break;
308         default:
309           abort ();
310         } 
311     }
312   fprintf (stderr, "\n");
313 }