expr.c 6.87 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 143 144
	
	return newv;
}

static Value *
eval_cell_value (Sheet *sheet, Value *value)
145
{
Arturo Espinosa's avatar
Arturo Espinosa committed
146 147 148 149 150 151 152 153
	Value *res;
	
	res = g_new (Value, 1);
	res->type = value->type;
	
	switch (res->type){
	case VALUE_STRING:
		res->v.str = value->v.str;
154
		string_ref (res->v.str);
Arturo Espinosa's avatar
Arturo Espinosa committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
		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;
}

Value *
175
eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **error_string)
Arturo Espinosa's avatar
Arturo Espinosa committed
176 177 178 179
{
	Value *a, *b, *res;
	Sheet *sheet = asheet;
	
180
	switch (tree->oper){
Arturo Espinosa's avatar
Arturo Espinosa committed
181 182 183 184 185
	case OP_ADD:
	case OP_SUB:
	case OP_MULT:
	case OP_DIV:
	case OP_EXP:
186 187 188 189
		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
190 191 192

		if (!(a && b)){
			if (a)
193
				value_release (a);
Arturo Espinosa's avatar
Arturo Espinosa committed
194
			if (b)
195
				value_release (b);
Arturo Espinosa's avatar
Arturo Espinosa committed
196 197 198 199
			return NULL;
		}
		
		if (!VALUE_IS_NUMBER (a) || !VALUE_IS_NUMBER (b)){
200 201
			value_release (a);
			value_release (b);
Arturo Espinosa's avatar
Arturo Espinosa committed
202 203 204 205 206 207 208 209 210
			*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);
			
211
			switch (tree->oper){
Arturo Espinosa's avatar
Arturo Espinosa committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225
			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)){
226 227 228
					value_release (a);
					value_release (b);
					value_release (res);
Arturo Espinosa's avatar
Arturo Espinosa committed
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
					*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);
245 246
			a = value_cast_to_float (a);
			b = value_cast_to_float (b);
Arturo Espinosa's avatar
Arturo Espinosa committed
247
			
248
			switch (tree->oper){
Arturo Espinosa's avatar
Arturo Espinosa committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
			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)){
266 267 268
					value_release (a);
					value_release (b);
					value_release (res);
Arturo Espinosa's avatar
Arturo Espinosa committed
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
					*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:
			}
		}
284 285
		value_release (a);
		value_release (b);
Arturo Espinosa's avatar
Arturo Espinosa committed
286 287 288 289 290 291 292 293 294 295 296 297 298
		return res;
		
	case OP_CONCAT:
		g_warning ("Concat not implemented yet\n");
		*error_string = _("OOPS");
		return NULL;

	case OP_FUNCALL:
		g_warning ("Function call not implemented yet\n");
		*error_string = _("OOPS");
		return NULL;

	case OP_CONSTANT:
299
		return eval_cell_value (sheet, tree->u.constant);
Arturo Espinosa's avatar
Arturo Espinosa committed
300 301

	case OP_VAR:{
302
		CellRef *ref;
Arturo Espinosa's avatar
Arturo Espinosa committed
303 304 305 306 307 308 309 310 311 312 313 314 315
		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;
		}

316 317 318 319 320
		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
321

322 323 324 325 326
		if (ref->row_relative)
			row = eval_row + ref->row;
		else
			row = ref->row;
		
Arturo Espinosa's avatar
Arturo Espinosa committed
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
		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:
342 343
		a = eval_expr (sheet, tree->u.value,
			       eval_col, eval_row, error_string);
Arturo Espinosa's avatar
Arturo Espinosa committed
344 345 346 347
		if (!a)
			return NULL;
		if (!VALUE_IS_NUMBER (a)){
			*error_string = _("Type mismatch");
348
			value_release (a);
Arturo Espinosa's avatar
Arturo Espinosa committed
349 350 351 352 353 354 355 356 357 358
			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);
		}
359
		value_release (a);
Arturo Espinosa's avatar
Arturo Espinosa committed
360
		return res;
361
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
362 363 364
	
	*error_string = _("Unknown evaluation error");
	return NULL;
365
}