GUI: reduce vertical size of the toolbar area
[gnumeric.git] / src / parser.y
blob9f084618511fdf6a44283d469ca494fd8a8fd422
1 %{
2 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * Gnumeric Parser
6 * (C) 1998-2002 GNOME Foundation
7 * Copyright (C) 2002-2009 Morten Welinder
9 * Authors:
10 * Miguel de Icaza (miguel@gnu.org)
11 * Jody Goldberg (jody@gnome.org)
12 * Morten Welinder (terra@diku.dk)
13 * Almer S. Tigelaar (almer@gnome.org)
15 #include <gnumeric-config.h>
16 #include <glib/gi18n-lib.h>
17 #include "gnumeric.h"
18 #include "number-match.h"
19 #include "expr.h"
20 #include "expr-impl.h"
21 #include "expr-name.h"
22 #include "func.h"
23 #include "workbook.h"
24 #include "sheet.h"
25 #include "gnm-format.h"
26 #include "application.h"
27 #include "parse-util.h"
28 #include "gutils.h"
29 #include "style.h"
30 #include "value.h"
31 #include <goffice/goffice.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <stdlib.h>
37 #define YYDEBUG 1
39 /* ------------------------------------------------------------------------- */
40 /* Allocation with disposal-on-error */
43 * If some dork enters "=1+2+2*(1+" we have already allocated space for
44 * "1+2", "2", and "1" before the parser sees the syntax error and warps
45 * us to the error production in the "line" non-terminal.
47 * To make sure we can clean up, we register every allocation. On success,
48 * nothing should be left (except the final expression which is unregistered),
49 * but on failure we must free everything allocated.
51 * Note: there is some room left for optimisation here. Talk to terra@diku.dk
52 * before you set out to do it.
55 static void
56 free_expr_list_list (GSList *list)
58 GSList *l;
59 for (l = list; l; l = l->next)
60 gnm_expr_list_unref (l->data);
61 g_slist_free (list);
64 typedef void (*ParseDeallocator) (void *);
65 static GPtrArray *deallocate_stack;
67 static void
68 deallocate_init (void)
70 deallocate_stack = g_ptr_array_new ();
73 static void
74 deallocate_uninit (void)
76 g_ptr_array_free (deallocate_stack, TRUE);
77 deallocate_stack = NULL;
80 static void
81 deallocate_all (void)
83 int i;
85 for (i = 0; i < (int)deallocate_stack->len; i += 2) {
86 ParseDeallocator freer = g_ptr_array_index (deallocate_stack, i + 1);
87 freer (g_ptr_array_index (deallocate_stack, i));
90 g_ptr_array_set_size (deallocate_stack, 0);
93 static void
94 deallocate_assert_empty (void)
96 if (deallocate_stack->len == 0)
97 return;
99 g_warning ("deallocate_stack not empty as expected.");
100 deallocate_all ();
103 static void *
104 register_allocation (gpointer data, ParseDeallocator freer)
106 /* It's handy to be able to register and unregister NULLs. */
107 if (data) {
108 int len;
110 * There are really only a few different freers, so we
111 * could encode the freer in the lower bits of the data
112 * pointer. Unfortunately, no-one can predict how high
113 * Miguel would jump when he found out.
115 len = deallocate_stack->len;
116 g_ptr_array_set_size (deallocate_stack, len + 2);
117 g_ptr_array_index (deallocate_stack, len) = data;
118 g_ptr_array_index (deallocate_stack, len + 1) = freer;
121 /* Returning the pointer here improved readability of the caller. */
122 return data;
125 #define register_expr_allocation(expr) \
126 register_allocation ((gpointer)(expr), (ParseDeallocator)&gnm_expr_free)
128 #define register_expr_list_allocation(list) \
129 register_allocation ((list), (ParseDeallocator)&gnm_expr_list_unref)
131 #define register_expr_list_list_allocation(list) \
132 register_allocation ((list), (ParseDeallocator)&free_expr_list_list)
134 static void
135 unregister_allocation (void const *data)
137 int i, pos;
139 /* It's handy to be able to register and unregister NULLs. */
140 if (!data)
141 return;
143 pos = deallocate_stack->len - 2;
144 if (pos >= 0 && data == g_ptr_array_index (deallocate_stack, pos)) {
145 g_ptr_array_set_size (deallocate_stack, pos);
146 return;
150 * Bummer. In certain error cases, it is possible that the parser
151 * will reduce after it has discovered a token that will lead to an
152 * error. "2/16/1800 00:00" (without the quotes) is an example.
153 * The first "00" is registered before the second division is
154 * reduced.
156 * Another example is 564077 where we deallocate out of order.
158 * This isn't a big deal -- we will just look at the entries below
159 * the top.
161 for (i = pos - 2; i >= 0; i -= 2) {
162 if (data == g_ptr_array_index (deallocate_stack, i)) {
163 g_ptr_array_remove_index (deallocate_stack, i);
164 g_ptr_array_remove_index (deallocate_stack, i);
165 return;
169 g_warning ("Unbalanced allocation registration");
172 /* ------------------------------------------------------------------------- */
174 /* Bison/Yacc internals */
175 static int yylex (void);
176 static int yyerror (char const *s);
178 typedef struct {
179 char const *ptr; /* current position of the lexer */
180 char const *start; /* start of the expression */
182 /* Location where the parsing is taking place */
183 GnmParsePos const *pos;
185 /* loaded from convs with locale specific mappings */
186 gunichar decimal_point;
187 gunichar arg_sep;
188 gunichar union_char;
189 gunichar array_col_sep;
190 gunichar array_row_sep;
191 /* if arg_sep conflicts with array_col_sep or array_row_sep */
192 int in_array_sep_is; /* token id */
194 GnmExprParseFlags flags;
195 GnmConventions const *convs;
197 /* dynamic state */
198 int in_array; /* toggled in the lexer for '{' and '}' */
199 GnmExprList *result;
201 GnmParseError *error;
202 } ParserState;
204 /* The error returned from the */
205 static ParserState *state;
207 static void
208 report_err (ParserState *state, GError *err,
209 char const *last, int guesstimate_of_length)
211 if (state->error != NULL) {
212 state->error->err = err;
213 state->error->end_char = last - state->start;
214 state->error->begin_char = state->error->end_char - guesstimate_of_length;
215 if (state->error->begin_char < 0)
216 state->error->begin_char = 0;
217 } else
218 g_error_free (err);
221 static gboolean
222 is_signed (const GnmExpr *expr)
224 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_UNARY_NEG)
225 return TRUE;
227 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_UNARY_PLUS)
228 return TRUE;
230 if (GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_CONSTANT) {
231 GnmValue const *v = expr->constant.value;
232 return VALUE_IS_FLOAT (v) && value_get_as_float (v) < 0;
235 return FALSE;
238 /* Handle -cst for use in arrays. Don't handle other types here. */
239 static GnmExpr *
240 fold_negative_constant (GnmExpr *expr)
242 if (expr && GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_CONSTANT) {
243 GnmValue *v = (GnmValue *)expr->constant.value;
245 if (VALUE_IS_FLOAT (v)) {
246 gnm_float f = value_get_as_float (v);
247 expr->constant.value = value_new_float (0 - f);
248 value_release (v);
249 return expr;
253 return NULL;
256 /* Handle +cst for use in arrays. Don't handle other types here. */
257 static GnmExpr *
258 fold_positive_constant (GnmExpr *expr)
260 if (expr && GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_CONSTANT) {
261 const GnmValue *v = expr->constant.value;
262 if (VALUE_IS_FLOAT (v))
263 return expr;
266 return NULL;
269 static GnmExpr *
270 build_unary_op (GnmExprOp op, GnmExpr *expr)
272 if (!expr) return NULL;
274 unregister_allocation (expr);
275 return register_expr_allocation (gnm_expr_new_unary (op, expr));
278 static GnmExpr *
279 build_binop (GnmExpr *l, GnmExprOp op, GnmExpr *r)
281 if (!l || !r) return NULL;
283 unregister_allocation (r);
284 unregister_allocation (l);
285 return register_expr_allocation (gnm_expr_new_binary (l, op, r));
288 static GnmExpr *
289 build_logical (GnmExpr *l, gboolean is_and, GnmExpr *r)
291 static GnmFunc *and_func = NULL, *or_func = NULL;
293 if (!l || !r) return NULL;
295 if (and_func == NULL)
296 and_func = gnm_func_lookup ("AND", NULL);
297 if (or_func == NULL)
298 or_func = gnm_func_lookup ("OR", NULL);
300 unregister_allocation (r);
301 unregister_allocation (l);
302 return register_expr_allocation
303 (gnm_expr_new_funcall2 (is_and ? and_func : or_func, l, r));
306 static GnmExpr *
307 build_not (GnmExpr *expr)
309 static GnmFunc *not_func = NULL;
311 if (!expr) return NULL;
313 if (not_func == NULL)
314 not_func = gnm_func_lookup ("NOT", NULL);
315 unregister_allocation (expr);
316 return register_expr_allocation
317 (gnm_expr_new_funcall1 (not_func, expr));
320 static GnmExpr *
321 build_exp (GnmExpr *l, GnmExpr *r)
323 if (is_signed (l)) {
324 /* See bug 115941 */
325 l = build_unary_op (GNM_EXPR_OP_PAREN, l);
328 if (GNM_EXPR_GET_OPER (l) == GNM_EXPR_OP_EXP) {
329 /* Add ()s to x^y^z */
330 l = build_unary_op (GNM_EXPR_OP_PAREN, l);
333 if (GNM_EXPR_GET_OPER (r) == GNM_EXPR_OP_EXP) {
334 /* Add ()s to x^y^z */
335 r = build_unary_op (GNM_EXPR_OP_PAREN, r);
338 return build_binop (l, GNM_EXPR_OP_EXP, r);
342 * Build an array expression.
344 * Returns NULL on failure. Caller must YYERROR in that case.
346 static GnmExpr *
347 build_array (GSList *cols)
349 GnmValue *array;
350 int mx, y;
352 if (!cols) {
353 report_err (state, g_error_new (1, PERR_INVALID_EMPTY,
354 _("An array must have at least 1 element")),
355 state->ptr, 0);
356 return NULL;
359 mx = g_list_length (cols->data);
360 array = value_new_array_empty (mx, g_slist_length (cols));
362 y = 0;
363 while (cols) {
364 GSList *row = cols->data;
365 int x = 0;
366 while (row && x < mx) {
367 GnmExpr const *expr = row->data;
368 GnmValue const *v = expr->constant.value;
370 g_assert (expr && GNM_EXPR_GET_OPER (expr) == GNM_EXPR_OP_CONSTANT);
372 value_array_set (array, x, y, value_dup (v));
374 x++;
375 row = row->next;
377 if (x < mx || row) {
378 /* parser_error = PARSE_ERR_SYNTAX; */
379 report_err (state, g_error_new (1, PERR_ASYMETRIC_ARRAY,
380 _("Arrays must be rectangular")),
381 state->ptr, 0);
382 value_release (array);
383 return NULL;
385 y++;
386 cols = cols->next;
389 return register_expr_allocation (gnm_expr_new_constant (array));
393 * Build a range constructor.
395 * Returns NULL on failure. Caller must YYERROR in that case.
397 static GnmExpr *
398 build_range_ctor (GnmExpr *l, GnmExpr *r, GnmExpr *validate)
400 if (!l || !r) return NULL;
402 if (validate != NULL) {
403 if (GNM_EXPR_GET_OPER (validate) != GNM_EXPR_OP_CELLREF ||
404 validate->cellref.ref.sheet != NULL) {
405 report_err (state, g_error_new (1, PERR_UNEXPECTED_TOKEN,
406 _("Constructed ranges use simple references")),
407 state->ptr, 0);
408 return NULL;
412 unregister_allocation (r);
413 unregister_allocation (l);
414 return register_expr_allocation (gnm_expr_new_range_ctor (l, r));
418 * Build an intersection expression.
420 * Returns NULL on failure. Caller must YYERROR in that case.
422 static GnmExpr *
423 build_intersect (GnmExpr *l, GnmExpr *r)
425 if (!l || !r) return NULL;
427 if (gnm_expr_is_rangeref (l) && gnm_expr_is_rangeref (r))
428 return build_binop (l, GNM_EXPR_OP_INTERSECT, r);
429 report_err (state, g_error_new (1, PERR_SET_CONTENT_MUST_BE_RANGE,
430 _("All entries in the set must be references")),
431 state->ptr, 0);
432 return NULL;
436 * Build a set expression.
438 * Returns NULL on failure. Caller must YYERROR in that case.
440 static GnmExpr *
441 build_set (GnmExprList *list)
443 /* verify that every thing is a ref */
444 GnmExprList *ptr;
445 for (ptr = list; ptr != NULL ; ptr = ptr->next) {
446 GnmExpr const *expr = ptr->data;
447 if (!expr || !gnm_expr_is_rangeref (expr)) {
448 report_err (state, g_error_new (1, PERR_SET_CONTENT_MUST_BE_RANGE,
449 _("All entries in the set must be references")),
450 state->ptr, 0);
451 return NULL;
455 unregister_allocation (list);
456 return register_expr_allocation (gnm_expr_new_set (list));
460 * parse_string_as_value:
462 * Try to parse the entered text as a basic value (empty, bool, int,
463 * gnm_float, err) if this succeeds, we store this as a GnmValue otherwise, we
464 * return a string.
466 static GnmExpr *
467 parse_string_as_value (GnmExpr *str)
469 GnmValue *v = format_match_simple (value_peek_string (str->constant.value));
471 if (v != NULL) {
472 unregister_allocation (str);
473 gnm_expr_free (str);
474 return register_expr_allocation (gnm_expr_new_constant (v));
476 return str;
479 static const GnmExpr *
480 parser_simple_name (const char *str, Sheet *sheet)
482 GnmExpr const *res;
483 GnmNamedExpr *nexpr;
485 if (sheet) {
486 GnmParsePos pp;
487 parse_pos_init_sheet (&pp, sheet);
488 nexpr = expr_name_lookup (&pp, str);
489 } else
490 nexpr = expr_name_lookup (state->pos, str);
492 if (nexpr == NULL) {
493 if (state->flags & GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_INVALID) {
494 GError *e;
495 e = sheet
496 ? g_error_new (1, PERR_UNKNOWN_NAME,
497 _("Name '%s' does not exist in sheet '%s'"),
498 str, sheet->name_quoted)
499 : g_error_new (1, PERR_UNKNOWN_NAME,
500 _("Name '%s' does not exist"),
501 str);
502 report_err (state, e, state->ptr, 0);
503 res = NULL;
504 } else if (!sheet && state->flags & GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS) {
505 res = gnm_expr_new_constant (value_new_string (str));
506 } else if (state->convs->input.name_validate (str)) {
507 GnmParsePos pp = *state->pos;
508 pp.sheet = sheet;
509 /* Create a place holder */
510 nexpr = expr_name_add (&pp, str, NULL, NULL, TRUE, NULL);
511 res = gnm_expr_new_name (nexpr, sheet, NULL);
512 } else {
513 report_err (state, g_error_new (1, PERR_UNKNOWN_NAME,
514 _("'%s' cannot be used as a name"),
515 str),
516 state->ptr, 0);
517 res = NULL;
519 } else
520 res = gnm_expr_new_name (nexpr, sheet, NULL);
522 return res;
526 * parser_simple_val_or_name:
527 * @str : An expression with oper constant, whose value is a string.
529 * Check to see if a string is a simple value or failing that a named
530 * expression, if it is not create a placeholder name for it.
532 static GnmExpr *
533 parser_simple_val_or_name (GnmExpr *str_expr)
535 GnmExpr const *res;
536 char const *str = value_peek_string (str_expr->constant.value);
537 GnmValue *v = format_match_simple (str);
539 /* if it is not a simple value see if it is a name */
540 if (v == NULL) {
541 res = parser_simple_name (str, NULL);
542 } else
543 res = gnm_expr_new_constant (v);
545 unregister_allocation (str_expr);
546 gnm_expr_free (str_expr);
547 return register_expr_allocation (res);
550 static Sheet *
551 parser_sheet_by_name (Workbook *wb, GnmExpr *name_expr)
553 char const *name = value_peek_string (name_expr->constant.value);
554 Sheet *sheet = NULL;
556 if (wb == NULL)
557 return NULL;
559 sheet = workbook_sheet_by_name (wb, name);
561 /* Applix has absolute and relative sheet references */
562 if (sheet == NULL && *name == '$' &&
563 state->convs->allow_absolute_sheet_references)
564 sheet = workbook_sheet_by_name (wb, name + 1);
566 if (sheet == NULL)
567 /* TODO : length is broken in the context of quoted names or
568 * names with escaped character */
569 /* -1 is a kludge. We know that this routine is only called
570 * when the last token was SHEET_SEP */
571 report_err (state, g_error_new (1, PERR_UNKNOWN_SHEET,
572 _("Unknown sheet '%s'"), name),
573 state->ptr-1, strlen (name));
575 return sheet;
578 /* Make byacc happier */
579 static int yyparse (void);
583 %union {
584 GnmExpr *expr;
585 GnmValue *value;
586 GnmCellRef *cell;
587 GnmExprList *list;
588 Sheet *sheet;
589 Workbook *wb;
591 %type <list> opt_exp arg_list array_row array_rows
592 %type <expr> exp array_exp function string_opt_quote cellref
593 %token <expr> STRING QUOTED_STRING CONSTANT RANGEREF tok_GTE tok_LTE tok_NE tok_AND tok_OR tok_NOT INTERSECT
594 %token ARG_SEP ARRAY_COL_SEP ARRAY_ROW_SEP SHEET_SEP INVALID_TOKEN
595 %type <sheet> sheetref
596 %type <wb> workbookref
597 %token <wb> tok_WORKBOOKREF
599 %left '<' '>' '=' tok_GTE tok_LTE tok_NE
600 %left '&'
601 %left '-' '+'
602 %left '*' '/'
603 %right tok_RIGHT_EXP
604 %left tok_LEFT_EXP
605 %nonassoc '%'
606 %nonassoc tok_NEG tok_PLUS tok_NOT
607 %left tok_AND tok_OR
608 %left ','
609 %left RANGE_INTERSECT
610 %left RANGE_SEP
613 line: opt_exp exp {
614 unregister_allocation ($2);
615 unregister_allocation ($1);
616 state->result = gnm_expr_list_prepend ($1, $2);
619 | error {
620 if (state->result != NULL) {
621 gnm_expr_list_unref (state->result);
622 state->result = NULL;
627 opt_exp : opt_exp exp ARG_SEP {
628 unregister_allocation ($2);
629 unregister_allocation ($1);
630 $$ = gnm_expr_list_prepend ($1, $2);
631 register_expr_list_allocation ($$);
633 | { $$ = NULL; register_expr_list_allocation ($$); }
636 exp: CONSTANT { $$ = $1; }
637 | QUOTED_STRING { $$ = $1; }
638 | STRING {
639 $$ = parser_simple_val_or_name ($1);
640 if ($$ == NULL) { YYERROR; }
642 | cellref { $$ = $1; }
643 | exp '+' exp { $$ = build_binop ($1, GNM_EXPR_OP_ADD, $3); }
644 | exp '-' exp { $$ = build_binop ($1, GNM_EXPR_OP_SUB, $3); }
645 | exp '*' exp { $$ = build_binop ($1, GNM_EXPR_OP_MULT, $3); }
646 | exp '/' exp { $$ = build_binop ($1, GNM_EXPR_OP_DIV, $3); }
647 | exp tok_RIGHT_EXP exp { $$ = build_exp ($1, $3); }
648 | exp tok_LEFT_EXP exp { $$ = build_exp ($1, $3); }
649 | exp '&' exp { $$ = build_binop ($1, GNM_EXPR_OP_CAT, $3); }
650 | exp '=' exp { $$ = build_binop ($1, GNM_EXPR_OP_EQUAL, $3); }
651 | exp '<' exp { $$ = build_binop ($1, GNM_EXPR_OP_LT, $3); }
652 | exp '>' exp { $$ = build_binop ($1, GNM_EXPR_OP_GT, $3); }
653 | exp tok_GTE exp { $$ = build_binop ($1, GNM_EXPR_OP_GTE, $3); }
654 | exp tok_NE exp { $$ = build_binop ($1, GNM_EXPR_OP_NOT_EQUAL, $3); }
655 | exp tok_LTE exp { $$ = build_binop ($1, GNM_EXPR_OP_LTE, $3); }
656 | exp tok_AND exp { $$ = build_logical ($1, TRUE, $3); }
657 | exp tok_OR exp { $$ = build_logical ($1, FALSE, $3); }
658 | exp RANGE_INTERSECT exp {
659 $$ = build_intersect ($1, $3);
660 if ($$ == NULL) { YYERROR; }
663 | '-' exp %prec tok_NEG {
664 GnmExpr *tmp = fold_negative_constant ($2);
665 $$ = tmp ? tmp : build_unary_op (GNM_EXPR_OP_UNARY_NEG, $2);
667 | '+' exp %prec tok_PLUS {
668 /* Don't fold here. */
669 $$ = build_unary_op (GNM_EXPR_OP_UNARY_PLUS, $2);
671 | tok_NOT exp { $$ = build_not ($2); }
672 | exp '%' { $$ = build_unary_op (GNM_EXPR_OP_PERCENTAGE, $1); }
674 | '(' arg_list ')' {
675 if ($2 == NULL) {
676 report_err (state, g_error_new (1, PERR_INVALID_EMPTY,
677 _("() is an invalid expression")),
678 state->ptr-2, 2);
679 YYERROR;
680 } else {
681 if ($2->next == NULL) {
682 unregister_allocation ($2);
683 $$ = register_expr_allocation (gnm_expr_new_unary (GNM_EXPR_OP_PAREN, $2->data));
684 /* NOTE : free list not content */
685 gnm_expr_list_free ($2);
686 } else {
687 $$ = build_set ($2);
688 if ($$ == NULL) { YYERROR; }
692 | '{' array_rows '}' {
693 unregister_allocation ($2);
694 $$ = build_array ($2);
695 free_expr_list_list ($2);
696 if ($$ == NULL) { YYERROR; }
699 | function
700 | sheetref STRING {
701 char const *name = value_peek_string ($2->constant.value);
702 GnmExpr const *ename = parser_simple_name (name, $1);
704 if (ename) {
705 unregister_allocation ($2); gnm_expr_free ($2);
706 $$ = register_expr_allocation (ename);
707 } else {
708 YYERROR;
711 | workbookref STRING {
712 GnmNamedExpr *nexpr = NULL;
713 char const *name = value_peek_string ($2->constant.value);
714 GnmParsePos pos = *state->pos;
716 pos.sheet = NULL;
717 pos.wb = $1;
718 nexpr = expr_name_lookup (&pos, name);
719 if (nexpr != NULL) {
720 unregister_allocation ($2); gnm_expr_free ($2);
721 $$ = register_expr_allocation (gnm_expr_new_name (nexpr, NULL, $1));
722 } else {
723 report_err (state, g_error_new (1, PERR_UNKNOWN_NAME,
724 _("Name '%s' does not exist in workbook"),
725 name),
726 state->ptr, strlen (name));
727 YYERROR;
732 function : STRING '(' arg_list ')' {
733 char const *name = value_peek_string ($1->constant.value);
734 GnmExpr const *f_call = (*state->convs->input.func) (
735 state->convs, state->pos->wb, name, $3);
737 $$ = NULL;
738 if (f_call) {
739 /* We're done with the function name. */
740 unregister_allocation ($1); gnm_expr_free ($1);
741 unregister_allocation ($3);
742 $$ = register_expr_allocation (f_call);
743 } else {
744 YYERROR;
749 string_opt_quote : STRING
750 | QUOTED_STRING
753 opt_sheet_sep : SHEET_SEP
756 /* only used for names */
757 workbookref : tok_WORKBOOKREF opt_sheet_sep
758 | '[' string_opt_quote ']' {
759 char const *wb_name = value_peek_string ($2->constant.value);
760 Workbook *ref_wb = state->pos
761 ? (state->pos->wb
762 ? state->pos->wb
763 : (state->pos->sheet
764 ? state->pos->sheet->workbook
765 : NULL))
766 : NULL;
767 Workbook *wb =
768 state->convs->input.external_wb (state->convs,
769 ref_wb,
770 wb_name);
772 if (wb != NULL) {
773 unregister_allocation ($2); gnm_expr_free ($2);
774 $$ = wb;
775 } else {
776 /* kludge to produce better error messages
777 * we know that the last token read will be the ']'
778 * so subtract 1.
780 report_err (state, g_error_new (1, PERR_UNKNOWN_WORKBOOK,
781 _("Unknown workbook '%s'"), wb_name),
782 state->ptr - 1, strlen (wb_name));
783 YYERROR;
786 | '[' ']' {
787 /* Special syntax for global names shadowed by sheet names. */
788 Workbook *wb = state->pos
789 ? (state->pos->wb
790 ? state->pos->wb
791 : (state->pos->sheet
792 ? state->pos->sheet->workbook
793 : NULL))
794 : NULL;
795 $$ = wb;
796 if (wb == NULL) {
797 report_err (state, g_error_new (1, PERR_UNKNOWN_WORKBOOK,
798 _("Unknown workbook")),
799 state->ptr - 1, 1);
800 YYERROR;
805 /* does not need to handle 3d case. this is only used for names.
806 * 3d cell references are handled in the lexer
808 sheetref: string_opt_quote SHEET_SEP {
809 Sheet *sheet = parser_sheet_by_name (state->pos->wb, $1);
810 if (sheet != NULL) {
811 unregister_allocation ($1); gnm_expr_free ($1);
812 $$ = sheet;
813 } else {
814 YYERROR;
817 | workbookref string_opt_quote SHEET_SEP {
818 Workbook *wb = $1;
819 Sheet *sheet = parser_sheet_by_name (wb, $2);
820 if (sheet != NULL) {
821 unregister_allocation ($2); gnm_expr_free ($2);
822 $$ = sheet;
823 } else {
824 YYERROR;
829 cellref: RANGEREF { $$ = $1; }
830 | function RANGE_SEP function {
831 $$ = build_range_ctor ($1, $3, NULL);
832 if ($$ == NULL) { YYERROR; }
834 | RANGEREF RANGE_SEP function {
835 $$ = build_range_ctor ($1, $3, $1);
836 if ($$ == NULL) { YYERROR; }
838 | function RANGE_SEP RANGEREF {
839 $$ = build_range_ctor ($1, $3, $3);
840 if ($$ == NULL) { YYERROR; }
842 | RANGEREF RANGE_SEP RANGEREF {
843 $$ = build_range_ctor ($1, $3, NULL);
844 if ($$ == NULL) { YYERROR; }
848 arg_list: exp {
849 unregister_allocation ($1);
850 $$ = gnm_expr_list_prepend (NULL, $1);
851 register_expr_list_allocation ($$);
853 | exp ARG_SEP arg_list {
854 GSList *tmp = $3;
855 unregister_allocation ($3);
856 unregister_allocation ($1);
858 if (tmp == NULL)
859 tmp = gnm_expr_list_prepend (NULL, gnm_expr_new_constant (value_new_empty ()));
861 $$ = gnm_expr_list_prepend (tmp, $1);
862 register_expr_list_allocation ($$);
864 | ARG_SEP arg_list {
865 GSList *tmp = $2;
866 unregister_allocation ($2);
868 if (tmp == NULL)
869 tmp = gnm_expr_list_prepend (NULL, gnm_expr_new_constant (value_new_empty ()));
871 $$ = gnm_expr_list_prepend (tmp, gnm_expr_new_constant (value_new_empty ()));
872 register_expr_list_allocation ($$);
874 | { $$ = NULL; }
877 array_exp: CONSTANT { $$ = $1; }
878 | '-' CONSTANT {
879 GnmExpr *tmp = fold_negative_constant ($2);
880 if (!tmp) { YYERROR; }
881 $$ = tmp;
883 | '+' CONSTANT {
884 GnmExpr *tmp = fold_positive_constant ($2);
885 if (!tmp) { YYERROR; }
886 $$ = tmp;
888 | string_opt_quote { $$ = parse_string_as_value ($1); }
892 array_row : { $$ = NULL; }
893 | array_exp {
894 unregister_allocation ($1);
895 $$ = g_slist_prepend (NULL, $1);
896 register_expr_list_allocation ($$);
898 | array_exp ARRAY_COL_SEP array_row {
899 unregister_allocation ($3);
900 unregister_allocation ($1);
901 $$ = g_slist_prepend ($3, $1);
902 register_expr_list_allocation ($$);
906 array_rows: array_row {
907 unregister_allocation ($1);
908 $$ = g_slist_prepend (NULL, $1);
909 register_expr_list_list_allocation ($$);
911 | array_row ARRAY_ROW_SEP array_rows {
912 unregister_allocation ($3);
913 unregister_allocation ($1);
914 $$ = g_slist_prepend ($3, $1);
915 register_expr_list_list_allocation ($$);
921 static char const *
922 find_matching_close (char const *str, char const **res)
924 while (*str) {
925 if (*str == '(') {
926 char const *tmp = str;
927 str = find_matching_close (str + 1, res);
928 if (*str != ')' && *res == NULL) {
929 *res = tmp;
930 return str;
932 if (*str == 0)
933 return str;
934 } else if (*str == ')')
935 return str;
936 else if (*str == '\'' || *str == '\"') {
937 GString *dummy = g_string_new (NULL);
938 char const *end = go_strunescape (dummy, str);
939 g_string_free (dummy, TRUE);
940 if (end == NULL)
941 return str + strlen (str);
942 str = end;
943 continue; /* skip incrementing str */
945 str = g_utf8_next_char (str);
948 return str;
951 static inline int
952 eat_space (ParserState *state, int res)
954 /* help the user by ignoring pointless spaces after an
955 * arg_sep. We know they are going to be errors and
956 * the spaces can not be operators in this context */
957 while (*state->ptr == ' ')
958 state->ptr++;
959 return res;
963 * Do we want to ignore space before a given character?
965 static gboolean
966 ignore_space_before (gunichar c)
968 switch (c) {
969 case '*': case '/': case '+': case '-': case '%': case '^': case '&':
970 case '>': case '<': case '=':
971 case ')':
972 case '#':
973 case '"': case '\'': /* Refers to opening quote only. */
974 case UNICODE_LOGICAL_NOT_C:
975 case UNICODE_LOGICAL_AND_C:
976 case UNICODE_LOGICAL_OR_C:
977 case UNICODE_MINUS_SIGN_C:
978 case UNICODE_DIVISION_SLASH_C:
979 case UNICODE_NOT_EQUAL_TO_C:
980 case UNICODE_LESS_THAN_OR_EQUAL_TO_C:
981 case UNICODE_GREATER_THAN_OR_EQUAL_TO_C:
982 case 0:
983 return TRUE;
984 default:
985 return FALSE;
990 * Do we want to ignore space after a given character?
992 static gboolean
993 ignore_space_after (gunichar c)
995 switch (c) {
996 case '*': case '/': case '+': case '-': case '%': case '^': case '&':
997 case '>': case '<': case '=':
998 case '(':
999 case '"': case '\'': /* Refers to closing quote only [not actually hit]. */
1000 case UNICODE_LOGICAL_NOT_C:
1001 case UNICODE_LOGICAL_AND_C:
1002 case UNICODE_LOGICAL_OR_C:
1003 case UNICODE_MINUS_SIGN_C:
1004 case UNICODE_DIVISION_SLASH_C:
1005 case UNICODE_NOT_EQUAL_TO_C:
1006 case UNICODE_LESS_THAN_OR_EQUAL_TO_C:
1007 case UNICODE_GREATER_THAN_OR_EQUAL_TO_C:
1008 case 0:
1009 return TRUE;
1010 default:
1011 return FALSE;
1015 static gboolean
1016 open_paren (const char *p)
1018 while (g_unichar_isspace (g_utf8_get_char (p)))
1019 p = g_utf8_next_char (p);
1020 return *p == '(';
1023 static int
1024 yylex (void)
1026 gunichar c, tmp;
1027 char const *start, *end;
1028 GnmRangeRef ref;
1029 gboolean is_number = FALSE;
1030 gboolean is_space = FALSE;
1031 gboolean error_token = FALSE;
1034 * Some special logic to handle space as intersection char.
1035 * Any number of white space characters are treated as one
1036 * intersecton.
1038 * Also, if we are not using space for that, drop spaces.
1040 while (g_unichar_isspace (g_utf8_get_char (state->ptr))) {
1041 state->ptr = g_utf8_next_char (state->ptr);
1042 is_space = TRUE;
1044 if (is_space && state->convs->intersection_char == ' ' &&
1045 !ignore_space_before (g_utf8_get_char (state->ptr)))
1046 return RANGE_INTERSECT;
1048 start = state->ptr;
1049 c = g_utf8_get_char (start);
1050 if (c == 0)
1051 return 0;
1052 state->ptr = g_utf8_next_char (state->ptr);
1054 if (c == state->convs->intersection_char)
1055 return RANGE_INTERSECT;
1057 if (c == '&' && state->convs->decode_ampersands) {
1058 if (!strncmp (state->ptr, "amp;", 4)) {
1059 state->ptr += 4;
1060 return '&';
1063 if (!strncmp (state->ptr, "lt;", 3)) {
1064 state->ptr += 3;
1065 if (*state->ptr == '='){
1066 state->ptr++;
1067 return tok_LTE;
1069 if (!strncmp (state->ptr, "&gt;", 4)) {
1070 state->ptr += 4;
1071 return tok_NE;
1073 return '<';
1075 if (!strncmp (state->ptr, "gt;", 3)) {
1076 state->ptr += 3;
1077 if (*state->ptr == '='){
1078 state->ptr++;
1079 return tok_GTE;
1081 return '>';
1083 if (!strncmp (state->ptr, "apos;", 5) ||
1084 !strncmp (state->ptr, "quot;", 5)) {
1085 char const *quotes_end;
1086 char const *p;
1087 char *string, *s;
1088 GnmValue *v;
1090 if (*state->ptr == 'q') {
1091 quotes_end = "&quot;";
1092 c = '\"';
1093 } else {
1094 quotes_end = "&apos;";
1095 c = '\'';
1098 state->ptr += 5;
1099 p = state->ptr;
1100 double_quote_loop:
1101 state->ptr = strstr (state->ptr, quotes_end);
1102 if (!*state->ptr) {
1103 report_err (state, g_error_new (1, PERR_MISSING_CLOSING_QUOTE,
1104 _("Could not find matching closing quote")),
1105 p, 1);
1106 return INVALID_TOKEN;
1108 if (!strncmp (state->ptr + 6, quotes_end, 6)) {
1109 state->ptr += 2 * 6;
1110 goto double_quote_loop;
1113 s = string = g_malloc (1 + state->ptr - p);
1114 while (p != state->ptr) {
1115 if (*p == '&') {
1116 if (!strncmp (p, "&amp;", 5)) {
1117 p += 5;
1118 *s++ = '&';
1119 continue;
1120 } else if (!strncmp (p, "&lt;", 4)) {
1121 p += 4;
1122 *s++ = '<';
1123 continue;
1124 } else if (!strncmp (p, "&gt;", 4)) {
1125 p += 4;
1126 *s++ = '>';
1127 continue;
1128 } else if (!strncmp (p, quotes_end, 6)) {
1129 p += 12; /* two in a row is the escape mechanism */
1130 *s++ = c;
1131 continue;
1132 } else if (!strncmp (p, "&quot;", 6)) {
1133 p += 6;
1134 *s++ = '\"';
1135 continue;
1136 } else if (!strncmp (p, "&apos;", 6)) {
1137 p += 6;
1138 *s++ = '\'';
1139 continue;
1142 *s++ = *p++;
1145 *s = 0;
1146 state->ptr += 6;
1148 v = value_new_string_nocopy (string);
1149 yylval.expr = register_expr_allocation (gnm_expr_new_constant (v));
1150 return QUOTED_STRING;
1154 if (c == ':' && state->convs->range_sep_colon)
1155 return eat_space (state, RANGE_SEP);
1157 if (c == state->convs->sheet_name_sep)
1158 return eat_space (state, SHEET_SEP);
1160 if (c == '.' && *state->ptr == '.' && state->convs->range_sep_dotdot) {
1161 state->ptr++;
1162 return RANGE_SEP;
1165 if (c == '#' && state->convs->accept_hash_logicals) {
1166 if (!strncmp (state->ptr, "NOT#", 4)) {
1167 state->ptr += 4;
1168 return eat_space (state, tok_NOT);
1170 if (!strncmp (state->ptr, "AND#", 4)) {
1171 state->ptr += 4;
1172 return eat_space (state, tok_AND);
1174 if (!strncmp (state->ptr, "OR#", 3)) {
1175 state->ptr += 3;
1176 return eat_space (state, tok_OR);
1180 if (c == state->arg_sep)
1181 return eat_space (state, state->in_array ? state->in_array_sep_is : ARG_SEP);
1182 if ((c == state->union_char) && (state->union_char != 0))
1183 return eat_space (state, ARG_SEP);
1184 if (c == state->array_col_sep)
1185 return eat_space (state, ARRAY_COL_SEP);
1186 if (c == state->array_row_sep)
1187 return eat_space (state, ARRAY_ROW_SEP);
1189 end = state->convs->input.range_ref (&ref, start,
1190 state->pos, state->convs);
1192 * In order to parse "LOG10(1024)" in sheets with more than ~8500
1193 * columns we do not consider anything a rangeref if it is followed
1194 * by an opening parenthesis.
1196 if (start != end && !open_paren (end)) {
1197 state->ptr = end;
1198 if (invalid_sheet == ref.a.sheet) {
1199 yylval.expr = register_expr_allocation
1200 (gnm_expr_new_constant
1201 (value_new_error_REF (NULL)));
1202 return CONSTANT;
1204 if (state->flags & GNM_EXPR_PARSE_FORCE_ABSOLUTE_REFERENCES) {
1205 if (ref.a.col_relative) {
1206 ref.a.col += state->pos->eval.col;
1207 ref.a.col_relative = FALSE;
1209 if (ref.b.col_relative) {
1210 ref.b.col += state->pos->eval.col;
1211 ref.b.col_relative = FALSE;
1213 if (ref.a.row_relative) {
1214 ref.a.row += state->pos->eval.row;
1215 ref.a.row_relative = FALSE;
1217 if (ref.b.row_relative) {
1218 ref.b.row += state->pos->eval.row;
1219 ref.b.row_relative = FALSE;
1221 } else if (state->flags & GNM_EXPR_PARSE_FORCE_RELATIVE_REFERENCES) {
1222 if (!ref.a.col_relative) {
1223 ref.a.col -= state->pos->eval.col;
1224 ref.a.col_relative = TRUE;
1226 if (!ref.b.col_relative) {
1227 ref.b.col -= state->pos->eval.col;
1228 ref.b.col_relative = TRUE;
1230 if (!ref.a.row_relative) {
1231 ref.a.row -= state->pos->eval.row;
1232 ref.a.row_relative = TRUE;
1234 if (!ref.b.row_relative) {
1235 ref.b.row -= state->pos->eval.row;
1236 ref.b.row_relative = TRUE;
1240 if (ref.a.sheet == NULL && (state->flags & GNM_EXPR_PARSE_FORCE_EXPLICIT_SHEET_REFERENCES)) {
1241 ref.a.sheet = state->pos->sheet;
1242 if (ref.a.sheet == NULL) {
1243 report_err (state, g_error_new (1, PERR_SHEET_IS_REQUIRED,
1244 _("Sheet name is required")),
1245 state->ptr, 0);
1246 return INVALID_TOKEN;
1250 if ((ref.b.sheet == NULL || ref.b.sheet == ref.a.sheet) &&
1251 ref.a.col == ref.b.col &&
1252 ref.a.col_relative == ref.b.col_relative &&
1253 ref.a.row == ref.b.row &&
1254 ref.a.row_relative == ref.b.row_relative) {
1255 yylval.expr = register_expr_allocation (gnm_expr_new_cellref (&ref.a));
1256 return RANGEREF;
1258 yylval.expr = register_expr_allocation (gnm_expr_new_constant (
1259 value_new_cellrange_unsafe (&ref.a, &ref.b)));
1260 return RANGEREF;
1263 /* Do NOT handle negative numbers here. That has to be done in the
1264 * parser otherwise we mishandle A1-1 when it looks like
1265 * rangeref CONSTANT */
1266 if (c == state->decimal_point) {
1267 /* Could be a number or a stand alone */
1268 if (!g_unichar_isdigit (g_utf8_get_char (state->ptr)))
1269 return c;
1270 is_number = TRUE;
1271 } else if (g_unichar_isdigit (c)) {
1272 /* find the end of the first portion of the number */
1273 do {
1274 c = g_utf8_get_char (state->ptr);
1275 state->ptr = g_utf8_next_char (state->ptr);
1276 } while (g_unichar_isdigit (c));
1277 is_number = TRUE;
1278 if (c == 0)
1279 state->ptr--;
1282 if (is_number) {
1283 GnmValue *v = NULL;
1285 if (c == state->decimal_point || c == 'e' || c == 'E') {
1286 /* This is a floating point number */
1287 char *end;
1288 gnm_float d;
1290 errno = 0;
1291 d = gnm_utf8_strto (start, &end);
1292 if (start == end) {
1293 g_warning ("%s is not a double, but was expected to be one", start);
1294 } else if (errno != ERANGE) {
1295 v = value_new_float (d);
1296 state->ptr = end;
1297 } else if (c != 'e' && c != 'E') {
1298 report_err (state, g_error_new (1, PERR_OUT_OF_RANGE,
1299 _("The number is out of range")),
1300 state->ptr, end - start);
1301 return INVALID_TOKEN;
1302 } else {
1303 /* For an exponent it's hard to highlight the
1304 * right region w/o it turning into an ugly
1305 * hack, for now the cursor is put at the end.
1307 report_err (state, g_error_new (1, PERR_OUT_OF_RANGE,
1308 _("The number is out of range")),
1309 state->ptr, 0);
1310 return INVALID_TOKEN;
1312 } else {
1313 char *end;
1314 long l;
1316 l = gnm_utf8_strtol (start, &end);
1317 if (start == end) {
1318 g_warning ("%s is not an integer, but was expected to be one", start);
1319 } else if (errno != ERANGE && l >= INT_MIN && l <= INT_MAX) {
1320 v = value_new_int (l);
1321 state->ptr = end;
1322 } else {
1323 gnm_float d;
1325 errno = 0;
1326 d = gnm_utf8_strto (start, &end);
1327 if (errno != ERANGE) {
1328 v = value_new_float (d);
1329 state->ptr = end;
1330 } else {
1331 report_err (state, g_error_new (1, PERR_OUT_OF_RANGE,
1332 _("The number is out of range")),
1333 state->ptr, end - start);
1334 return INVALID_TOKEN;
1339 /* Very odd string, Could be a bound problem. Trigger an error */
1340 if (v == NULL)
1341 return c;
1343 yylval.expr = register_expr_allocation (gnm_expr_new_constant (v));
1344 return CONSTANT;
1347 switch (c) {
1348 case '#':
1349 if (state->ptr[0] != '"') {
1350 while ((tmp = g_utf8_get_char (state->ptr)) != 0 &&
1351 !g_unichar_isspace (tmp)) {
1352 state->ptr = g_utf8_next_char (state->ptr);
1353 if (tmp == '!' || tmp == '?' ||
1354 ((state->ptr - start) == 4 && 0 == strncmp (start, "#N/A", 4))) {
1355 GOString *name = go_string_new_nocopy (g_strndup (start, state->ptr - start));
1356 yylval.expr = register_expr_allocation
1357 (gnm_expr_new_constant (
1358 value_new_error_str (NULL, name)));
1359 go_string_unref (name);
1360 return CONSTANT;
1364 report_err (state, g_error_new
1365 (1, PERR_UNEXPECTED_TOKEN,
1366 _("Improperly formatted error token")),
1367 state->ptr, state->ptr - start);
1369 return INVALID_TOKEN;
1371 error_token = TRUE;
1372 start++;
1373 /* Fall through */
1374 case '\'':
1375 case '"': {
1376 GString *s = g_string_new (NULL);
1377 char const *end = state->convs->input.string (start, s, state->convs);
1379 if (end == NULL) {
1380 size_t len = strlen (start);
1381 g_string_free (s, TRUE);
1382 report_err (state,
1383 g_error_new (1, PERR_MISSING_CLOSING_QUOTE,
1384 _("Could not find matching closing quote")),
1385 start + len, len);
1386 return INVALID_TOKEN;
1389 state->ptr = (char *)end;
1391 if (error_token) {
1392 GnmValue *v = value_new_error (NULL, s->str);
1393 yylval.expr = register_expr_allocation (gnm_expr_new_constant (v));
1394 g_string_free (s, TRUE);
1395 return eat_space (state, CONSTANT);
1396 } else {
1397 GnmValue *v = value_new_string_nocopy (g_string_free (s, FALSE));
1398 yylval.expr = register_expr_allocation (gnm_expr_new_constant (v));
1399 return eat_space (state, QUOTED_STRING);
1403 case '[': {
1404 const char *p = state->ptr;
1405 GString *s = g_string_new (NULL);
1406 Workbook *ref_wb = state->pos
1407 ? (state->pos->wb
1408 ? state->pos->wb
1409 : (state->pos->sheet
1410 ? state->pos->sheet->workbook
1411 : NULL))
1412 : NULL;
1414 while (g_unichar_isspace (g_utf8_get_char (p)))
1415 p = g_utf8_next_char (p);
1417 if (p[0] == '"' || p[0] == '\'') {
1418 p = go_strunescape (s, p);
1419 } else {
1420 gunichar uc;
1421 while (1) {
1422 uc = g_utf8_get_char (p);
1423 if (!uc || uc == ']' || g_unichar_isspace (uc))
1424 break;
1425 p = g_utf8_next_char (p);
1426 g_string_append_unichar (s, uc);
1430 while (p && g_unichar_isspace (g_utf8_get_char (p)))
1431 p = g_utf8_next_char (p);
1433 if (s->len == 0 || !p || p[0] != ']') {
1434 g_string_free (s, TRUE);
1435 break;
1438 yylval.wb = state->convs->input.external_wb (state->convs,
1439 ref_wb,
1440 s->str);
1441 g_string_free (s, TRUE);
1442 if (!yylval.wb)
1443 break;
1445 state->ptr = p + 1;
1446 return tok_WORKBOOKREF;
1450 if ((end = state->convs->input.name (start, state->convs))) {
1451 state->ptr = end;
1452 yylval.expr = register_expr_allocation (gnm_expr_new_constant (
1453 value_new_string_nocopy (g_strndup (start, state->ptr - start))));
1454 return STRING;
1457 switch (c) {
1458 case '<':
1459 if (*state->ptr == '='){
1460 state->ptr++;
1461 return eat_space (state, tok_LTE);
1463 if (*state->ptr == '>'){
1464 state->ptr++;
1465 return eat_space (state, tok_NE);
1467 return eat_space (state, c);
1469 case '>':
1470 if (*state->ptr == '='){
1471 state->ptr++;
1472 return eat_space (state, tok_GTE);
1474 return eat_space (state, c);
1476 case '\n': return 0;
1478 case '{':
1479 state->in_array++;
1480 return c;
1481 case '}':
1482 state->in_array--;
1483 return c;
1485 case '^':
1486 return state->convs->exp_is_left_associative
1487 ? tok_LEFT_EXP
1488 : tok_RIGHT_EXP;
1490 case UNICODE_LOGICAL_NOT_C: return tok_NOT;
1491 case UNICODE_MINUS_SIGN_C: return '-';
1492 case UNICODE_DIVISION_SLASH_C: return '/';
1493 case UNICODE_LOGICAL_AND_C: return tok_AND;
1494 case UNICODE_LOGICAL_OR_C: return tok_OR;
1495 case UNICODE_NOT_EQUAL_TO_C: return eat_space (state, tok_NE);
1496 case UNICODE_LESS_THAN_OR_EQUAL_TO_C: return eat_space (state, tok_LTE);
1497 case UNICODE_GREATER_THAN_OR_EQUAL_TO_C: return eat_space (state, tok_GTE);
1500 if (ignore_space_after (c))
1501 return eat_space (state, c);
1502 else
1503 return c;
1507 yyerror (char const *s)
1509 #if 0
1510 g_printerr ("Error: %s\n", s);
1511 #endif
1512 return 0;
1515 static void
1516 setup_state (ParserState *pstate, const char *str,
1517 GnmParsePos const *pp,
1518 GnmExprParseFlags flags,
1519 GnmConventions const *convs,
1520 GnmParseError *error)
1522 pstate->start = pstate->ptr = str;
1523 pstate->pos = pp;
1525 pstate->flags = flags;
1526 pstate->convs =
1527 (NULL != convs) ? convs : ((NULL != pp->sheet) ? pp->sheet->convs : gnm_conventions_default);
1530 pstate->decimal_point = pstate->convs->decimal_sep_dot
1531 ? '.'
1532 : g_utf8_get_char (go_locale_get_decimal ()->str); /* FIXME: one char handled. */
1534 if (pstate->convs->arg_sep != 0)
1535 pstate->arg_sep = pstate->convs->arg_sep;
1536 else
1537 pstate->arg_sep = go_locale_get_arg_sep ();
1538 pstate->union_char = pstate->convs->union_char;
1539 if (pstate->convs->array_col_sep != 0)
1540 pstate->array_col_sep = pstate->convs->array_col_sep;
1541 else
1542 pstate->array_col_sep = go_locale_get_col_sep ();
1543 if (pstate->convs->array_row_sep != 0)
1544 pstate->array_row_sep = pstate->convs->array_row_sep;
1545 else
1546 pstate->array_row_sep = go_locale_get_row_sep ();
1548 /* Some locales/conventions have ARG_SEP == ARRAY_ROW_SEP
1549 * eg {1\2\3;4\5\6} for XL style with ',' as a decimal
1550 * some have ARG_SEP == ARRAY_COL_SEPARATOR
1551 * eg {1,2,3;4,5,6} for XL style with '.' as a decimal
1552 * or {1;2;3|4;5;6} for OOo/
1553 * keep track of whether we are in an array to allow the lexer to
1554 * dis-ambiguate. */
1555 if (pstate->arg_sep == pstate->array_col_sep)
1556 pstate->in_array_sep_is = ARRAY_COL_SEP;
1557 else if (pstate->arg_sep == pstate->array_row_sep)
1558 pstate->in_array_sep_is = ARRAY_ROW_SEP;
1559 else
1560 pstate->in_array_sep_is = ARG_SEP;
1561 pstate->in_array = 0;
1563 pstate->result = NULL;
1564 pstate->error = error;
1566 state = pstate;
1570 * gnm_expr_parse_str:
1572 * @str : The string to parse.
1573 * @pp : #GnmParsePos
1574 * @flags : See parse-utils for descriptions
1575 * @convs : optionally NULL #GnmConventions
1576 * @error : optionally NULL ptr to store details of error.
1578 * Parse a string. if @error is non-null it will be assumed that the
1579 * caller has passed a pointer to a GnmParseError struct AND that it will
1580 * take responsibility for freeing that struct and its contents.
1581 * with parse_error_free.
1582 * If @convs is NULL use the conventions from @pp.
1584 GnmExprTop const *
1585 gnm_expr_parse_str (char const *str, GnmParsePos const *pp,
1586 GnmExprParseFlags flags,
1587 GnmConventions const *convs,
1588 GnmParseError *error)
1590 GnmExpr const *expr;
1591 ParserState pstate;
1593 g_return_val_if_fail (str != NULL, NULL);
1594 g_return_val_if_fail (pp != NULL, NULL);
1595 g_return_val_if_fail (state == NULL, NULL);
1597 if (deallocate_stack == NULL)
1598 deallocate_init ();
1600 setup_state (&pstate, str, pp, flags, convs, error);
1601 yyparse ();
1602 state = NULL;
1604 if (pstate.result != NULL) {
1605 deallocate_assert_empty ();
1607 #if 0
1608 /* If this happens, something is very wrong */
1609 if (pstate.error != NULL && pstate.error->message != NULL) {
1610 g_warning ("An error occurred and the GnmExpr is non-null! This should not happen");
1611 g_warning ("Error message is %s (%d, %d)", pstate.error->message, pstate.error->begin_char,
1612 pstate.error->end_char);
1614 #endif
1616 /* Do we have multiple expressions */
1617 if (pstate.result->next != NULL) {
1618 if (flags & GNM_EXPR_PARSE_PERMIT_MULTIPLE_EXPRESSIONS)
1619 expr = gnm_expr_new_set (g_slist_reverse (pstate.result));
1620 else {
1621 gnm_expr_list_unref (pstate.result);
1622 report_err (&pstate, g_error_new (1, PERR_MULTIPLE_EXPRESSIONS,
1623 _("Multiple expressions are not supported in this context")),
1624 pstate.start,
1625 (pstate.ptr - pstate.start));
1626 expr = NULL;
1628 } else {
1629 /* Free the list, do not unref the content */
1630 expr = pstate.result->data;
1631 gnm_expr_list_free (pstate.result);
1633 } else {
1634 /* If there is no error message, attempt to be more detailed */
1635 if (pstate.error != NULL &&
1636 (pstate.error->err == NULL || pstate.error->err->message == NULL)) {
1637 char const *last_token = pstate.ptr;
1639 if (*last_token == '\0') {
1640 char const *str = pstate.start;
1641 char const *res = NULL;
1642 char const *last = find_matching_close (str, &res);
1644 if (*last)
1645 report_err (&pstate, g_error_new (1, PERR_MISSING_PAREN_OPEN,
1646 _("Could not find matching opening parenthesis")),
1647 last, 1);
1648 else if (res != NULL)
1649 report_err (&pstate, g_error_new (1, PERR_MISSING_PAREN_CLOSE,
1650 _("Could not find matching closing parenthesis")),
1651 res, 1);
1652 else
1653 report_err (&pstate, g_error_new (1, PERR_INVALID_EXPRESSION,
1654 _("Invalid expression")),
1655 pstate.ptr, pstate.ptr - pstate.start);
1656 } else
1657 report_err (&pstate, g_error_new (1, PERR_UNEXPECTED_TOKEN,
1658 _("Unexpected token %c"), *last_token),
1659 last_token, 1);
1662 deallocate_all ();
1664 expr = NULL;
1667 deallocate_uninit ();
1669 return gnm_expr_top_new (expr);
1672 GnmLexerItem *
1673 gnm_expr_lex_all (char const *str, GnmParsePos const *pp,
1674 GnmExprParseFlags flags,
1675 GnmConventions const *convs)
1677 GnmLexerItem *res = NULL;
1678 int n = 0, alloc = 0;
1679 ParserState pstate;
1680 GnmParseError *error = NULL;
1682 g_return_val_if_fail (str != NULL, NULL);
1683 g_return_val_if_fail (pp != NULL, NULL);
1685 if (deallocate_stack == NULL)
1686 deallocate_init ();
1688 setup_state (&pstate, str, pp, flags, convs, error);
1690 while (1) {
1691 int len;
1693 if (alloc <= n) {
1694 alloc = alloc * 2 + 20;
1695 res = g_renew (GnmLexerItem, res, alloc);
1698 res[n].start = pstate.ptr - pstate.start;
1699 res[n].token = yylex ();
1700 res[n].end = pstate.ptr - pstate.start;
1702 if (res[n].token == 0)
1703 break;
1705 len = res[n].end - res[n].start;
1706 /* Kill spaces that got eaten, but not a space operator */
1707 while (len > 1 && str[res[n].start] == ' ') {
1708 res[n].start++;
1709 len--;
1711 while (len > 1 && str[res[n].end - 1] == ' ') {
1712 res[n].end--;
1713 len--;
1716 n++;
1719 deallocate_all ();
1721 state = NULL;
1723 return res;