expr.c 8.22 KB
Newer Older
1
#include <config.h>
Arturo Espinosa's avatar
Arturo Espinosa committed
2
3
#include <gnome.h>
#include "gnumeric.h"
4
5

char *parser_expr;
6
ParseErr parser_error;
7
8
ExprTree *parser_result;
int parser_col, parser_row;
9

10
11
ExprTree *
expr_parse_string (char *expr, int col, int row, char **error_msg)
12
13
{
	parser_expr = expr;
14
	parser_error = PARSE_OK;
15
16
17
	parser_col = col;
	parser_row = row;
		
18
	yyparse ();
19
20
21
	switch (parser_error){
	case PARSE_OK:
		*error_msg = NULL;
22
		parser_result->ref_count = 1;
Arturo Espinosa's avatar
Arturo Espinosa committed
23
		return parser_result;
24

Arturo Espinosa's avatar
Arturo Espinosa committed
25
26
27
28
	case PARSE_ERR_SYNTAX:
		*error_msg = _("Syntax error");
		break;
			
29
30
31
32
	case PARSE_ERR_NO_QUOTE:
		*error_msg = _("Missing quote");
		break;
	}
33
34
35
	return NULL;
}

36
37
38
39
40
41
42
43
44
/*
 * eval_expr_release:
 * @ExprTree:  The tree to be released
 *
 * This releases all of the resources used by a tree.  
 * It is only used internally by eval_expr_unref
 */
static void
eval_expr_release (ExprTree *tree)
45
{
46
	g_return_if_fail (tree != NULL);
47
	
48
	switch (tree->oper){
49
50
51
	case OP_VAR:
		break;
		
52
	case OP_CONSTANT:
53
		value_release (tree->u.constant);
54
55
56
		break;
		
	case OP_FUNCALL:
57
		symbol_unref (tree->u.function.symbol);
58
59
60
61
62
63
64
65
		break;

	case OP_ADD:
	case OP_SUB:
	case OP_MULT:
	case OP_DIV:
	case OP_EXP:
	case OP_CONCAT:
66
67
		eval_expr_release (tree->u.binary.value_a);
		eval_expr_release (tree->u.binary.value_b);
68
69
70
		break;

	case OP_NEG:
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
		eval_expr_release (tree->u.value);
		break;
		
	default:
		g_warning ("Unknown ExprTree type passed to eval_expr_release\n");
	}
	g_free (tree);
}

void
expr_tree_ref (ExprTree *tree)
{
	g_return_if_fail (tree != NULL);
	g_return_if_fail (tree->ref_count > 0);

	tree->ref_count++;
}

void
expr_tree_unref (ExprTree *tree)
{
	g_return_if_fail (tree != NULL);
	g_return_if_fail (tree->ref_count > 0);

	tree->ref_count--;
	if (tree->ref_count == 0)
		eval_expr_release (tree);
}

void
value_release (Value *value)
{
	switch (value->type){
	case VALUE_STRING:
		string_unref (value->v.str);
		break;

	case VALUE_INTEGER:
		mpz_clear (value->v.v_int);
110
111
		break;
		
112
113
114
115
	case VALUE_FLOAT:
		mpf_clear (value->v.v_float);
		break;

116
	default:
117
		g_warning ("Unknown value type passed to value_release\n");
118
119
	}
}
120

Arturo Espinosa's avatar
Arturo Espinosa committed
121
122
123
124
/*
 * Casts a value to float if it is integer, and returns
 * a new Value * if required
 */
125
Value *
126
value_cast_to_float (Value *v)
Arturo Espinosa's avatar
Arturo Espinosa committed
127
128
129
130
131
132
133
134
135
136
137
{
	Value *newv;
	
	g_return_val_if_fail (VALUE_IS_NUMBER (v), NULL);

	if (v->type == VALUE_FLOAT)
		return v;
	
	newv = g_new (Value, 1);
	newv->type = VALUE_FLOAT;
	mpf_set_z (newv->v.v_float, v->v.v_int);
138
	value_release (v);
Arturo Espinosa's avatar
Arturo Espinosa committed
139
140
141
142
	
	return newv;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
float_t
value_get_as_double (Value *v)
{
	if (v->type == VALUE_STRING){
		return atof (v->v.str->str);
	}

	if (v->type == VALUE_CELLRANGE){
		g_warning ("Getting range as a double: what to do?");
		return 0.0;
	}

	if (v->type == VALUE_INTEGER)
		return (float_t) v->v.v_int;

	return v->v.v_float;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
161
162
static Value *
eval_cell_value (Sheet *sheet, Value *value)
163
{
Arturo Espinosa's avatar
Arturo Espinosa committed
164
165
166
167
168
169
170
171
	Value *res;
	
	res = g_new (Value, 1);
	res->type = value->type;
	
	switch (res->type){
	case VALUE_STRING:
		res->v.str = value->v.str;
172
		string_ref (res->v.str);
Arturo Espinosa's avatar
Arturo Espinosa committed
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
		break;
		
	case VALUE_INTEGER:
		mpz_init (res->v.v_int);
		mpz_set  (res->v.v_int, value->v.v_int);
		break;
		
	case VALUE_FLOAT:
		mpf_init (res->v.v_float);
		mpf_set (res->v.v_float, value->v.v_float);
		break;
		
	case VALUE_CELLRANGE:
		res->v.cell_range = value->v.cell_range;
		break;
	}
	return res;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
static Value *
eval_funcall (Sheet *sheet, ExprTree *tree, int eval_col, int eval_row, char **error_string)
{
	FunctionDefinition *fd;
	GList *l;
	int argc, arg, i;
	Value *v;
	
	fd = (FunctionDefinition *) tree->u.function.symbol->data;
	
	l = tree->u.function.arg_list;
	argc = g_list_length (l);

	if (fd->expr_fn)
	{
		/* Functions that deal with ExprNodes */
		v = fd->expr_fn (sheet, l, eval_col, eval_row, error_string);
	}
	else
	{
		/* Functions that take pre-computed Values */
		Value **values;
		int fn_argc;
		char *arg_type = fd->args;
		
		fn_argc = strlen (fd->args);
		
		if (fn_argc != argc){
			*error_string = _("Invalid number of arguments");
			return NULL;
		}

		values = g_new (Value *, argc);
		
		for (arg = 0; l; l = l->next, arg++, arg_type++){
			ExprTree *t = (ExprTree *) l->data;
			
			v = eval_expr (sheet, t, eval_col, eval_row, error_string);
			if (v == NULL)
				goto free_list;
			
			values [arg] = v;
		}
		v = fd->fn (arg+1, values, error_string);

	free_list:
		for (i = 0; i < arg; i++)
			value_release (values [i]);
		g_free (values);
		return v;
	}
	return v;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
246
Value *
247
eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **error_string)
Arturo Espinosa's avatar
Arturo Espinosa committed
248
249
250
251
{
	Value *a, *b, *res;
	Sheet *sheet = asheet;
	
252
	switch (tree->oper){
Arturo Espinosa's avatar
Arturo Espinosa committed
253
254
255
256
257
	case OP_ADD:
	case OP_SUB:
	case OP_MULT:
	case OP_DIV:
	case OP_EXP:
258
259
260
261
		a = eval_expr (sheet, tree->u.binary.value_a,
			       eval_col, eval_row, error_string);
		b = eval_expr (sheet, tree->u.binary.value_b,
			       eval_col, eval_row, error_string);
Arturo Espinosa's avatar
Arturo Espinosa committed
262
263
264

		if (!(a && b)){
			if (a)
265
				value_release (a);
Arturo Espinosa's avatar
Arturo Espinosa committed
266
			if (b)
267
				value_release (b);
Arturo Espinosa's avatar
Arturo Espinosa committed
268
269
270
271
			return NULL;
		}
		
		if (!VALUE_IS_NUMBER (a) || !VALUE_IS_NUMBER (b)){
272
273
			value_release (a);
			value_release (b);
Arturo Espinosa's avatar
Arturo Espinosa committed
274
275
276
277
278
279
280
281
282
			*error_string = _("Type mismatch");
			return NULL;
		}
		
		res = g_new (Value, 1);
		if (a->type == VALUE_INTEGER && b->type == VALUE_INTEGER){
			res->type = VALUE_INTEGER;
			mpz_init (res->v.v_int);
			
283
			switch (tree->oper){
Arturo Espinosa's avatar
Arturo Espinosa committed
284
285
286
287
288
289
290
291
292
293
294
295
296
297
			case OP_ADD:
				mpz_add (res->v.v_int, a->v.v_int, b->v.v_int);
				break;
				
			case OP_SUB:
				mpz_sub (res->v.v_int, a->v.v_int, b->v.v_int);
				break;
				
			case OP_MULT:
				mpz_mul (res->v.v_int, a->v.v_int, b->v.v_int);
				break;
				
			case OP_DIV:
				if (mpz_cmp_si (b->v.v_int, 0)){
298
299
300
					value_release (a);
					value_release (b);
					value_release (res);
Arturo Espinosa's avatar
Arturo Espinosa committed
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
					*error_string = _("Division by zero");
					return NULL;
				}
					
				mpz_tdivq(res->v.v_int, a->v.v_int,b->v.v_int);
				break;
				
			case OP_EXP:
				mpz_set_si (res->v.v_int, 0);
				g_warning ("INT EXP not implemented yet\n");
				break;
			default:
			}
		} else {
			res->type = VALUE_FLOAT;
			mpf_init (res->v.v_float);
317
318
			a = value_cast_to_float (a);
			b = value_cast_to_float (b);
Arturo Espinosa's avatar
Arturo Espinosa committed
319
			
320
			switch (tree->oper){
Arturo Espinosa's avatar
Arturo Espinosa committed
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
			case OP_ADD:
				mpf_add (res->v.v_float,
					 a->v.v_float, b->v.v_float);
				break;
				
			case OP_SUB:
				mpf_sub (res->v.v_float,
					 a->v.v_float, b->v.v_float);
				break;
				
			case OP_MULT:
				mpf_mul (res->v.v_float,
					 a->v.v_float, b->v.v_float);
				break;
				
			case OP_DIV:
				if (mpf_cmp_si (b->v.v_int, 0)){
338
339
340
					value_release (a);
					value_release (b);
					value_release (res);
Arturo Espinosa's avatar
Arturo Espinosa committed
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
					*error_string = _("Division by zero");
					return NULL;
				}
					
				mpf_div (res->v.v_float,
					 a->v.v_float, b->v.v_float);
				break;
				
			case OP_EXP:
				mpz_set_si (res->v.v_int, 0);
				g_warning ("FLOAT EXP not implemented yet\n");
				break;
			default:
			}
		}
356
357
		value_release (a);
		value_release (b);
Arturo Espinosa's avatar
Arturo Espinosa committed
358
359
360
361
362
363
364
365
		return res;
		
	case OP_CONCAT:
		g_warning ("Concat not implemented yet\n");
		*error_string = _("OOPS");
		return NULL;

	case OP_FUNCALL:
Arturo Espinosa's avatar
Arturo Espinosa committed
366
		return eval_funcall (sheet, tree, eval_col, eval_row, error_string);
Arturo Espinosa's avatar
Arturo Espinosa committed
367
368

	case OP_CONSTANT:
369
		return eval_cell_value (sheet, tree->u.constant);
Arturo Espinosa's avatar
Arturo Espinosa committed
370
371

	case OP_VAR:{
372
		CellRef *ref;
Arturo Espinosa's avatar
Arturo Espinosa committed
373
374
375
376
377
378
379
380
381
382
383
384
385
		Cell *cell;
		int col, row;
		
		if (sheet == NULL){
			/* Only the test program requests this */
			res = g_new (Value, 1);

			res->type = VALUE_FLOAT;
			res->v.v_float = 3.14;
			
			return res;
		}

386
387
388
389
390
		ref = &tree->u.constant->v.cell;
		if (ref->col_relative)
			col = eval_col + ref->col;
		else
			col = ref->col;
Arturo Espinosa's avatar
Arturo Espinosa committed
391

392
393
394
395
396
		if (ref->row_relative)
			row = eval_row + ref->row;
		else
			row = ref->row;
		
Arturo Espinosa's avatar
Arturo Espinosa committed
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
		cell = sheet_cell_get (sheet, col, row);
		if (!cell)
			cell = sheet_cell_new (sheet, col, row);
		
		if (!cell->value){
			res = g_new (Value, 1);
			
			res->type = VALUE_INTEGER;
			res->v.v_int = 0;
		} else {
			return eval_cell_value (sheet, cell->value);
		}
		return res;
	}
	case OP_NEG:
412
413
		a = eval_expr (sheet, tree->u.value,
			       eval_col, eval_row, error_string);
Arturo Espinosa's avatar
Arturo Espinosa committed
414
415
416
417
		if (!a)
			return NULL;
		if (!VALUE_IS_NUMBER (a)){
			*error_string = _("Type mismatch");
418
			value_release (a);
Arturo Espinosa's avatar
Arturo Espinosa committed
419
420
421
422
423
424
425
426
427
428
			return NULL;
		}
		res = g_new (Value, 1);
		if (a->type == VALUE_INTEGER){
			mpz_init_set (res->v.v_int, a->v.v_int);
			mpz_neg (res->v.v_int, a->v.v_int);
		} else {
			mpf_init_set (res->v.v_int, a->v.v_int);
			mpf_neg (res->v.v_float, a->v.v_float);
		}
429
		value_release (a);
Arturo Espinosa's avatar
Arturo Espinosa committed
430
		return res;
431
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
432
433
434
	
	*error_string = _("Unknown evaluation error");
	return NULL;
435
}