d6d573848106b9fa8ca1bc8d4fc8ad9aa16659f4
[pspp] / src / language / expressions / evaluate.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "evaluate.h"
20
21 #include <ctype.h>
22
23 #include "libpspp/assertion.h"
24 #include "libpspp/message.h"
25 #include "language/expressions/helpers.h"
26 #include "language/expressions/private.h"
27 #include "language/lexer/value-parser.h"
28 #include "libpspp/pool.h"
29 #include "output/driver.h"
30
31 #include "xalloc.h"
32
33 static void
34 expr_evaluate (struct expression *e, const struct ccase *c, int case_idx,
35                void *result)
36 {
37   struct dataset *ds = e->ds;
38   union operation_data *op = e->ops;
39
40   double *ns = e->number_stack;
41   struct substring *ss = e->string_stack;
42
43   /* Without a dictionary/dataset, the expression can't refer to variables,
44      and you don't need to specify a case when you evaluate the
45      expression.  With a dictionary/dataset, the expression can refer
46      to variables, so you must specify a case when you evaluate the
47      expression. */
48   assert ((c != NULL) == (e->ds != NULL));
49
50   pool_clear (e->eval_pool);
51
52   for (;;)
53     {
54       assert (op < e->ops + e->op_cnt);
55       switch (op++->operation)
56         {
57         case OP_number:
58         case OP_boolean:
59           *ns++ = op++->number;
60           break;
61
62         case OP_string:
63           {
64             const struct substring *s = &op++->string;
65             *ss++ = copy_string (e, s->string, s->length);
66           }
67           break;
68
69         case OP_return_number:
70           *(double *) result = isfinite (ns[-1]) ? ns[-1] : SYSMIS;
71           return;
72
73         case OP_return_string:
74           *(struct substring *) result = ss[-1];
75           return;
76
77 #include "evaluate.inc"
78
79         default:
80           NOT_REACHED ();
81         }
82     }
83 }
84
85 double
86 expr_evaluate_num (struct expression *e, const struct ccase *c, int case_idx)
87 {
88   double d;
89
90   assert (e->type == OP_number || e->type == OP_boolean);
91   expr_evaluate (e, c, case_idx, &d);
92   return d;
93 }
94
95 void
96 expr_evaluate_str (struct expression *e, const struct ccase *c, int case_idx,
97                    char *dst, size_t dst_size)
98 {
99   struct substring s;
100
101   assert (e->type == OP_string);
102   assert ((dst == NULL) == (dst_size == 0));
103   expr_evaluate (e, c, case_idx, &s);
104
105   buf_copy_rpad (dst, dst_size, s.string, s.length, ' ');
106 }
107 \f
108 #include "language/lexer/lexer.h"
109 #include "language/command.h"
110
111 int
112 cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
113 {
114   bool optimize = true;
115   int retval = CMD_FAILURE;
116   bool dump_postfix = false;
117
118   struct ccase *c = NULL;
119
120   struct dataset *ds = NULL;
121
122   char *name = NULL;
123
124   struct expression *expr;
125
126   for (;;)
127     {
128       struct dictionary *d = NULL;
129       if (lex_match_id (lexer, "NOOPTIMIZE"))
130         optimize = 0;
131       else if (lex_match_id (lexer, "POSTFIX"))
132         dump_postfix = 1;
133       else if (lex_match (lexer, T_LPAREN))
134         {
135           struct variable *v;
136           int width;
137
138           if (!lex_force_id (lexer))
139             goto done;
140           name = xstrdup (lex_tokcstr (lexer));
141
142           lex_get (lexer);
143           if (!lex_force_match (lexer, T_EQUALS))
144             goto done;
145
146           if (lex_is_number (lexer))
147             width = 0;
148           else if (lex_is_string (lexer))
149             width = ss_length (lex_tokss (lexer));
150           else
151             {
152               lex_error (lexer, _("expecting number or string"));
153               goto done;
154             }
155
156           if  (ds == NULL)
157             {
158               ds = dataset_create (NULL, "");
159               d = dataset_dict (ds);
160             }
161
162           v = dict_create_var (d, name, width);
163           if (v == NULL)
164             {
165               msg (SE, _("Duplicate variable name %s."), name);
166               goto done;
167             }
168           free (name);
169           name = NULL;
170
171           if (c == NULL)
172             c = case_create (dict_get_proto (d));
173           else
174             c = case_unshare_and_resize (c, dict_get_proto (d));
175
176           if (!parse_value (lexer, case_data_rw (c, v), v))
177             NOT_REACHED ();
178
179           if (!lex_force_match (lexer, T_RPAREN))
180             goto done;
181         }
182       else
183         break;
184     }
185
186   if (!lex_force_match (lexer, T_SLASH))
187       goto done;
188
189   expr = expr_parse_any (lexer, ds, optimize);
190   if (!expr || lex_end_of_command (lexer) != CMD_SUCCESS)
191     {
192       if (expr != NULL)
193         expr_free (expr);
194       output_log ("error");
195       goto done;
196     }
197
198   if (dump_postfix)
199     expr_debug_print_postfix (expr);
200   else
201     switch (expr->type)
202       {
203       case OP_number:
204         {
205           double d = expr_evaluate_num (expr, c, 0);
206           if (d == SYSMIS)
207             output_log ("sysmis");
208           else
209             output_log ("%.2f", d);
210         }
211         break;
212
213       case OP_boolean:
214         {
215           double b = expr_evaluate_num (expr, c, 0);
216           output_log ("%s",
217                       b == SYSMIS ? "sysmis" : b == 0.0 ? "false" : "true");
218         }
219         break;
220
221       case OP_string:
222         {
223           struct substring out;
224           expr_evaluate (expr, c, 0, &out);
225           output_log ("\"%.*s\"", (int) out.length, out.string);
226           break;
227         }
228
229       default:
230         NOT_REACHED ();
231       }
232
233   expr_free (expr);
234   retval = CMD_SUCCESS;
235
236  done:
237   dataset_destroy (ds);
238
239   case_unref (c);
240
241   free (name);
242
243   return retval;
244 }
245
246 void
247 expr_debug_print_postfix (const struct expression *e)
248 {
249   struct string s = DS_EMPTY_INITIALIZER;
250
251   for (size_t i = 0; i < e->op_cnt; i++)
252     {
253       union operation_data *op = &e->ops[i];
254       if (i > 0)
255         ds_put_byte (&s, ' ');
256       switch (e->op_types[i])
257         {
258         case OP_operation:
259           if (op->operation == OP_return_number)
260             ds_put_cstr (&s, "return_number");
261           else if (op->operation == OP_return_string)
262             ds_put_cstr (&s, "return_string");
263           else if (is_function (op->operation))
264             ds_put_format (&s, "%s", operations[op->operation].prototype);
265           else if (is_composite (op->operation))
266             ds_put_format (&s, "%s", operations[op->operation].name);
267           else
268             ds_put_format (&s, "%s:", operations[op->operation].name);
269           break;
270         case OP_number:
271           if (op->number != SYSMIS)
272             ds_put_format (&s, "n<%g>", op->number);
273           else
274             ds_put_cstr (&s, "n<SYSMIS>");
275           break;
276         case OP_string:
277           ds_put_cstr (&s, "s<");
278           ds_put_substring (&s, op->string);
279           ds_put_byte (&s, '>');
280           break;
281         case OP_format:
282           {
283             char str[FMT_STRING_LEN_MAX + 1];
284             fmt_to_string (op->format, str);
285             ds_put_format (&s, "f<%s>", str);
286           }
287           break;
288         case OP_variable:
289           ds_put_format (&s, "v<%s>", var_get_name (op->variable));
290           break;
291         case OP_vector:
292           ds_put_format (&s, "vec<%s>", vector_get_name (op->vector));
293           break;
294         case OP_integer:
295           ds_put_format (&s, "i<%d>", op->integer);
296           break;
297         default:
298           NOT_REACHED ();
299         }
300     }
301   output_log_nocopy (ds_steal_cstr (&s));
302 }