5 * (C) 1998-2002 GNOME Foundation
6 * Copyright (C) 2002-2009 Morten Welinder
9 * Miguel de Icaza (miguel@gnu.org)
10 * Jody Goldberg (jody@gnome.org)
11 * Morten Welinder (terra@diku.dk)
12 * Almer S. Tigelaar (almer@gnome.org)
14 #include <gnumeric-config.h>
15 #include <glib/gi18n-lib.h>
17 #include <number-match.h>
19 #include <expr-impl.h>
20 #include <expr-name.h>
24 #include <gnm-format.h>
25 #include <application.h>
26 #include <parse-util.h>
30 #include <goffice/goffice.h>
38 /* ------------------------------------------------------------------------- */
39 /* Allocation with disposal-on-error */
42 * If some dork enters "=1+2+2*(1+" we have already allocated space for
43 * "1+2", "2", and "1" before the parser sees the syntax error and warps
44 * us to the error production in the "line" non-terminal.
46 * To make sure we can clean up, we register every allocation. On success,
47 * nothing should be left (except the final expression which is unregistered),
48 * but on failure we must free everything allocated.
50 * Note: there is some room left for optimisation here. Talk to terra@diku.dk
51 * before you set out to do it.
55 free_expr_list_list
(GSList
*list
)
58 for
(l
= list
; l
; l
= l
->next
)
59 gnm_expr_list_unref
(l
->data
);
63 typedef
void (*ParseDeallocator
) (void *);
64 static GPtrArray
*deallocate_stack
;
67 deallocate_init
(void)
69 deallocate_stack
= g_ptr_array_new
();
73 deallocate_uninit
(void)
75 g_ptr_array_free
(deallocate_stack
, TRUE
);
76 deallocate_stack
= NULL
;
84 for
(i
= 0; i
< (int)deallocate_stack
->len
; i
+= 2) {
85 ParseDeallocator freer
= g_ptr_array_index
(deallocate_stack
, i
+ 1);
86 freer
(g_ptr_array_index
(deallocate_stack
, i
));
89 g_ptr_array_set_size
(deallocate_stack
, 0);
93 deallocate_assert_empty
(void)
95 if
(deallocate_stack
->len
== 0)
98 g_warning
("deallocate_stack not empty as expected.");
103 register_allocation
(gpointer data
, ParseDeallocator freer
)
105 /* It's handy to be able to register and unregister NULLs. */
109 * There are really only a few different freers, so we
110 * could encode the freer in the lower bits of the data
111 * pointer. Unfortunately, no-one can predict how high
112 * Miguel would jump when he found out.
114 len
= deallocate_stack
->len
;
115 g_ptr_array_set_size
(deallocate_stack
, len
+ 2);
116 g_ptr_array_index
(deallocate_stack
, len
) = data
;
117 g_ptr_array_index
(deallocate_stack
, len
+ 1) = freer
;
120 /* Returning the pointer here improved readability of the caller. */
124 #define register_expr_allocation(expr) \
125 register_allocation
((gpointer
)(expr
), (ParseDeallocator
)&gnm_expr_free
)
127 #define register_expr_list_allocation(list) \
128 register_allocation
((list
), (ParseDeallocator
)&gnm_expr_list_unref
)
130 #define register_expr_list_list_allocation(list) \
131 register_allocation
((list
), (ParseDeallocator
)&free_expr_list_list
)
134 unregister_allocation
(void const *data
)
138 /* It's handy to be able to register and unregister NULLs. */
142 pos
= deallocate_stack
->len
- 2;
143 if
(pos
>= 0 && data
== g_ptr_array_index
(deallocate_stack
, pos
)) {
144 g_ptr_array_set_size
(deallocate_stack
, pos
);
149 * Bummer. In certain error cases, it is possible that the parser
150 * will reduce after it has discovered a token that will lead to an
151 * error. "2/16/1800 00:00" (without the quotes) is an example.
152 * The first "00" is registered before the second division is
155 * Another example is 564077 where we deallocate out of order.
157 * This isn't a big deal -- we will just look at the entries below
160 for
(i
= pos
- 2; i
>= 0; i
-= 2) {
161 if
(data
== g_ptr_array_index
(deallocate_stack
, i
)) {
162 g_ptr_array_remove_index
(deallocate_stack
, i
);
163 g_ptr_array_remove_index
(deallocate_stack
, i
);
168 g_warning
("Unbalanced allocation registration");
171 /* ------------------------------------------------------------------------- */
173 /* Bison/Yacc internals */
174 static int yylex (void);
175 static int yyerror (char const *s
);
178 char const *ptr
; /* current position of the lexer */
179 char const *start
; /* start of the expression */
181 /* Location where the parsing is taking place */
182 GnmParsePos
const *pos
;
184 /* loaded from convs with locale specific mappings */
185 gunichar decimal_point
;
188 gunichar array_col_sep
;
189 gunichar array_row_sep
;
190 /* if arg_sep conflicts with array_col_sep or array_row_sep */
191 int in_array_sep_is
; /* token id */
193 GnmExprParseFlags flags
;
194 GnmConventions
const *convs
;
197 int in_array
; /* toggled in the lexer for '{' and '}' */
200 GnmParseError
*error;
203 /* The error returned from the */
204 static ParserState
*state
;
207 report_err
(ParserState
*state
, GError
*err
,
208 char const *last
, int guesstimate_of_length
)
210 if
(state
->error != NULL
) {
211 state
->error->err
= err
;
212 state
->error->end_char
= last
- state
->start
;
213 state
->error->begin_char
= state
->error->end_char
- guesstimate_of_length
;
214 if
(state
->error->begin_char
< 0)
215 state
->error->begin_char
= 0;
221 is_signed
(const GnmExpr
*expr
)
223 if
(GNM_EXPR_GET_OPER
(expr
) == GNM_EXPR_OP_UNARY_NEG
)
226 if
(GNM_EXPR_GET_OPER
(expr
) == GNM_EXPR_OP_UNARY_PLUS
)
229 if
(GNM_EXPR_GET_OPER
(expr
) == GNM_EXPR_OP_CONSTANT
) {
230 GnmValue
const *v
= expr
->constant.value
;
231 return VALUE_IS_FLOAT
(v
) && value_get_as_float
(v
) < 0;
237 /* Handle -cst for use in arrays. Don't handle other types here. */
239 fold_negative_constant
(GnmExpr
*expr
)
241 if
(expr
&& GNM_EXPR_GET_OPER
(expr
) == GNM_EXPR_OP_CONSTANT
) {
242 GnmValue
*v
= (GnmValue
*)expr
->constant.value
;
244 if
(VALUE_IS_FLOAT
(v
)) {
245 gnm_float f
= value_get_as_float
(v
);
246 expr
->constant.value
= value_new_float
(0 - f
);
255 /* Handle +cst for use in arrays. Don't handle other types here. */
257 fold_positive_constant
(GnmExpr
*expr
)
259 if
(expr
&& GNM_EXPR_GET_OPER
(expr
) == GNM_EXPR_OP_CONSTANT
) {
260 const GnmValue
*v
= expr
->constant.value
;
261 if
(VALUE_IS_FLOAT
(v
))
269 build_unary_op
(GnmExprOp op
, GnmExpr
*expr
)
271 if
(!expr
) return NULL
;
273 unregister_allocation
(expr
);
274 return register_expr_allocation
(gnm_expr_new_unary
(op
, expr
));
278 build_binop
(GnmExpr
*l
, GnmExprOp op
, GnmExpr
*r
)
280 if
(!l ||
!r
) return NULL
;
282 unregister_allocation
(r
);
283 unregister_allocation
(l
);
284 return register_expr_allocation
(gnm_expr_new_binary
(l
, op
, r
));
288 build_logical
(GnmExpr
*l
, gboolean is_and
, GnmExpr
*r
)
290 static GnmFunc
*and_func
= NULL
, *or_func
= NULL
;
292 if
(!l ||
!r
) return NULL
;
294 if
(and_func
== NULL
)
295 and_func
= gnm_func_lookup
("AND", NULL
);
297 or_func
= gnm_func_lookup
("OR", NULL
);
299 unregister_allocation
(r
);
300 unregister_allocation
(l
);
301 return register_expr_allocation
302 (gnm_expr_new_funcall2
(is_and ? and_func
: or_func
, l
, r
));
306 build_not
(GnmExpr
*expr
)
308 static GnmFunc
*not_func
= NULL
;
310 if
(!expr
) return NULL
;
312 if
(not_func
== NULL
)
313 not_func
= gnm_func_lookup
("NOT", NULL
);
314 unregister_allocation
(expr
);
315 return register_expr_allocation
316 (gnm_expr_new_funcall1
(not_func
, expr
));
320 build_exp
(GnmExpr
*l
, GnmExpr
*r
)
324 l
= build_unary_op
(GNM_EXPR_OP_PAREN
, l
);
327 if
(GNM_EXPR_GET_OPER
(l
) == GNM_EXPR_OP_EXP
) {
328 /* Add ()s to x^y^z */
329 l
= build_unary_op
(GNM_EXPR_OP_PAREN
, l
);
332 if
(GNM_EXPR_GET_OPER
(r
) == GNM_EXPR_OP_EXP
) {
333 /* Add ()s to x^y^z */
334 r
= build_unary_op
(GNM_EXPR_OP_PAREN
, r
);
337 return build_binop
(l
, GNM_EXPR_OP_EXP
, r
);
341 * Build an array expression.
343 * Returns NULL on failure. Caller must YYERROR in that case.
346 build_array
(GSList
*cols
)
352 report_err
(state
, g_error_new
(1, PERR_INVALID_EMPTY
,
353 _
("An array must have at least 1 element")),
358 mx
= g_list_length
(cols
->data
);
359 array
= value_new_array_empty
(mx
, g_slist_length
(cols
));
363 GSList
*row
= cols
->data
;
365 while
(row
&& x
< mx
) {
366 GnmExpr
const *expr
= row
->data
;
367 GnmValue
const *v
= expr
->constant.value
;
369 g_assert
(expr
&& GNM_EXPR_GET_OPER
(expr
) == GNM_EXPR_OP_CONSTANT
);
371 value_array_set
(array
, x
, y
, value_dup
(v
));
377 /* parser_error = PARSE_ERR_SYNTAX; */
378 report_err
(state
, g_error_new
(1, PERR_ASYMETRIC_ARRAY
,
379 _
("Arrays must be rectangular")),
381 value_release
(array
);
388 return register_expr_allocation
(gnm_expr_new_constant
(array
));
392 * Build a range constructor.
394 * Returns NULL on failure. Caller must YYERROR in that case.
397 build_range_ctor
(GnmExpr
*l
, GnmExpr
*r
, GnmExpr
*validate
)
399 if
(!l ||
!r
) return NULL
;
401 if
(validate
!= NULL
) {
402 if
(GNM_EXPR_GET_OPER
(validate
) != GNM_EXPR_OP_CELLREF ||
403 validate
->cellref.ref.sheet
!= NULL
) {
404 report_err
(state
, g_error_new
(1, PERR_UNEXPECTED_TOKEN
,
405 _
("Constructed ranges use simple references")),
411 unregister_allocation
(r
);
412 unregister_allocation
(l
);
413 return register_expr_allocation
(gnm_expr_new_range_ctor
(l
, r
));
417 * Build an intersection expression.
419 * Returns NULL on failure. Caller must YYERROR in that case.
422 build_intersect
(GnmExpr
*l
, GnmExpr
*r
)
424 if
(!l ||
!r
) return NULL
;
426 if
(gnm_expr_is_rangeref
(l
) && gnm_expr_is_rangeref
(r
))
427 return build_binop
(l
, GNM_EXPR_OP_INTERSECT
, r
);
428 report_err
(state
, g_error_new
(1, PERR_SET_CONTENT_MUST_BE_RANGE
,
429 _
("All entries in the set must be references")),
435 * Build a set expression.
437 * Returns NULL on failure. Caller must YYERROR in that case.
440 build_set
(GnmExprList
*list
)
442 /* verify that every thing is a ref */
444 for
(ptr
= list
; ptr
!= NULL
; ptr
= ptr
->next
) {
445 GnmExpr
const *expr
= ptr
->data
;
446 if
(!expr ||
!gnm_expr_is_rangeref
(expr
)) {
447 report_err
(state
, g_error_new
(1, PERR_SET_CONTENT_MUST_BE_RANGE
,
448 _
("All entries in the set must be references")),
454 unregister_allocation
(list
);
455 return register_expr_allocation
(gnm_expr_new_set
(list
));
459 * parse_string_as_value:
461 * Try to parse the entered text as a basic value (empty, bool, int,
462 * gnm_float, err) if this succeeds, we store this as a GnmValue otherwise, we
466 parse_string_as_value
(GnmExpr
*str
)
468 GnmValue
*v
= format_match_simple
(value_peek_string
(str
->constant.value
));
471 unregister_allocation
(str
);
473 return register_expr_allocation
(gnm_expr_new_constant
(v
));
478 static const GnmExpr
*
479 parser_simple_name
(const char *str
, Sheet
*sheet
)
486 parse_pos_init_sheet
(&pp
, sheet
);
487 nexpr
= expr_name_lookup
(&pp
, str
);
489 nexpr
= expr_name_lookup
(state
->pos
, str
);
492 if
(state
->flags
& GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_INVALID
) {
495 ? g_error_new
(1, PERR_UNKNOWN_NAME
,
496 _
("Name '%s' does not exist in sheet '%s'"),
497 str
, sheet
->name_quoted
)
498 : g_error_new
(1, PERR_UNKNOWN_NAME
,
499 _
("Name '%s' does not exist"),
501 report_err
(state
, e
, state
->ptr
, 0);
503 } else if
(!sheet
&& state
->flags
& GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS
) {
504 res
= gnm_expr_new_constant
(value_new_string
(str
));
505 } else if
(state
->convs
->input.name_validate
(str
)) {
506 GnmParsePos pp
= *state
->pos
;
508 /* Create a place holder */
509 nexpr
= expr_name_add
(&pp
, str
, NULL
, NULL
, TRUE
, NULL
);
510 res
= gnm_expr_new_name
(nexpr
, sheet
, NULL
);
512 report_err
(state
, g_error_new
(1, PERR_UNKNOWN_NAME
,
513 _
("'%s' cannot be used as a name"),
519 res
= gnm_expr_new_name
(nexpr
, sheet
, NULL
);
525 * parser_simple_val_or_name:
526 * @str : An expression with oper constant, whose value is a string.
528 * Check to see if a string is a simple value or failing that a named
529 * expression, if it is not create a placeholder name for it.
532 parser_simple_val_or_name
(GnmExpr
*str_expr
)
535 char const *str
= value_peek_string
(str_expr
->constant.value
);
536 GnmValue
*v
= format_match_simple
(str
);
538 /* if it is not a simple value see if it is a name */
540 res
= parser_simple_name
(str
, NULL
);
542 res
= gnm_expr_new_constant
(v
);
544 unregister_allocation
(str_expr
);
545 gnm_expr_free
(str_expr
);
546 return register_expr_allocation
(res
);
550 parser_sheet_by_name
(Workbook
*wb
, GnmExpr
*name_expr
)
552 char const *name
= value_peek_string
(name_expr
->constant.value
);
558 sheet
= workbook_sheet_by_name
(wb
, name
);
560 /* Applix has absolute and relative sheet references */
561 if
(sheet
== NULL
&& *name
== '$' &&
562 state
->convs
->allow_absolute_sheet_references
)
563 sheet
= workbook_sheet_by_name
(wb
, name
+ 1);
566 /* TODO : length is broken in the context of quoted names or
567 * names with escaped character */
568 /* -1 is a kludge. We know that this routine is only called
569 * when the last token was SHEET_SEP */
570 report_err
(state
, g_error_new
(1, PERR_UNKNOWN_SHEET
,
571 _
("Unknown sheet '%s'"), name
),
572 state
->ptr
-1, strlen
(name
));
577 /* Make byacc happier */
578 static int yyparse (void);
590 %type
<list
> opt_exp arg_list array_row array_rows
591 %type
<expr
> exp array_exp function string_opt_quote cellref
592 %token
<expr
> STRING QUOTED_STRING CONSTANT RANGEREF tok_GTE tok_LTE tok_NE tok_AND tok_OR tok_NOT INTERSECT
593 %token ARG_SEP ARRAY_COL_SEP ARRAY_ROW_SEP SHEET_SEP INVALID_TOKEN
594 %type
<sheet
> sheetref
595 %type
<wb
> workbookref
596 %token
<wb
> tok_WORKBOOKREF
598 %left
'<' '>' '=' tok_GTE tok_LTE tok_NE
605 %nonassoc tok_NEG tok_PLUS tok_NOT
608 %left RANGE_INTERSECT
613 unregister_allocation
($2);
614 unregister_allocation
($1);
615 state
->result
= gnm_expr_list_prepend
($1, $2);
619 if
(state
->result
!= NULL
) {
620 gnm_expr_list_unref
(state
->result
);
621 state
->result
= NULL
;
626 opt_exp
: opt_exp exp ARG_SEP
{
627 unregister_allocation
($2);
628 unregister_allocation
($1);
629 $$
= gnm_expr_list_prepend
($1, $2);
630 register_expr_list_allocation
($$
);
632 |
{ $$
= NULL
; register_expr_list_allocation
($$
); }
635 exp: CONSTANT
{ $$
= $1; }
636 | QUOTED_STRING
{ $$
= $1; }
638 $$
= parser_simple_val_or_name
($1);
639 if
($$
== NULL
) { YYERROR; }
641 | cellref
{ $$
= $1; }
642 | exp
'+' exp
{ $$
= build_binop
($1, GNM_EXPR_OP_ADD
, $3); }
643 | exp
'-' exp
{ $$
= build_binop
($1, GNM_EXPR_OP_SUB
, $3); }
644 | exp
'*' exp
{ $$
= build_binop
($1, GNM_EXPR_OP_MULT
, $3); }
645 | exp
'/' exp
{ $$
= build_binop
($1, GNM_EXPR_OP_DIV
, $3); }
646 | exp tok_RIGHT_EXP exp
{ $$
= build_exp
($1, $3); }
647 | exp tok_LEFT_EXP exp
{ $$
= build_exp
($1, $3); }
648 | exp
'&' exp
{ $$
= build_binop
($1, GNM_EXPR_OP_CAT
, $3); }
649 | exp
'=' exp
{ $$
= build_binop
($1, GNM_EXPR_OP_EQUAL
, $3); }
650 | exp
'<' exp
{ $$
= build_binop
($1, GNM_EXPR_OP_LT
, $3); }
651 | exp
'>' exp
{ $$
= build_binop
($1, GNM_EXPR_OP_GT
, $3); }
652 | exp tok_GTE exp
{ $$
= build_binop
($1, GNM_EXPR_OP_GTE
, $3); }
653 | exp tok_NE exp
{ $$
= build_binop
($1, GNM_EXPR_OP_NOT_EQUAL
, $3); }
654 | exp tok_LTE exp
{ $$
= build_binop
($1, GNM_EXPR_OP_LTE
, $3); }
655 | exp tok_AND exp
{ $$
= build_logical
($1, TRUE
, $3); }
656 | exp tok_OR exp
{ $$
= build_logical
($1, FALSE
, $3); }
657 | exp RANGE_INTERSECT exp
{
658 $$
= build_intersect
($1, $3);
659 if
($$
== NULL
) { YYERROR; }
662 |
'-' exp %prec tok_NEG
{
663 GnmExpr
*tmp
= fold_negative_constant
($2);
664 $$
= tmp ? tmp
: build_unary_op
(GNM_EXPR_OP_UNARY_NEG
, $2);
666 |
'+' exp %prec tok_PLUS
{
667 /* Don't fold here. */
668 $$
= build_unary_op
(GNM_EXPR_OP_UNARY_PLUS
, $2);
670 | tok_NOT exp
{ $$
= build_not
($2); }
671 | exp
'%' { $$
= build_unary_op
(GNM_EXPR_OP_PERCENTAGE
, $1); }
675 report_err
(state
, g_error_new
(1, PERR_INVALID_EMPTY
,
676 _
("() is an invalid expression")),
680 if
($2->next
== NULL
) {
681 unregister_allocation
($2);
682 $$
= register_expr_allocation
(gnm_expr_new_unary
(GNM_EXPR_OP_PAREN
, $2->data
));
683 /* NOTE : free list not content */
684 gnm_expr_list_free
($2);
687 if
($$
== NULL
) { YYERROR; }
691 |
'{' array_rows
'}' {
692 unregister_allocation
($2);
693 $$
= build_array
($2);
694 free_expr_list_list
($2);
695 if
($$
== NULL
) { YYERROR; }
700 char const *name
= value_peek_string
($2->constant.value
);
701 GnmExpr
const *ename
= parser_simple_name
(name
, $1);
704 unregister_allocation
($2); gnm_expr_free
($2);
705 $$
= register_expr_allocation
(ename
);
710 | workbookref STRING
{
711 GnmNamedExpr
*nexpr
= NULL
;
712 char const *name
= value_peek_string
($2->constant.value
);
713 GnmParsePos pos
= *state
->pos
;
717 nexpr
= expr_name_lookup
(&pos
, name
);
719 unregister_allocation
($2); gnm_expr_free
($2);
720 $$
= register_expr_allocation
(gnm_expr_new_name
(nexpr
, NULL
, $1));
722 report_err
(state
, g_error_new
(1, PERR_UNKNOWN_NAME
,
723 _
("Name '%s' does not exist in workbook"),
725 state
->ptr
, strlen
(name
));
731 function
: STRING
'(' arg_list
')' {
732 char const *name
= value_peek_string
($1->constant.value
);
733 GnmExpr
const *f_call
= (*state
->convs
->input.func
) (
734 state
->convs
, state
->pos
->wb
, name
, $3);
738 /* We're done with the function name. */
739 unregister_allocation
($1); gnm_expr_free
($1);
740 unregister_allocation
($3);
741 $$
= register_expr_allocation
(f_call
);
748 string_opt_quote
: STRING
752 opt_sheet_sep
: SHEET_SEP
755 /* only used for names */
756 workbookref
: tok_WORKBOOKREF opt_sheet_sep
757 |
'[' string_opt_quote
']' {
758 char const *wb_name
= value_peek_string
($2->constant.value
);
759 Workbook
*ref_wb
= state
->pos
763 ? state
->pos
->sheet
->workbook
767 state
->convs
->input.external_wb
(state
->convs
,
772 unregister_allocation
($2); gnm_expr_free
($2);
775 /* kludge to produce better error messages
776 * we know that the last token read will be the ']'
779 report_err
(state
, g_error_new
(1, PERR_UNKNOWN_WORKBOOK
,
780 _
("Unknown workbook '%s'"), wb_name
),
781 state
->ptr
- 1, strlen
(wb_name
));
786 /* Special syntax for global names shadowed by sheet names. */
787 Workbook
*wb
= state
->pos
791 ? state
->pos
->sheet
->workbook
796 report_err
(state
, g_error_new
(1, PERR_UNKNOWN_WORKBOOK
,
797 _
("Unknown workbook")),
804 /* does not need to handle 3d case. this is only used for names.
805 * 3d cell references are handled in the lexer
807 sheetref: string_opt_quote SHEET_SEP
{
808 Sheet
*sheet
= parser_sheet_by_name
(state
->pos
->wb
, $1);
810 unregister_allocation
($1); gnm_expr_free
($1);
816 | workbookref string_opt_quote SHEET_SEP
{
818 Sheet
*sheet
= parser_sheet_by_name
(wb
, $2);
820 unregister_allocation
($2); gnm_expr_free
($2);
828 cellref: RANGEREF
{ $$
= $1; }
829 | function RANGE_SEP function
{
830 $$
= build_range_ctor
($1, $3, NULL
);
831 if
($$
== NULL
) { YYERROR; }
833 | RANGEREF RANGE_SEP function
{
834 $$
= build_range_ctor
($1, $3, $1);
835 if
($$
== NULL
) { YYERROR; }
837 | function RANGE_SEP RANGEREF
{
838 $$
= build_range_ctor
($1, $3, $3);
839 if
($$
== NULL
) { YYERROR; }
841 | RANGEREF RANGE_SEP RANGEREF
{
842 $$
= build_range_ctor
($1, $3, NULL
);
843 if
($$
== NULL
) { YYERROR; }
848 unregister_allocation
($1);
849 $$
= gnm_expr_list_prepend
(NULL
, $1);
850 register_expr_list_allocation
($$
);
852 | exp ARG_SEP arg_list
{
854 unregister_allocation
($3);
855 unregister_allocation
($1);
858 tmp
= gnm_expr_list_prepend
(NULL
, gnm_expr_new_constant
(value_new_empty
()));
860 $$
= gnm_expr_list_prepend
(tmp
, $1);
861 register_expr_list_allocation
($$
);
865 unregister_allocation
($2);
868 tmp
= gnm_expr_list_prepend
(NULL
, gnm_expr_new_constant
(value_new_empty
()));
870 $$
= gnm_expr_list_prepend
(tmp
, gnm_expr_new_constant
(value_new_empty
()));
871 register_expr_list_allocation
($$
);
876 array_exp: CONSTANT
{ $$
= $1; }
878 GnmExpr
*tmp
= fold_negative_constant
($2);
879 if
(!tmp
) { YYERROR; }
883 GnmExpr
*tmp
= fold_positive_constant
($2);
884 if
(!tmp
) { YYERROR; }
887 | string_opt_quote
{ $$
= parse_string_as_value
($1); }
891 array_row
: { $$
= NULL
; }
893 unregister_allocation
($1);
894 $$
= g_slist_prepend
(NULL
, $1);
895 register_expr_list_allocation
($$
);
897 | array_exp ARRAY_COL_SEP array_row
{
898 unregister_allocation
($3);
899 unregister_allocation
($1);
900 $$
= g_slist_prepend
($3, $1);
901 register_expr_list_allocation
($$
);
905 array_rows: array_row
{
906 unregister_allocation
($1);
907 $$
= g_slist_prepend
(NULL
, $1);
908 register_expr_list_list_allocation
($$
);
910 | array_row ARRAY_ROW_SEP array_rows
{
911 unregister_allocation
($3);
912 unregister_allocation
($1);
913 $$
= g_slist_prepend
($3, $1);
914 register_expr_list_list_allocation
($$
);
921 find_matching_close
(char const *str
, char const **res
)
925 char const *tmp
= str
;
926 str
= find_matching_close
(str
+ 1, res
);
927 if
(*str
!= ')' && *res
== NULL
) {
933 } else if
(*str
== ')')
935 else if
(*str
== '\'' ||
*str
== '\"') {
936 GString
*dummy
= g_string_new
(NULL
);
937 char const *end
= go_strunescape
(dummy
, str
);
938 g_string_free
(dummy
, TRUE
);
940 return str
+ strlen
(str
);
942 continue
; /* skip incrementing str */
944 str
= g_utf8_next_char
(str
);
951 eat_space
(ParserState
*state
, int res
)
953 /* help the user by ignoring pointless spaces after an
954 * arg_sep. We know they are going to be errors and
955 * the spaces can not be operators in this context */
956 while
(*state
->ptr
== ' ')
962 * Do we want to ignore space before a given character?
965 ignore_space_before
(gunichar c
)
968 case
'*': case
'/': case
'+': case
'-': case
'%': case
'^': case
'&':
969 case
'>': case
'<': case
'=':
972 case
'"': case
'\'': /* Refers to opening quote only. */
973 case UNICODE_LOGICAL_NOT_C
:
974 case UNICODE_LOGICAL_AND_C
:
975 case UNICODE_LOGICAL_OR_C
:
976 case UNICODE_MINUS_SIGN_C
:
977 case UNICODE_DIVISION_SLASH_C
:
978 case UNICODE_NOT_EQUAL_TO_C
:
979 case UNICODE_LESS_THAN_OR_EQUAL_TO_C
:
980 case UNICODE_GREATER_THAN_OR_EQUAL_TO_C
:
989 * Do we want to ignore space after a given character?
992 ignore_space_after
(gunichar c
)
995 case
'*': case
'/': case
'+': case
'-': case
'%': case
'^': case
'&':
996 case
'>': case
'<': case
'=':
998 case
'"': case
'\'': /* Refers to closing quote only [not actually hit]. */
999 case UNICODE_LOGICAL_NOT_C
:
1000 case UNICODE_LOGICAL_AND_C
:
1001 case UNICODE_LOGICAL_OR_C
:
1002 case UNICODE_MINUS_SIGN_C
:
1003 case UNICODE_DIVISION_SLASH_C
:
1004 case UNICODE_NOT_EQUAL_TO_C
:
1005 case UNICODE_LESS_THAN_OR_EQUAL_TO_C
:
1006 case UNICODE_GREATER_THAN_OR_EQUAL_TO_C
:
1015 open_paren
(const char *p
)
1017 while
(g_unichar_isspace
(g_utf8_get_char
(p
)))
1018 p
= g_utf8_next_char
(p
);
1026 char const *start
, *end
;
1028 gboolean is_number
= FALSE
;
1029 gboolean is_space
= FALSE
;
1030 gboolean error_token
= FALSE
;
1033 * Some special logic to handle space as intersection char.
1034 * Any number of white space characters are treated as one
1037 * Also, if we are not using space for that, drop spaces.
1039 while
(g_unichar_isspace
(g_utf8_get_char
(state
->ptr
))) {
1040 state
->ptr
= g_utf8_next_char
(state
->ptr
);
1043 if
(is_space
&& state
->convs
->intersection_char
== ' ' &&
1044 !ignore_space_before
(g_utf8_get_char
(state
->ptr
)))
1045 return RANGE_INTERSECT
;
1048 c
= g_utf8_get_char
(start
);
1051 state
->ptr
= g_utf8_next_char
(state
->ptr
);
1053 if
(c
== state
->convs
->intersection_char
)
1054 return RANGE_INTERSECT
;
1056 if
(c
== '&' && state
->convs
->decode_ampersands
) {
1057 if
(!strncmp
(state
->ptr
, "amp;", 4)) {
1062 if
(!strncmp
(state
->ptr
, "lt;", 3)) {
1064 if
(*state
->ptr
== '='){
1068 if
(!strncmp
(state
->ptr
, ">", 4)) {
1074 if
(!strncmp
(state
->ptr
, "gt;", 3)) {
1076 if
(*state
->ptr
== '='){
1082 if
(!strncmp
(state
->ptr
, "apos;", 5) ||
1083 !strncmp
(state
->ptr
, "quot;", 5)) {
1084 char const *quotes_end
;
1089 if
(*state
->ptr
== 'q') {
1090 quotes_end
= """;
1093 quotes_end
= "'";
1100 state
->ptr
= strstr
(state
->ptr
, quotes_end
);
1102 report_err
(state
, g_error_new
(1, PERR_MISSING_CLOSING_QUOTE
,
1103 _
("Could not find matching closing quote")),
1105 return INVALID_TOKEN
;
1107 if
(!strncmp
(state
->ptr
+ 6, quotes_end
, 6)) {
1108 state
->ptr
+= 2 * 6;
1109 goto double_quote_loop
;
1112 s
= string = g_malloc
(1 + state
->ptr
- p
);
1113 while
(p
!= state
->ptr
) {
1115 if
(!strncmp
(p
, "&", 5)) {
1119 } else if
(!strncmp
(p
, "<", 4)) {
1123 } else if
(!strncmp
(p
, ">", 4)) {
1127 } else if
(!strncmp
(p
, quotes_end
, 6)) {
1128 p
+= 12; /* two in a row is the escape mechanism */
1131 } else if
(!strncmp
(p
, """, 6)) {
1135 } else if
(!strncmp
(p
, "'", 6)) {
1147 v
= value_new_string_nocopy
(string);
1148 yylval.expr
= register_expr_allocation
(gnm_expr_new_constant
(v
));
1149 return QUOTED_STRING
;
1153 if
(c
== ':' && state
->convs
->range_sep_colon
)
1154 return eat_space
(state
, RANGE_SEP
);
1156 if
(c
== state
->convs
->sheet_name_sep
)
1157 return eat_space
(state
, SHEET_SEP
);
1159 if
(c
== '.' && *state
->ptr
== '.' && state
->convs
->range_sep_dotdot
) {
1164 if
(c
== '#' && state
->convs
->accept_hash_logicals
) {
1165 if
(!strncmp
(state
->ptr
, "NOT#", 4)) {
1167 return eat_space
(state
, tok_NOT
);
1169 if
(!strncmp
(state
->ptr
, "AND#", 4)) {
1171 return eat_space
(state
, tok_AND
);
1173 if
(!strncmp
(state
->ptr
, "OR#", 3)) {
1175 return eat_space
(state
, tok_OR
);
1179 if
(c
== state
->arg_sep
)
1180 return eat_space
(state
, state
->in_array ? state
->in_array_sep_is
: ARG_SEP
);
1181 if
((c
== state
->union_char
) && (state
->union_char
!= 0))
1182 return eat_space
(state
, ARG_SEP
);
1183 if
(c
== state
->array_col_sep
)
1184 return eat_space
(state
, ARRAY_COL_SEP
);
1185 if
(c
== state
->array_row_sep
)
1186 return eat_space
(state
, ARRAY_ROW_SEP
);
1188 end
= state
->convs
->input.range_ref
(&ref
, start
,
1189 state
->pos
, state
->convs
);
1191 * In order to parse "LOG10(1024)" in sheets with more than ~8500
1192 * columns we do not consider anything a rangeref if it is followed
1193 * by an opening parenthesis.
1195 if
(start
!= end
&& !open_paren
(end
)) {
1197 if
(invalid_sheet
== ref.a.sheet
) {
1198 yylval.expr
= register_expr_allocation
1199 (gnm_expr_new_constant
1200 (value_new_error_REF
(NULL
)));
1203 if
(state
->flags
& GNM_EXPR_PARSE_FORCE_ABSOLUTE_REFERENCES
) {
1204 if
(ref.a.col_relative
) {
1205 ref.a.col
+= state
->pos
->eval.col
;
1206 ref.a.col_relative
= FALSE
;
1208 if
(ref.b.col_relative
) {
1209 ref.b.col
+= state
->pos
->eval.col
;
1210 ref.b.col_relative
= FALSE
;
1212 if
(ref.a.row_relative
) {
1213 ref.a.row
+= state
->pos
->eval.row
;
1214 ref.a.row_relative
= FALSE
;
1216 if
(ref.b.row_relative
) {
1217 ref.b.row
+= state
->pos
->eval.row
;
1218 ref.b.row_relative
= FALSE
;
1220 } else if
(state
->flags
& GNM_EXPR_PARSE_FORCE_RELATIVE_REFERENCES
) {
1221 if
(!ref.a.col_relative
) {
1222 ref.a.col
-= state
->pos
->eval.col
;
1223 ref.a.col_relative
= TRUE
;
1225 if
(!ref.b.col_relative
) {
1226 ref.b.col
-= state
->pos
->eval.col
;
1227 ref.b.col_relative
= TRUE
;
1229 if
(!ref.a.row_relative
) {
1230 ref.a.row
-= state
->pos
->eval.row
;
1231 ref.a.row_relative
= TRUE
;
1233 if
(!ref.b.row_relative
) {
1234 ref.b.row
-= state
->pos
->eval.row
;
1235 ref.b.row_relative
= TRUE
;
1239 if
(ref.a.sheet
== NULL
&& (state
->flags
& GNM_EXPR_PARSE_FORCE_EXPLICIT_SHEET_REFERENCES
)) {
1240 ref.a.sheet
= state
->pos
->sheet
;
1241 if
(ref.a.sheet
== NULL
) {
1242 report_err
(state
, g_error_new
(1, PERR_SHEET_IS_REQUIRED
,
1243 _
("Sheet name is required")),
1245 return INVALID_TOKEN
;
1249 if
((ref.b.sheet
== NULL || ref.b.sheet
== ref.a.sheet
) &&
1250 ref.a.col
== ref.b.col
&&
1251 ref.a.col_relative
== ref.b.col_relative
&&
1252 ref.a.row
== ref.b.row
&&
1253 ref.a.row_relative
== ref.b.row_relative
) {
1254 yylval.expr
= register_expr_allocation
(gnm_expr_new_cellref
(&ref.a
));
1257 yylval.expr
= register_expr_allocation
(gnm_expr_new_constant
(
1258 value_new_cellrange_unsafe
(&ref.a
, &ref.b
)));
1262 /* Do NOT handle negative numbers here. That has to be done in the
1263 * parser otherwise we mishandle A1-1 when it looks like
1264 * rangeref CONSTANT */
1265 if
(c
== state
->decimal_point
) {
1266 /* Could be a number or a stand alone */
1267 if
(!g_unichar_isdigit
(g_utf8_get_char
(state
->ptr
)))
1270 } else if
(g_unichar_isdigit
(c
)) {
1271 /* find the end of the first portion of the number */
1273 c
= g_utf8_get_char
(state
->ptr
);
1274 state
->ptr
= g_utf8_next_char
(state
->ptr
);
1275 } while
(g_unichar_isdigit
(c
));
1284 if
(c
== state
->decimal_point || c
== 'e' || c
== 'E') {
1285 /* This is a floating point number */
1290 d
= gnm_utf8_strto
(start
, &end
);
1292 g_warning
("%s is not a double, but was expected to be one", start
);
1293 } else if
(errno
!= ERANGE
) {
1294 v
= value_new_float
(d
);
1296 } else if
(c
!= 'e' && c
!= 'E') {
1297 report_err
(state
, g_error_new
(1, PERR_OUT_OF_RANGE
,
1298 _
("The number is out of range")),
1299 state
->ptr
, end
- start
);
1300 return INVALID_TOKEN
;
1302 /* For an exponent it's hard to highlight the
1303 * right region w/o it turning into an ugly
1304 * hack, for now the cursor is put at the end.
1306 report_err
(state
, g_error_new
(1, PERR_OUT_OF_RANGE
,
1307 _
("The number is out of range")),
1309 return INVALID_TOKEN
;
1315 l
= gnm_utf8_strtol
(start
, &end
);
1317 g_warning
("%s is not an integer, but was expected to be one", start
);
1318 } else if
(errno
!= ERANGE
&& l
>= INT_MIN
&& l
<= INT_MAX
) {
1319 v
= value_new_int
(l
);
1325 d
= gnm_utf8_strto
(start
, &end
);
1326 if
(errno
!= ERANGE
) {
1327 v
= value_new_float
(d
);
1330 report_err
(state
, g_error_new
(1, PERR_OUT_OF_RANGE
,
1331 _
("The number is out of range")),
1332 state
->ptr
, end
- start
);
1333 return INVALID_TOKEN
;
1338 /* Very odd string, Could be a bound problem. Trigger an error */
1342 yylval.expr
= register_expr_allocation
(gnm_expr_new_constant
(v
));
1348 if
(state
->ptr
[0] != '"') {
1349 while
((tmp
= g_utf8_get_char
(state
->ptr
)) != 0 &&
1350 !g_unichar_isspace
(tmp
)) {
1351 state
->ptr
= g_utf8_next_char
(state
->ptr
);
1352 if
(tmp
== '!' || tmp
== '?' ||
1353 ((state
->ptr
- start
) == 4 && 0 == strncmp
(start
, "#N/A", 4))) {
1354 GOString
*name
= go_string_new_nocopy
(g_strndup
(start
, state
->ptr
- start
));
1355 yylval.expr
= register_expr_allocation
1356 (gnm_expr_new_constant
(
1357 value_new_error_str
(NULL
, name
)));
1358 go_string_unref
(name
);
1363 report_err
(state
, g_error_new
1364 (1, PERR_UNEXPECTED_TOKEN
,
1365 _
("Improperly formatted error token")),
1366 state
->ptr
, state
->ptr
- start
);
1368 return INVALID_TOKEN
;
1375 GString
*s
= g_string_new
(NULL
);
1376 char const *end
= state
->convs
->input.
string (start
, s
, state
->convs
);
1379 size_t len
= strlen
(start
);
1380 g_string_free
(s
, TRUE
);
1382 g_error_new
(1, PERR_MISSING_CLOSING_QUOTE
,
1383 _
("Could not find matching closing quote")),
1385 return INVALID_TOKEN
;
1388 state
->ptr
= (char *)end
;
1391 GnmValue
*v
= value_new_error
(NULL
, s
->str
);
1392 yylval.expr
= register_expr_allocation
(gnm_expr_new_constant
(v
));
1393 g_string_free
(s
, TRUE
);
1394 return eat_space
(state
, CONSTANT
);
1396 GnmValue
*v
= value_new_string_nocopy
(g_string_free
(s
, FALSE
));
1397 yylval.expr
= register_expr_allocation
(gnm_expr_new_constant
(v
));
1398 return eat_space
(state
, QUOTED_STRING
);
1403 const char *p
= state
->ptr
;
1404 GString
*s
= g_string_new
(NULL
);
1405 Workbook
*ref_wb
= state
->pos
1408 : (state
->pos
->sheet
1409 ? state
->pos
->sheet
->workbook
1413 while
(g_unichar_isspace
(g_utf8_get_char
(p
)))
1414 p
= g_utf8_next_char
(p
);
1416 if
(p
[0] == '"' || p
[0] == '\'') {
1417 p
= go_strunescape
(s
, p
);
1421 uc
= g_utf8_get_char
(p
);
1422 if
(!uc || uc
== ']' || g_unichar_isspace
(uc
))
1424 p
= g_utf8_next_char
(p
);
1425 g_string_append_unichar
(s
, uc
);
1429 while
(p
&& g_unichar_isspace
(g_utf8_get_char
(p
)))
1430 p
= g_utf8_next_char
(p
);
1432 if
(s
->len
== 0 ||
!p || p
[0] != ']') {
1433 g_string_free
(s
, TRUE
);
1437 yylval.wb
= state
->convs
->input.external_wb
(state
->convs
,
1440 g_string_free
(s
, TRUE
);
1445 return tok_WORKBOOKREF
;
1449 if
((end
= state
->convs
->input.name
(start
, state
->convs
))) {
1451 yylval.expr
= register_expr_allocation
(gnm_expr_new_constant
(
1452 value_new_string_nocopy
(g_strndup
(start
, state
->ptr
- start
))));
1458 if
(*state
->ptr
== '='){
1460 return eat_space
(state
, tok_LTE
);
1462 if
(*state
->ptr
== '>'){
1464 return eat_space
(state
, tok_NE
);
1466 return eat_space
(state
, c
);
1469 if
(*state
->ptr
== '='){
1471 return eat_space
(state
, tok_GTE
);
1473 return eat_space
(state
, c
);
1475 case
'\n': return
0;
1485 return state
->convs
->exp_is_left_associative
1489 case UNICODE_LOGICAL_NOT_C
: return tok_NOT
;
1490 case UNICODE_MINUS_SIGN_C
: return
'-';
1491 case UNICODE_DIVISION_SLASH_C
: return
'/';
1492 case UNICODE_LOGICAL_AND_C
: return tok_AND
;
1493 case UNICODE_LOGICAL_OR_C
: return tok_OR
;
1494 case UNICODE_NOT_EQUAL_TO_C
: return eat_space
(state
, tok_NE
);
1495 case UNICODE_LESS_THAN_OR_EQUAL_TO_C
: return eat_space
(state
, tok_LTE
);
1496 case UNICODE_GREATER_THAN_OR_EQUAL_TO_C
: return eat_space
(state
, tok_GTE
);
1499 if
(ignore_space_after
(c
))
1500 return eat_space
(state
, c
);
1506 yyerror (char const *s
)
1509 g_printerr
("Error: %s\n", s
);
1515 setup_state
(ParserState
*pstate
, const char *str
,
1516 GnmParsePos
const *pp
,
1517 GnmExprParseFlags flags
,
1518 GnmConventions
const *convs
,
1519 GnmParseError
*error)
1521 pstate
->start
= pstate
->ptr
= str
;
1524 pstate
->flags
= flags
;
1526 (NULL
!= convs
) ? convs
: ((NULL
!= pp
->sheet
) ? pp
->sheet
->convs
: gnm_conventions_default
);
1529 pstate
->decimal_point
= pstate
->convs
->decimal_sep_dot
1531 : g_utf8_get_char
(go_locale_get_decimal
()->str
); /* FIXME: one char handled. */
1533 if
(pstate
->convs
->arg_sep
!= 0)
1534 pstate
->arg_sep
= pstate
->convs
->arg_sep
;
1536 pstate
->arg_sep
= go_locale_get_arg_sep
();
1537 pstate
->union_char
= pstate
->convs
->union_char
;
1538 if
(pstate
->convs
->array_col_sep
!= 0)
1539 pstate
->array_col_sep
= pstate
->convs
->array_col_sep
;
1541 pstate
->array_col_sep
= go_locale_get_col_sep
();
1542 if
(pstate
->convs
->array_row_sep
!= 0)
1543 pstate
->array_row_sep
= pstate
->convs
->array_row_sep
;
1545 pstate
->array_row_sep
= go_locale_get_row_sep
();
1547 /* Some locales/conventions have ARG_SEP == ARRAY_ROW_SEP
1548 * eg {1\2\3;4\5\6} for XL style with ',' as a decimal
1549 * some have ARG_SEP == ARRAY_COL_SEPARATOR
1550 * eg {1,2,3;4,5,6} for XL style with '.' as a decimal
1551 * or {1;2;3|4;5;6} for OOo/
1552 * keep track of whether we are in an array to allow the lexer to
1554 if
(pstate
->arg_sep
== pstate
->array_col_sep
)
1555 pstate
->in_array_sep_is
= ARRAY_COL_SEP
;
1556 else if
(pstate
->arg_sep
== pstate
->array_row_sep
)
1557 pstate
->in_array_sep_is
= ARRAY_ROW_SEP
;
1559 pstate
->in_array_sep_is
= ARG_SEP
;
1560 pstate
->in_array
= 0;
1562 pstate
->result
= NULL
;
1563 pstate
->error = error;
1569 * gnm_expr_parse_str:
1571 * @str : The string to parse.
1572 * @pp : #GnmParsePos
1573 * @flags : See parse-utils for descriptions
1574 * @convs : optionally NULL #GnmConventions
1575 * @error : optionally NULL ptr to store details of error.
1577 * Parse a string. if @error is non-null it will be assumed that the
1578 * caller has passed a pointer to a GnmParseError struct AND that it will
1579 * take responsibility for freeing that struct and its contents.
1580 * with parse_error_free.
1581 * If @convs is NULL use the conventions from @pp.
1584 gnm_expr_parse_str
(char const *str
, GnmParsePos
const *pp
,
1585 GnmExprParseFlags flags
,
1586 GnmConventions
const *convs
,
1587 GnmParseError
*error)
1589 GnmExpr
const *expr
;
1592 g_return_val_if_fail
(str
!= NULL
, NULL
);
1593 g_return_val_if_fail
(pp
!= NULL
, NULL
);
1594 g_return_val_if_fail
(state
== NULL
, NULL
);
1596 if
(deallocate_stack
== NULL
)
1599 setup_state
(&pstate
, str
, pp
, flags
, convs
, error);
1603 if
(pstate.result
!= NULL
) {
1604 deallocate_assert_empty
();
1607 /* If this happens, something is very wrong */
1608 if
(pstate.
error != NULL
&& pstate.
error->message
!= NULL
) {
1609 g_warning
("An error occurred and the GnmExpr is non-null! This should not happen");
1610 g_warning
("Error message is %s (%d, %d)", pstate.
error->message
, pstate.
error->begin_char
,
1611 pstate.
error->end_char
);
1615 /* Do we have multiple expressions */
1616 if
(pstate.result
->next
!= NULL
) {
1617 if
(flags
& GNM_EXPR_PARSE_PERMIT_MULTIPLE_EXPRESSIONS
)
1618 expr
= gnm_expr_new_set
(g_slist_reverse
(pstate.result
));
1620 gnm_expr_list_unref
(pstate.result
);
1621 report_err
(&pstate
, g_error_new
(1, PERR_MULTIPLE_EXPRESSIONS
,
1622 _
("Multiple expressions are not supported in this context")),
1624 (pstate.ptr
- pstate.start
));
1628 /* Free the list, do not unref the content */
1629 expr
= pstate.result
->data
;
1630 gnm_expr_list_free
(pstate.result
);
1633 /* If there is no error message, attempt to be more detailed */
1634 if
(pstate.
error != NULL
&&
1635 (pstate.
error->err
== NULL || pstate.
error->err
->message
== NULL
)) {
1636 char const *last_token
= pstate.ptr
;
1638 if
(*last_token
== '\0') {
1639 char const *str
= pstate.start
;
1640 char const *res
= NULL
;
1641 char const *last
= find_matching_close
(str
, &res
);
1644 report_err
(&pstate
, g_error_new
(1, PERR_MISSING_PAREN_OPEN
,
1645 _
("Could not find matching opening parenthesis")),
1647 else if
(res
!= NULL
)
1648 report_err
(&pstate
, g_error_new
(1, PERR_MISSING_PAREN_CLOSE
,
1649 _
("Could not find matching closing parenthesis")),
1652 report_err
(&pstate
, g_error_new
(1, PERR_INVALID_EXPRESSION
,
1653 _
("Invalid expression")),
1654 pstate.ptr
, pstate.ptr
- pstate.start
);
1656 report_err
(&pstate
, g_error_new
(1, PERR_UNEXPECTED_TOKEN
,
1657 _
("Unexpected token %c"), *last_token
),
1666 deallocate_uninit
();
1668 return gnm_expr_top_new
(expr
);
1672 gnm_expr_lex_all
(char const *str
, GnmParsePos
const *pp
,
1673 GnmExprParseFlags flags
,
1674 GnmConventions
const *convs
)
1676 GnmLexerItem
*res
= NULL
;
1677 int n
= 0, alloc
= 0;
1679 GnmParseError
*error = NULL
;
1681 g_return_val_if_fail
(str
!= NULL
, NULL
);
1682 g_return_val_if_fail
(pp
!= NULL
, NULL
);
1684 if
(deallocate_stack
== NULL
)
1687 setup_state
(&pstate
, str
, pp
, flags
, convs
, error);
1693 alloc
= alloc
* 2 + 20;
1694 res
= g_renew
(GnmLexerItem
, res
, alloc
);
1697 res
[n
].start
= pstate.ptr
- pstate.start
;
1698 res
[n
].token
= yylex ();
1699 res
[n
].end
= pstate.ptr
- pstate.start
;
1701 if
(res
[n
].token
== 0)
1704 len
= res
[n
].end
- res
[n
].start
;
1705 /* Kill spaces that got eaten, but not a space operator */
1706 while
(len
> 1 && str
[res
[n
].start
] == ' ') {
1710 while
(len
> 1 && str
[res
[n
].end
- 1] == ' ') {