parser.y 14.3 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
#include "number-match.h"
16
17
18
19
#include "symbol.h"
#include "expr.h"
#include "sheet.h"
#include "utils.h"
Miguel de Icaza's avatar
New:    
Miguel de Icaza committed
20
	
21
/* Allocation with disposal-on-error */ 
Arturo Espinosa's avatar
Arturo Espinosa committed
22
static void *alloc_buffer    (int size);
23
24
25
26
27
28
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); 
Morten Welinder's avatar
Morten Welinder committed
29
static Value*v_new (void);
30
	
31
32
33
34
35
36
37
#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
38
	ALLOC_LIST
39
40
41
42
43
44
45
46
47
48
49
50
} 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 */ 
51
static void dump_tree (ExprTree *tree);
52
53
54
55
56

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

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* The expression being parsed */
static const char *parser_expr;

/* The error returned from the */
static ParseErr parser_error;

/* The sheet where the parsing takes place */
static Sheet *parser_sheet;

/* Location where the parsing is taking place */
static int parser_col, parser_row;

/* The suggested format to use for this expression */
static const char **parser_desired_format;

static ExprTree **parser_result;

74
75
76
77
78
#define p_new(type) ((type *) alloc_buffer ((unsigned) sizeof (type)))

static ExprTree *
build_binop (ExprTree *l, Operation op, ExprTree *r)
{
79
80
81
82
83
84
	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;
85
86
}

87
%}
88

89
%union {
90
	ExprTree *tree;
91
92
	CellRef  *cell;
	GList    *list;
93
	Sheet    *sheetref;
94
}
95
96
97
98
%type  <tree>     exp
%type  <list>     arg_list
%token <tree>     NUMBER STRING FUNCALL CONSTANT CELLREF GTE LTE NE
%token <sheetref> SHEETREF
99
%type  <tree>     cellref
Arturo Espinosa's avatar
Arturo Espinosa committed
100

101
%left '&'
Arturo Espinosa's avatar
Arturo Espinosa committed
102
%left '<' '>' '=' GTE LTE NE
103
%left '-' '+' 
104
%left '*' '/'
Miguel de Icaza's avatar
Miguel de Icaza committed
105
%left NEG PLUS
106
107
108
109
%left '!'
%right '^'

%%
110
111
line:	  exp           { *parser_result = $1; }
	| error 	{ parser_error = PARSE_ERR_SYNTAX; }
112
113
114
	;

exp:	  NUMBER 	{ $$ = $1 }
Arturo Espinosa's avatar
Arturo Espinosa committed
115
	| STRING        { $$ = $1 }
116
        | cellref       { $$ = $1 }
Arturo Espinosa's avatar
Arturo Espinosa committed
117
	| CONSTANT      { $$ = $1 }
118
119
120
121
122
123
124
125
126
127
128
129
130
	| 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; }
131

132
133
        | '-' exp %prec NEG {
		$$ = p_new (ExprTree);
Arturo Espinosa's avatar
Arturo Espinosa committed
134
		$$->ref_count = 1;
135
		$$->oper = OPER_NEG;
136
137
		$$->u.value = $2;
	}
Miguel de Icaza's avatar
Miguel de Icaza committed
138
139
140
141
142

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

143
        | cellref ':' cellref {
Arturo Espinosa's avatar
Arturo Espinosa committed
144
		$$ = p_new (ExprTree);
Arturo Espinosa's avatar
Arturo Espinosa committed
145
		$$->ref_count = 1;
146
		$$->oper = OPER_CONSTANT;
Arturo Espinosa's avatar
Arturo Espinosa committed
147
148
		$$->u.constant = v_new ();
		$$->u.constant->type = VALUE_CELLRANGE;
Morten Welinder's avatar
Morten Welinder committed
149
150
		$$->u.constant->v.cell_range.cell_a = $1->u.ref;
		$$->u.constant->v.cell_range.cell_b = $3->u.ref;
Arturo Espinosa's avatar
Arturo Espinosa committed
151
152
153
154

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

156

157
	| FUNCALL '(' arg_list ')' {
Arturo Espinosa's avatar
Arturo Espinosa committed
158
		$$ = $1;
159
160
161
162
		$$->u.function.arg_list = $3;
	}
	;

163
164
165
166
167
168
169
170
171
172
cellref:  CELLREF {
		$$ = $1;
	}

	| SHEETREF '!' CELLREF {
	        $$ = $3;
		$$->u.ref.sheet = $1;
	}
	;

Arturo Espinosa's avatar
Arturo Espinosa committed
173
174
175
176
177
178
179
180
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
181
182
	}
        | { $$ = NULL; }
183
184
185
186
	;

%%

187
188
189
static int
return_cellref (char *p)
{
190
191
	int col_relative = TRUE;
	int row_relative = TRUE;
192
193
	int col = 0;
	int row = 0;
194
	ExprTree *e;
Arturo Espinosa's avatar
Arturo Espinosa committed
195
	CellRef  *ref;
Arturo Espinosa's avatar
Arturo Espinosa committed
196

197
198
	/* Try to parse a column */
	if (*p == '$'){
199
		col_relative = FALSE;
200
201
202
203
204
205
206
207
		p++;
	}
	if (!(toupper (*p) >= 'A' && toupper (*p) <= 'Z'))
		return 0;

	col = toupper (*p++) - 'A';
	
	if (toupper (*p) >= 'A' && toupper (*p) <= 'Z')
208
		col = (col+1) * ('Z'-'A'+1) + toupper (*p++) - 'A';
209
210
211

	/* Try to parse a row */
	if (*p == '$'){
212
		row_relative = FALSE;
213
214
215
216
217
218
		p++;
	}
	
	if (!(*p >= '1' && *p <= '9'))
		return 0;

Arturo Espinosa's avatar
Arturo Espinosa committed
219
	while (isdigit (*p)){
220
		row = row * 10 + *p - '0';
Arturo Espinosa's avatar
Arturo Espinosa committed
221
222
223
		p++;
	}
	row--;
224
225
226

	/*  Ok, parsed successfully, create the return value */
	e = p_new (ExprTree);
Arturo Espinosa's avatar
Arturo Espinosa committed
227
	e->ref_count = 1;
Morten Welinder's avatar
Morten Welinder committed
228

229
	e->oper = OPER_VAR;
230

231
	ref = &e->u.ref;
232

233
234
	/* Setup the cell reference information */
	if (row_relative)
Arturo Espinosa's avatar
Arturo Espinosa committed
235
236
237
		ref->row = row - parser_row;
	else
		ref->row = row;
238
239

	if (col_relative)
Arturo Espinosa's avatar
Arturo Espinosa committed
240
241
242
		ref->col = col - parser_col;
	else
		ref->col = col;
243
244
245
	
	ref->col_relative = col_relative;
	ref->row_relative = row_relative;
246
	ref->sheet = parser_sheet;
Morten Welinder's avatar
Morten Welinder committed
247

248
	yylval.tree = e;
Arturo Espinosa's avatar
Arturo Espinosa committed
249

250
251
252
253
	return CELLREF;
}

static int
254
255
256
257
258
259
return_sheetref (Sheet *sheet)
{
	yylval.sheetref = sheet;
	return SHEETREF;
}

260
static int
261
make_string_return (char *string)
262
{
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
	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;
282
283
		if (parser_desired_format && *parser_desired_format == NULL)
			*parser_desired_format = format;
284
285
286
287
	} else {
		v->v.str = string_get (string);
		v->type = VALUE_STRING;
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
288
	
289
290
291
292
	e->oper = OPER_CONSTANT;
	e->u.constant = v;
	
	yylval.tree = e;
293

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
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
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
	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);
370
371
}

372
373
374
int yylex (void)
{
	int c;
375
	const char *p, *tmp;
376
	int is_float, digits;
377

378
        while(isspace (*parser_expr))
379
                parser_expr++;
380
381
382
383

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

385
386
387
	switch (c){
        case '0': case '1': case '2': case '3': case '4': case '5':
	case '6': case '7': case '8': case '9': case '.': {
388
		ExprTree *e = p_new (ExprTree);
389
		Value *v = v_new ();
Arturo Espinosa's avatar
Arturo Espinosa committed
390
391

		e->ref_count = 1;
392
393
394
		is_float = c == '.';
		p = parser_expr-1;
		tmp = parser_expr;
395

Arturo Espinosa's avatar
Arturo Espinosa committed
396
		digits = 1;
397
		while (isdigit (*tmp) || (!is_float && *tmp=='.' && ++is_float)) {
Arturo Espinosa's avatar
Arturo Espinosa committed
398
			tmp++;
399
400
401
402
			digits++;
		}

		/* Can't store it in a gint32 */
Arturo Espinosa's avatar
Arturo Espinosa committed
403
		is_float |= (digits > 9);
404

405
406
407
408
409
410
411
412
		if (*tmp == 'e' || *tmp == 'E') {
			is_float = 1;
			tmp++;
			if (*tmp == '-' || *tmp == '+')
				tmp++;
			while (isdigit (*tmp))
				tmp++;
		}
413

414
415
416
417
418
419
420
421
422
423
		/* 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 */
424
		e->oper = OPER_CONSTANT;
425
		e->u.constant = v;
426
		yylval.tree = e;
427
428

		parser_expr = tmp;
429
430
		return NUMBER;
	}
431
	case '\'':
432
	case '"': {
Arturo Espinosa's avatar
Arturo Espinosa committed
433
434
		char *string, *s;
		int v;
435
		char quotes_end = c;
436
		
437
                p = parser_expr;
438
                while(*parser_expr && *parser_expr != quotes_end) {
439
440
441
442
443
444
445
446
447
                        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
448
		s = string = (char *) alloca (1 + parser_expr - p);
449
450
451
		while (p != parser_expr){
			if (*p== '\\'){
				p++;
Arturo Espinosa's avatar
Arturo Espinosa committed
452
				*s++ = *p++;
453
			} else
Arturo Espinosa's avatar
Arturo Espinosa committed
454
				*s++ = *p++;
455
456
			
		}
Arturo Espinosa's avatar
Arturo Espinosa committed
457
		*s = 0;
458
		parser_expr++;
459

460
		v = try_symbol (string, FALSE);
Arturo Espinosa's avatar
Arturo Espinosa committed
461
		return v;
462
	}
463
	}
Arturo Espinosa's avatar
Arturo Espinosa committed
464
	
465
	if (isalpha (c) || c == '_' || c == '$'){
466
		const char *start = parser_expr - 1;
Arturo Espinosa's avatar
Arturo Espinosa committed
467
468
469
		char *str;
		int  len;
		
470
		while (isalnum (*parser_expr) || *parser_expr == '_' || *parser_expr == '$')
Arturo Espinosa's avatar
Arturo Espinosa committed
471
472
473
474
475
476
			parser_expr++;

		len = parser_expr - start;
		str = alloca (len + 1);
		strncpy (str, start, len);
		str [len] = 0;
477
		return try_symbol (str, TRUE);
478
	}
479
480

	if (c == '\n' || c == 0)
481
		return 0;
Arturo Espinosa's avatar
Arturo Espinosa committed
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501

	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;
	}
502
503
504
505
506
507
508
	
	return c;
}

int
yyerror (char *s)
{
509
510
511
512
#if 0
	printf ("Error: %s\n", s);
#endif
	return 0;
513
514
515
}

static void
Morten Welinder's avatar
Morten Welinder committed
516
alloc_register (AllocRec *a_info)
517
518
519
520
{
	alloc_list = g_list_prepend (alloc_list, a_info);
}

521
static void
Arturo Espinosa's avatar
Arturo Espinosa committed
522
register_symbol (Symbol *sym)
523
524
525
{
	AllocRec *a_info = g_new (AllocRec, 1);

Arturo Espinosa's avatar
Arturo Espinosa committed
526
527
528
	a_info->type = ALLOC_SYMBOL;
	a_info->data = sym;
	alloc_register (a_info);
529
530
}

531
532
533
534
void *
alloc_buffer (int size)
{
	AllocRec *a_info = g_new (AllocRec, 1);
Morten Welinder's avatar
Morten Welinder committed
535
	void *res = g_malloc (size);
536
537
538

	a_info->type = ALLOC_BUFFER;
	a_info->data = res;
Arturo Espinosa's avatar
Arturo Espinosa committed
539
	alloc_register (a_info);
540
541
542
543

	return res;
}

Morten Welinder's avatar
Morten Welinder committed
544
static Value *
545
546
547
v_new (void)
{
	AllocRec *a_info = g_new (AllocRec, 1);
Morten Welinder's avatar
Morten Welinder committed
548
	Value *res = g_new (Value, 1);
549
550
551

	a_info->type = ALLOC_VALUE;
	a_info->data = res;
Arturo Espinosa's avatar
Arturo Espinosa committed
552
	alloc_register (a_info);
553
554
555
556

	return res;
}

557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
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;
573

Arturo Espinosa's avatar
Arturo Espinosa committed
574
575
		case ALLOC_VALUE:
			value_release ((Value *)rec->data);
576
577
			break;
			
Arturo Espinosa's avatar
Arturo Espinosa committed
578
579
		case ALLOC_LIST:
			g_list_free ((GList *) rec->data);
Arturo Espinosa's avatar
Arturo Espinosa committed
580
			break;
581
		}
582
		g_free (rec);
583
584
	}

Morten Welinder's avatar
Morten Welinder committed
585
	g_list_free (alloc_list);
586
587
588
	alloc_list = NULL;
}

589
590
591
592
593
594
595
596
static void
alloc_list_free (void)
{
	GList *l = alloc_list;
	
	for (; l; l = l->next)
		g_free (l->data);

Morten Welinder's avatar
Morten Welinder committed
597
	g_list_free (alloc_list);
598
599
600
	alloc_list = NULL;
}

Arturo Espinosa's avatar
Arturo Espinosa committed
601
602
603
604
605
606
607
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
608
	alloc_register (a_info);
Arturo Espinosa's avatar
Arturo Espinosa committed
609
610
611
}

static void
612
forget (AllocType type, void *data)
Arturo Espinosa's avatar
Arturo Espinosa committed
613
614
615
616
617
618
{
	GList *l;

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

Arturo Espinosa's avatar
Arturo Espinosa committed
619
		if (a_info->type == type && a_info->data == data){
Arturo Espinosa's avatar
Arturo Espinosa committed
620
			alloc_list = g_list_remove_link (alloc_list, l);
Morten Welinder's avatar
Morten Welinder committed
621
			g_list_free_1 (l);
Morten Welinder's avatar
Morten Welinder committed
622
			g_free (a_info);
Arturo Espinosa's avatar
Arturo Espinosa committed
623
624
625
626
627
			return;
		}
	}
}

Arturo Espinosa's avatar
Arturo Espinosa committed
628
629
630
631
632
633
634
635
636
static void
forget_glist (GList *list)
{
	forget (ALLOC_LIST, list);
}

static void
forget_tree (ExprTree *tree)
{
Morten Welinder's avatar
Morten Welinder committed
637
	expr_tree_unref (tree);
Arturo Espinosa's avatar
Arturo Espinosa committed
638
639
640
	forget (ALLOC_BUFFER, tree);
}

Arturo Espinosa's avatar
Arturo Espinosa committed
641
void
642
value_dump (Value *value)
Arturo Espinosa's avatar
Arturo Espinosa committed
643
{
644
645
646
647
648
	switch (value->type){
	case VALUE_STRING:
		printf ("STRING: %s\n", value->v.str->str);
		break;

649
	case VALUE_INTEGER:
Arturo Espinosa's avatar
Arturo Espinosa committed
650
		printf ("NUM: %d\n", value->v.v_int);
651
652
		break;

653
	case VALUE_FLOAT:
Arturo Espinosa's avatar
Arturo Espinosa committed
654
		printf ("Float: %f\n", value->v.v_float);
655
		break;
Arturo Espinosa's avatar
Arturo Espinosa committed
656
657

	case VALUE_ARRAY: {
658
659
		int x, y;
		
Arturo Espinosa's avatar
Arturo Espinosa committed
660
		printf ("Array: { ");
661
662
663
		for (x = 0; x < value->v.array.x; x++)
			for (y = 0; y < value->v.array.y; y++)
				value_dump (&value->v.array.vals [x][y]);
Arturo Espinosa's avatar
Arturo Espinosa committed
664
		printf ("}\n");
665
666
667
668
669
670
671
672
673
674
675
		break;
	}
	case VALUE_CELLRANGE: {
		CellRef *c = &value->v.cell_range.cell_a;
		printf ("CellRange\n");
		printf ("%p: %d,%d rel? %d,%d\n", c->sheet, c->col, c->row,
			c->col_relative, c->row_relative);
		c = &value->v.cell_range.cell_b;
		printf ("%p: %d,%d rel? %d,%d\n", c->sheet, c->col, c->row,
			c->col_relative, c->row_relative);
		break;
Arturo Espinosa's avatar
Arturo Espinosa committed
676
	}
677
678
679
680
681
682
	default:
		printf ("Unhandled item type\n");
	}
}

void
683
dump_tree (ExprTree *tree)
684
685
{
	Symbol *s;
686
	CellRef *cr;
687
	
688
	switch (tree->oper){
689
	case OPER_VAR:
Morten Welinder's avatar
Morten Welinder committed
690
		cr = &tree->u.ref;
691
		printf ("Cell: %s%c%s%d\n",
692
			cr->col_relative ? "" : "$",
693
			cr->col + 'A',
694
			cr->row_relative ? "" : "$",
695
696
697
			cr->row + '1');
		return;
		
698
	case OPER_CONSTANT:
699
		value_dump (tree->u.constant);
700
701
		return;

702
	case OPER_FUNCALL:
703
		s = symbol_lookup (global_symbol_table, tree->u.function.symbol->str);
704
705
		printf ("Function call: %s\n", s->str);
		break;
Arturo Espinosa's avatar
Arturo Espinosa committed
706

707
	case OPER_ANY_BINARY:
708
709
710
		dump_tree (tree->u.binary.value_a);
		dump_tree (tree->u.binary.value_b);
		switch (tree->oper){
711
712
713
714
715
716
717
718
719
720
721
722
		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;
723
724
725
726
727
		default:
			printf ("Error\n");
		}
		break;
		
728
	case OPER_NEG:
729
		dump_tree (tree->u.value);
730
731
732
733
734
		printf ("NEGATIVE\n");
		break;
		
	}
}
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761

ParseErr
gnumeric_expr_parser (const char *expr, Sheet *sheet, int col, int row,
		      const char **desired_format, ExprTree **result)
{
	parser_error = PARSE_OK;
	parser_expr = expr;
	parser_sheet = sheet;
	parser_col   = col;
	parser_row   = row;
	parser_desired_format = desired_format;
	parser_result = result;

	if (parser_desired_format)
		*parser_desired_format = NULL;

	yyparse ();

	if (parser_error == PARSE_OK)
		alloc_list_free ();
	else {
		alloc_clean ();
		*parser_result = NULL;
	}

	return parser_error;
}