parser.y 14.6 KB
Newer Older
1
%{
2 3 4 5 6 7 8 9
/*
 * Gnumeric Parser
 *
 * (C) 1998 the Free Software Foundation
 *
 * Author:
 *    Miguel de Icaza (miguel@gnu.org)
 */
10
#include <config.h>
11
#include <ctype.h>
Arturo Espinosa's avatar
Arturo Espinosa committed
12
#include <string.h>
13 14
#include <gnome.h>
#include "gnumeric.h"
Miguel de Icaza's avatar
New:  
Miguel de Icaza committed
15 16
#include "number-match.h"
	
17
/* Allocation with disposal-on-error */ 
Arturo Espinosa's avatar
Arturo Espinosa committed
18
static void *alloc_buffer    (int size);
19 20 21 22 23 24
static void  register_symbol (Symbol *sym);
static void  alloc_clean     (void);
static void  alloc_glist     (GList *l); 
static void  forget_glist    (GList *list);
static void  forget_tree     (ExprTree *tree);
static void  alloc_list_free (void); 
25
static void *v_new (void);
26
	
27 28 29 30 31 32 33
#define ERROR -1
 
/* Types of items we know how to dispose on error */ 
typedef enum {
	ALLOC_SYMBOL,
	ALLOC_VALUE,
	ALLOC_BUFFER,
Arturo Espinosa's avatar
Arturo Espinosa committed
34
	ALLOC_LIST
35 36 37 38 39 40 41 42 43 44 45 46
} AllocType;

/* How we keep track of them */ 
typedef struct {
	AllocType type;
	void      *data;
} AllocRec;

/* This keeps a list of  AllocRecs */
static GList *alloc_list;
 
/* Debugging */ 
47
static void dump_tree (ExprTree *tree);
48 49 50 51 52

/* Bison/Yacc internals */ 
static int  yylex (void);
static int  yyerror (char *s);

53 54 55 56 57 58 59 60 61 62 63 64 65
#define p_new(type) ((type *) alloc_buffer ((unsigned) sizeof (type)))

static ExprTree *
build_binop (ExprTree *l, Operation op, ExprTree *r)
{
  ExprTree *res = p_new (ExprTree);
  res->ref_count = 1;
  res->u.binary.value_a = l;
  res->oper = op;
  res->u.binary.value_b = r;
  return res;
}

66
%}
67

68
%union {
69
	ExprTree *tree;
70 71
	CellRef  *cell;
	GList    *list;
72
	Sheet    *sheetref;
73
}
74 75 76 77
%type  <tree>     exp
%type  <list>     arg_list
%token <tree>     NUMBER STRING FUNCALL CONSTANT CELLREF GTE LTE NE
%token <sheetref> SHEETREF
Arturo Espinosa's avatar
Arturo Espinosa committed
78 79

%left '<' '>' '=' GTE LTE NE
80 81
%left '-' '+' '&'
%left '*' '/'
Miguel de Icaza's avatar
Miguel de Icaza committed
82
%left NEG PLUS
83 84 85 86
%left '!'
%right '^'

%%
87 88 89 90
line:	  exp           { parser_result = $1;
                          /* dump_tree (parser_result);*/
                          alloc_list_free (); 
                        }
Arturo Espinosa's avatar
Arturo Espinosa committed
91 92 93 94
	| error 	{
				alloc_clean ();
				parser_error = PARSE_ERR_SYNTAX;
			}
95 96 97
	;

exp:	  NUMBER 	{ $$ = $1 }
Arturo Espinosa's avatar
Arturo Espinosa committed
98
	| STRING        { $$ = $1 }
99
        | CELLREF       { $$ = $1 }
Arturo Espinosa's avatar
Arturo Espinosa committed
100
	| CONSTANT      { $$ = $1 }
101 102 103 104 105 106 107 108 109 110 111 112 113
	| exp '+' exp	{ $$ = build_binop ($1, OPER_ADD,       $3); }
	| exp '-' exp	{ $$ = build_binop ($1, OPER_SUB,       $3); }
	| exp '*' exp	{ $$ = build_binop ($1, OPER_MULT,      $3); }
	| exp '/' exp	{ $$ = build_binop ($1, OPER_DIV,       $3); }
	| exp '^' exp	{ $$ = build_binop ($1, OPER_EXP,       $3); }
	| exp '&' exp	{ $$ = build_binop ($1, OPER_CONCAT,    $3); }
	| exp '=' exp	{ $$ = build_binop ($1, OPER_EQUAL,     $3); }
	| exp '<' exp	{ $$ = build_binop ($1, OPER_LT,        $3); }
	| exp '>' exp	{ $$ = build_binop ($1, OPER_GT,        $3); }
	| exp GTE exp	{ $$ = build_binop ($1, OPER_GTE,       $3); }
	| exp NE  exp	{ $$ = build_binop ($1, OPER_NOT_EQUAL, $3); }
	| exp LTE exp	{ $$ = build_binop ($1, OPER_LTE,       $3); }
	| '(' exp ')'   { $$ = $2; }
114

115 116
        | '-' exp %prec NEG {
		$$ = p_new (ExprTree);
Arturo Espinosa's avatar
Arturo Espinosa committed
117
		$$->ref_count = 1;
118
		$$->oper = OPER_NEG;
119 120
		$$->u.value = $2;
	}
Miguel de Icaza's avatar
Miguel de Icaza committed
121 122 123 124 125

        | '+' exp %prec PLUS {
		$$ = $2;
	}

Arturo Espinosa's avatar
Arturo Espinosa committed
126 127 128 129 130 131 132
        | CELLREF ':' CELLREF {
		CellRef a, b;

		a = $1->u.constant->v.cell;
		b = $3->u.constant->v.cell;

		$$ = p_new (ExprTree);
Arturo Espinosa's avatar
Arturo Espinosa committed
133
		$$->ref_count = 1;
134
		$$->oper = OPER_CONSTANT;
Arturo Espinosa's avatar
Arturo Espinosa committed
135 136 137 138 139 140 141 142
		$$->u.constant = v_new ();
		$$->u.constant->type = VALUE_CELLRANGE;
		$$->u.constant->v.cell_range.cell_a = a;
		$$->u.constant->v.cell_range.cell_b = b;

		forget_tree ($1);
		forget_tree ($3);
	}
143

144 145 146 147 148
	| SHEETREF '!' CELLREF {
	        $$ = $3;
		$$->u.constant->v.cell.sheet = $1;
	}

149
	| FUNCALL '(' arg_list ')' {
Arturo Espinosa's avatar
Arturo Espinosa committed
150
		$$ = $1;
151 152 153 154
		$$->u.function.arg_list = $3;
	}
	;

Arturo Espinosa's avatar
Arturo Espinosa committed
155 156 157 158 159 160 161 162
arg_list: exp {
		$$ = g_list_prepend (NULL, $1);
		alloc_glist ($$);
        }
	| exp ',' arg_list {
		forget_glist ($3);
		$$ = g_list_prepend ($3, $1);
		alloc_glist ($$);
Arturo Espinosa's avatar
Arturo Espinosa committed
163 164
	}
        | { $$ = NULL; }
165 166 167 168
	;

%%

169 170 171
static int
return_cellref (char *p)
{
172 173
	int col_relative = TRUE;
	int row_relative = TRUE;
174 175
	int col = 0;
	int row = 0;
176
	ExprTree *e;
177
	Value    *v;
Arturo Espinosa's avatar
Arturo Espinosa committed
178
	CellRef  *ref;
Arturo Espinosa's avatar
Arturo Espinosa committed
179

180 181
	/* Try to parse a column */
	if (*p == '$'){
182
		col_relative = FALSE;
183 184 185 186 187 188 189 190
		p++;
	}
	if (!(toupper (*p) >= 'A' && toupper (*p) <= 'Z'))
		return 0;

	col = toupper (*p++) - 'A';
	
	if (toupper (*p) >= 'A' && toupper (*p) <= 'Z')
191
		col = (col+1) * ('Z'-'A'+1) + toupper (*p++) - 'A';
192 193 194

	/* Try to parse a row */
	if (*p == '$'){
195
		row_relative = FALSE;
196 197 198 199 200 201
		p++;
	}
	
	if (!(*p >= '1' && *p <= '9'))
		return 0;

Arturo Espinosa's avatar
Arturo Espinosa committed
202
	while (isdigit (*p)){
203
		row = row * 10 + *p - '0';
Arturo Espinosa's avatar
Arturo Espinosa committed
204 205 206
		p++;
	}
	row--;
207 208 209

	/*  Ok, parsed successfully, create the return value */
	e = p_new (ExprTree);
Arturo Espinosa's avatar
Arturo Espinosa committed
210
	e->ref_count = 1;
211 212
	v = v_new ();

213
	e->oper = OPER_VAR;
214

Arturo Espinosa's avatar
Arturo Espinosa committed
215
	ref = &v->v.cell;
216

217 218
	/* Setup the cell reference information */
	if (row_relative)
Arturo Espinosa's avatar
Arturo Espinosa committed
219 220 221
		ref->row = row - parser_row;
	else
		ref->row = row;
222 223

	if (col_relative)
Arturo Espinosa's avatar
Arturo Espinosa committed
224 225 226
		ref->col = col - parser_col;
	else
		ref->col = col;
227 228 229
	
	ref->col_relative = col_relative;
	ref->row_relative = row_relative;
230 231
	ref->sheet = parser_sheet;
	
Arturo Espinosa's avatar
Arturo Espinosa committed
232
	e->u.constant = v;
233
	
234
	yylval.tree = e;
Arturo Espinosa's avatar
Arturo Espinosa committed
235

236 237 238 239
	return CELLREF;
}

static int
240 241 242 243 244 245 246 247
return_sheetref (Sheet *sheet)
{
	yylval.sheetref = sheet;
	return SHEETREF;
}

static int
old_return_symbol (char *string)
248
{
249
	ExprTree *e = p_new (ExprTree);
250
	Symbol *sym;
Arturo Espinosa's avatar
Arturo Espinosa committed
251
	int type;
Arturo Espinosa's avatar
Arturo Espinosa committed
252

253
#warning remove me after testing the new code.
Arturo Espinosa's avatar
Arturo Espinosa committed
254
	e->ref_count = 1;
255
	sym = symbol_lookup (global_symbol_table, string);
256
	type = STRING;
Arturo Espinosa's avatar
Arturo Espinosa committed
257 258 259
	
	if (!sym)
	{
Arturo Espinosa's avatar
Arturo Espinosa committed
260
		Value *v = v_new ();
Miguel de Icaza's avatar
New:  
Miguel de Icaza committed
261 262
		double fv;
		char *format;
263 264 265 266 267 268 269

		/*
		 * Try to match the entered text against any
		 * of the known number formating codes, if this
		 * succeeds, we store this as a float + format,
		 * otherwise, we return a string.
		 */
Miguel de Icaza's avatar
New:  
Miguel de Icaza committed
270 271 272 273 274 275 276 277 278
		if (format_match (string, &fv, &format)){
			v->type = VALUE_FLOAT;
			v->v.v_float = fv;
			if (!parser_desired_format)
				parser_desired_format = format;
		} else {
			v->v.str = string_get (string);
			v->type = VALUE_STRING;
		}
Arturo Espinosa's avatar
Arturo Espinosa committed
279
		
280
		e->oper = OPER_CONSTANT;
Arturo Espinosa's avatar
Arturo Espinosa committed
281
		e->u.constant = v;
Arturo Espinosa's avatar
Arturo Espinosa committed
282 283 284
	}
	else
	{
285
		symbol_ref (sym);
286 287
		switch (sym->type){
		case SYMBOL_FUNCTION:
288
			e->oper = OPER_FUNCALL;
289
			type = FUNCALL;
Arturo Espinosa's avatar
Arturo Espinosa committed
290 291
			e->u.function.symbol = sym;
			e->u.function.arg_list = NULL;
292 293 294 295
			break;

		case SYMBOL_VALUE:
		case SYMBOL_STRING: {
Arturo Espinosa's avatar
Arturo Espinosa committed
296 297 298 299 300 301 302
			Value *v, *dv;

			/* Make a copy of the value */
			dv = (Value *) sym->data;
			v = v_new ();
			value_copy_to (v, dv);
			
303
			e->oper = OPER_CONSTANT;
Arturo Espinosa's avatar
Arturo Espinosa committed
304 305
			e->u.constant = v;
			type = CONSTANT;
306
			break;
Arturo Espinosa's avatar
Arturo Espinosa committed
307
		}
308 309
		
		} /* switch */
Arturo Espinosa's avatar
Arturo Espinosa committed
310
		register_symbol (sym);
311 312
	}
	
313
	yylval.tree = e;
Arturo Espinosa's avatar
Arturo Espinosa committed
314
	return type;
315 316 317
}

static int
318
make_string_return (char *string)
319
{
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
	ExprTree *e;
	Value *v;
	double fv;
	int type;
	char *format;

	e = p_new (ExprTree);
	e->ref_count = 1;

	v = v_new ();
	/*
	 * Try to match the entered text against any
	 * of the known number formating codes, if this
	 * succeeds, we store this as a float + format,
	 * otherwise, we return a string.
	 */
	if (format_match (string, &fv, &format)){
		v->type = VALUE_FLOAT;
		v->v.v_float = fv;
		if (!parser_desired_format)
			parser_desired_format = format;
	} else {
		v->v.str = string_get (string);
		v->type = VALUE_STRING;
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
345
	
346 347 348 349
	e->oper = OPER_CONSTANT;
	e->u.constant = v;
	
	yylval.tree = e;
350

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
	return STRING;
}

static int
return_symbol (Symbol *sym)
{
	ExprTree *e = p_new (ExprTree);
	int type = STRING;
	
	e->ref_count = 1;
	symbol_ref (sym);
	
	switch (sym->type){
	case SYMBOL_FUNCTION:
		e->oper = OPER_FUNCALL;
		type = FUNCALL;
		e->u.function.symbol = sym;
		e->u.function.arg_list = NULL;
		break;
		
	case SYMBOL_VALUE:
	case SYMBOL_STRING: {
		Value *v, *dv;
		
		/* Make a copy of the value */
		dv = (Value *) sym->data;
		v = v_new ();
		value_copy_to (v, dv);
		
		e->oper = OPER_CONSTANT;
		e->u.constant = v;
		type = CONSTANT;
		break;
	}
	
	} /* switch */

	register_symbol (sym);
	yylval.tree = e;

	return type;
}

/**
 * try_symbol:
 * @string: the string to try.
 * @try_cellref: whether we know for sure if it is not a cellref
 *
 * Attempts to figure out what @string refers to.
 * if @try_cellref is TRUE it will also attempt to match the
 * string as a cellname reference.
 */
static int
try_symbol (char *string, gboolean try_cellref)
{
	Symbol *sym;
	int v;

	if (try_cellref){
		v = return_cellref (string);
		if (v)
			return v;
	}

	sym = symbol_lookup (global_symbol_table, string);
	if (sym)
		return return_symbol (sym);
	else {
		Sheet *sheet;

		sheet = sheet_lookup_by_name (parser_sheet, string);
		if (sheet)
			return return_sheetref (sheet);
	}
	
	return make_string_return (string);
427 428
}

429 430 431
int yylex (void)
{
	int c;
432 433 434 435 436 437 438 439 440
	char *p, *tmp;
	int is_float;
	
        while(isspace (*parser_expr))
                parser_expr++;                                                                                       

	c = *parser_expr++;
        if (c == '(' || c == ',' || c == ')')
                return c;
441

442 443 444
	switch (c){
        case '0': case '1': case '2': case '3': case '4': case '5':
	case '6': case '7': case '8': case '9': case '.': {
445
		ExprTree *e = p_new (ExprTree);
446
		Value *v = v_new ();
Arturo Espinosa's avatar
Arturo Espinosa committed
447 448

		e->ref_count = 1;
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
		is_float = c == '.';
		p = parser_expr-1;
		tmp = parser_expr;
		
                while (isdigit (*tmp) || (!is_float && *tmp=='.' && ++is_float))
                        tmp++;
		
		if (*tmp == 'e' || *tmp == 'E') {
			is_float = 1;
			tmp++;
			if (*tmp == '-' || *tmp == '+')
				tmp++;
			while (isdigit (*tmp))
				tmp++;
		}
464

465 466 467 468 469 470 471 472 473 474
		/* Ok, we have skipped over a number, now load its value */
		if (is_float){
			v->type = VALUE_FLOAT;
			float_get_from_range (p, tmp, &v->v.v_float);
		} else {
			v->type = VALUE_INTEGER;
			int_get_from_range (p, tmp, &v->v.v_int);
		}

		/* Return the value to the parser */
475
		e->oper = OPER_CONSTANT;
476
		e->u.constant = v;
477
		yylval.tree = e;
478 479

		parser_expr = tmp;
480 481
		return NUMBER;
	}
482
	case '\'':
483
	case '"': {
Arturo Espinosa's avatar
Arturo Espinosa committed
484 485
		char *string, *s;
		int v;
486 487
		char *quotes_end = c;
		
488
                p = parser_expr;
489
                while(*parser_expr && *parser_expr != quotes_end) {
490 491 492 493 494 495 496 497 498
                        if (*parser_expr == '\\' && parser_expr [1])
                                parser_expr++;
                        parser_expr++;
                }
                if(!*parser_expr){
                        parser_error = PARSE_ERR_NO_QUOTE;
                        return ERROR;
                }
		
Arturo Espinosa's avatar
Arturo Espinosa committed
499
		s = string = (char *) alloca (1 + parser_expr - p);
500 501 502
		while (p != parser_expr){
			if (*p== '\\'){
				p++;
Arturo Espinosa's avatar
Arturo Espinosa committed
503
				*s++ = *p++;
504
			} else
Arturo Espinosa's avatar
Arturo Espinosa committed
505
				*s++ = *p++;
506 507
			
		}
Arturo Espinosa's avatar
Arturo Espinosa committed
508
		*s = 0;
509
		parser_expr++;
510

511
		v = try_symbol (string, FALSE);
Arturo Espinosa's avatar
Arturo Espinosa committed
512
		return v;
513
	}
514
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
515
	
516
	if (isalpha (c) || c == '_' || c == '$'){
Arturo Espinosa's avatar
Arturo Espinosa committed
517 518 519 520
		char *start = parser_expr - 1;
		char *str;
		int  len;
		
521
		while (isalnum (*parser_expr) || *parser_expr == '_' || *parser_expr == '$')
Arturo Espinosa's avatar
Arturo Espinosa committed
522 523 524 525 526 527
			parser_expr++;

		len = parser_expr - start;
		str = alloca (len + 1);
		strncpy (str, start, len);
		str [len] = 0;
528
		return try_symbol (str, TRUE);
529 530 531 532 533 534
	}
	if (c == '\n')
		return 0;
	
	if (c == EOF)
		return 0;
Arturo Espinosa's avatar
Arturo Espinosa committed
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554

	if (c == '<'){
		if (*parser_expr == '='){
			parser_expr++;
			return LTE;
		}
		if (*parser_expr == '>'){
			parser_expr++;
			return NE;
		}
		return c;
	}
	
	if (c == '>'){
		if (*parser_expr == '='){
			parser_expr++;
			return GTE;
		}
		return c;
	}
555 556 557 558 559 560 561 562 563 564 565 566
	
	return c;
}

int
yyerror (char *s)
{
    printf ("Error: %s\n", s);
    return 0;
}

static void
Arturo Espinosa's avatar
Arturo Espinosa committed
567
alloc_register (void *a_info)
568 569 570 571
{
	alloc_list = g_list_prepend (alloc_list, a_info);
}

572
static void
Arturo Espinosa's avatar
Arturo Espinosa committed
573
register_symbol (Symbol *sym)
574 575 576
{
	AllocRec *a_info = g_new (AllocRec, 1);

Arturo Espinosa's avatar
Arturo Espinosa committed
577 578 579
	a_info->type = ALLOC_SYMBOL;
	a_info->data = sym;
	alloc_register (a_info);
580 581
}

582 583 584 585 586 587 588 589
void *
alloc_buffer (int size)
{
	AllocRec *a_info = g_new (AllocRec, 1);
	char *res = g_malloc (size);

	a_info->type = ALLOC_BUFFER;
	a_info->data = res;
Arturo Espinosa's avatar
Arturo Espinosa committed
590
	alloc_register (a_info);
591 592 593 594

	return res;
}

595
static void *
596 597 598 599 600 601 602
v_new (void)
{
	AllocRec *a_info = g_new (AllocRec, 1);
	char *res = g_malloc (sizeof (Value));

	a_info->type = ALLOC_VALUE;
	a_info->data = res;
Arturo Espinosa's avatar
Arturo Espinosa committed
603
	alloc_register (a_info);
604 605 606 607

	return res;
}

608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
static void
alloc_clean (void)
{
	GList *l = alloc_list;
	
	for (; l; l = l->next){
		AllocRec *rec = l->data;

		switch (rec->type){
		case ALLOC_BUFFER:
			g_free (rec->data);
			break;
			
		case ALLOC_SYMBOL:
			symbol_unref ((Symbol *)rec->data);
			break;
624

Arturo Espinosa's avatar
Arturo Espinosa committed
625 626
		case ALLOC_VALUE:
			value_release ((Value *)rec->data);
627 628
			break;
			
Arturo Espinosa's avatar
Arturo Espinosa committed
629 630
		case ALLOC_LIST:
			g_list_free ((GList *) rec->data);
Arturo Espinosa's avatar
Arturo Espinosa committed
631
			break;
632
		}
633
		g_free (rec);
634 635 636 637 638 639
	}

	g_list_free (l);
	alloc_list = NULL;
}

640 641 642 643 644 645 646 647 648 649 650 651
static void
alloc_list_free (void)
{
	GList *l = alloc_list;
	
	for (; l; l = l->next)
		g_free (l->data);

	g_list_free (l);
	alloc_list = NULL;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
652 653 654 655 656 657 658
static void
alloc_glist (GList *list)
{
	AllocRec *a_info = g_new (AllocRec, 1);

	a_info->type = ALLOC_LIST;
	a_info->data = list;
Arturo Espinosa's avatar
Arturo Espinosa committed
659
	alloc_register (a_info);
Arturo Espinosa's avatar
Arturo Espinosa committed
660 661 662
}

static void
663
forget (AllocType type, void *data)
Arturo Espinosa's avatar
Arturo Espinosa committed
664 665 666 667 668 669
{
	GList *l;

	for (l = alloc_list; l; l = l->next){
		AllocRec *a_info = (AllocRec *) l->data;

Arturo Espinosa's avatar
Arturo Espinosa committed
670
		if (a_info->type == type && a_info->data == data){
Arturo Espinosa's avatar
Arturo Espinosa committed
671 672 673 674 675 676
			alloc_list = g_list_remove_link (alloc_list, l);
			return;
		}
	}
}

Arturo Espinosa's avatar
Arturo Espinosa committed
677 678 679 680 681 682 683 684 685 686
static void
forget_glist (GList *list)
{
	forget (ALLOC_LIST, list);
}

static void
forget_tree (ExprTree *tree)
{
	forget (ALLOC_BUFFER, tree);
Arturo Espinosa's avatar
Arturo Espinosa committed
687
	expr_tree_unref (tree); 
Arturo Espinosa's avatar
Arturo Espinosa committed
688 689
}

Arturo Espinosa's avatar
Arturo Espinosa committed
690
void
691
value_dump (Value *value)
Arturo Espinosa's avatar
Arturo Espinosa committed
692
{
693 694 695 696 697
	switch (value->type){
	case VALUE_STRING:
		printf ("STRING: %s\n", value->v.str->str);
		break;

698
	case VALUE_INTEGER:
Arturo Espinosa's avatar
Arturo Espinosa committed
699
		printf ("NUM: %d\n", value->v.v_int);
700 701
		break;

702
	case VALUE_FLOAT:
Arturo Espinosa's avatar
Arturo Espinosa committed
703
		printf ("Float: %f\n", value->v.v_float);
704
		break;
Arturo Espinosa's avatar
Arturo Espinosa committed
705 706 707 708 709 710 711 712 713 714

	case VALUE_ARRAY: {
		GList *l;

		printf ("Array: { ");
		for (l = value->v.array; l; l = l->next){
			value_dump (l->data);
		}
		printf ("}\n");
	}
715 716 717 718 719 720
	default:
		printf ("Unhandled item type\n");
	}
}

void
721
dump_tree (ExprTree *tree)
722 723
{
	Symbol *s;
724
	CellRef *cr;
725
	
726
	switch (tree->oper){
727
	case OPER_VAR:
728
		cr = &tree->u.constant->v.cell;
729
		printf ("Cell: %s%c%s%d\n",
730
			cr->col_relative ? "" : "$",
731
			cr->col + 'A',
732
			cr->row_relative ? "" : "$",
733 734 735
			cr->row + '1');
		return;
		
736
	case OPER_CONSTANT:
737
		value_dump (tree->u.constant);
738 739
		return;

740
	case OPER_FUNCALL:
741
		s = symbol_lookup (global_symbol_table, tree->u.function.symbol->str);
742 743
		printf ("Function call: %s\n", s->str);
		break;
Arturo Espinosa's avatar
Arturo Espinosa committed
744

745 746 747 748 749 750 751 752 753 754 755 756
	case OPER_EQUAL:
	case OPER_NOT_EQUAL:
	case OPER_LT:
	case OPER_LTE:
	case OPER_GT:
	case OPER_GTE:
	case OPER_ADD:
	case OPER_SUB:
	case OPER_MULT:
	case OPER_DIV:
	case OPER_EXP:
	case OPER_CONCAT:
757 758 759
		dump_tree (tree->u.binary.value_a);
		dump_tree (tree->u.binary.value_b);
		switch (tree->oper){
760 761 762 763 764 765 766 767 768 769 770 771
		case OPER_ADD: printf ("ADD\n"); break;
		case OPER_SUB: printf ("SUB\n"); break;
		case OPER_MULT: printf ("MULT\n"); break;
		case OPER_DIV: printf ("DIV\n"); break;
		case OPER_CONCAT: printf ("CONCAT\n"); break;
		case OPER_EQUAL: printf ("==\n"); break;
		case OPER_NOT_EQUAL: printf ("!=\n"); break;
		case OPER_LT: printf ("<\n"); break;
		case OPER_GT: printf (">\n"); break;
		case OPER_GTE: printf (">=\n"); break;
		case OPER_LTE: printf ("<=\n"); break;
		case OPER_EXP: printf ("EXP\n"); break;
772 773 774 775 776
		default:
			printf ("Error\n");
		}
		break;
		
777
	case OPER_NEG:
778
		dump_tree (tree->u.value);
779 780 781 782 783
		printf ("NEGATIVE\n");
		break;
		
	}
}