summaryrefslogtreecommitdiff
path: root/sc/source/filter/inc/formulabase.hxx
blob: 082f3c604965e62853bc264dc3d3a40a59c34e59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
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
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
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
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef OOX_XLS_FORMULABASE_HXX
#define OOX_XLS_FORMULABASE_HXX

#include <com/sun/star/beans/Pair.hpp>
#include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
#include <com/sun/star/sheet/FormulaToken.hpp>
#include <com/sun/star/table/CellAddress.hpp>
#include <com/sun/star/table/CellRangeAddress.hpp>
#include <com/sun/star/uno/Sequence.hxx>
#include "oox/helper/propertyset.hxx"
#include "oox/helper/refvector.hxx"
#include "addressconverter.hxx"

namespace com { namespace sun { namespace star {
    namespace sheet { class XFormulaOpCodeMapper; }
    namespace sheet { class XFormulaParser; }
} } }

namespace oox { template< typename Type > class Matrix; }

namespace oox {
namespace xls {

// Constants ==================================================================

const size_t BIFF_TOKARR_MAXLEN                 = 4096;     /// Maximum size of a token array.

// token class flags ----------------------------------------------------------

const sal_uInt8 BIFF_TOKCLASS_MASK              = 0x60;
const sal_uInt8 BIFF_TOKCLASS_NONE              = 0x00;     /// 00-1F: Base tokens.
const sal_uInt8 BIFF_TOKCLASS_REF               = 0x20;     /// 20-3F: Reference class tokens.
const sal_uInt8 BIFF_TOKCLASS_VAL               = 0x40;     /// 40-5F: Value class tokens.
const sal_uInt8 BIFF_TOKCLASS_ARR               = 0x60;     /// 60-7F: Array class tokens.

const sal_uInt8 BIFF_TOKFLAG_INVALID            = 0x80;     /// This bit must be null for a valid token identifier.

// base token identifiers -----------------------------------------------------

const sal_uInt8 BIFF_TOKID_MASK                 = 0x1F;

const sal_uInt8 BIFF_TOKID_NONE                 = 0x00;     /// Placeholder for invalid token id.
const sal_uInt8 BIFF_TOKID_EXP                  = 0x01;     /// Array or shared formula reference.
const sal_uInt8 BIFF_TOKID_TBL                  = 0x02;     /// Multiple operation reference.
const sal_uInt8 BIFF_TOKID_ADD                  = 0x03;     /// Addition operator.
const sal_uInt8 BIFF_TOKID_SUB                  = 0x04;     /// Subtraction operator.
const sal_uInt8 BIFF_TOKID_MUL                  = 0x05;     /// Multiplication operator.
const sal_uInt8 BIFF_TOKID_DIV                  = 0x06;     /// Division operator.
const sal_uInt8 BIFF_TOKID_POWER                = 0x07;     /// Power operator.
const sal_uInt8 BIFF_TOKID_CONCAT               = 0x08;     /// String concatenation operator.
const sal_uInt8 BIFF_TOKID_LT                   = 0x09;     /// Less than operator.
const sal_uInt8 BIFF_TOKID_LE                   = 0x0A;     /// Less than or equal operator.
const sal_uInt8 BIFF_TOKID_EQ                   = 0x0B;     /// Equal operator.
const sal_uInt8 BIFF_TOKID_GE                   = 0x0C;     /// Greater than or equal operator.
const sal_uInt8 BIFF_TOKID_GT                   = 0x0D;     /// Greater than operator.
const sal_uInt8 BIFF_TOKID_NE                   = 0x0E;     /// Not equal operator.
const sal_uInt8 BIFF_TOKID_ISECT                = 0x0F;     /// Intersection operator.
const sal_uInt8 BIFF_TOKID_LIST                 = 0x10;     /// List operator.
const sal_uInt8 BIFF_TOKID_RANGE                = 0x11;     /// Range operator.
const sal_uInt8 BIFF_TOKID_UPLUS                = 0x12;     /// Unary plus.
const sal_uInt8 BIFF_TOKID_UMINUS               = 0x13;     /// Unary minus.
const sal_uInt8 BIFF_TOKID_PERCENT              = 0x14;     /// Percent sign.
const sal_uInt8 BIFF_TOKID_PAREN                = 0x15;     /// Parentheses.
const sal_uInt8 BIFF_TOKID_MISSARG              = 0x16;     /// Missing argument.
const sal_uInt8 BIFF_TOKID_STR                  = 0x17;     /// String constant.
const sal_uInt8 BIFF_TOKID_NLR                  = 0x18;     /// Natural language reference (NLR).
const sal_uInt8 BIFF_TOKID_ATTR                 = 0x19;     /// Special attribute.
const sal_uInt8 BIFF_TOKID_SHEET                = 0x1A;     /// Start of a sheet reference (BIFF2-BIFF4).
const sal_uInt8 BIFF_TOKID_ENDSHEET             = 0x1B;     /// End of a sheet reference (BIFF2-BIFF4).
const sal_uInt8 BIFF_TOKID_ERR                  = 0x1C;     /// Error constant.
const sal_uInt8 BIFF_TOKID_BOOL                 = 0x1D;     /// Boolean constant.
const sal_uInt8 BIFF_TOKID_INT                  = 0x1E;     /// Integer constant.
const sal_uInt8 BIFF_TOKID_NUM                  = 0x1F;     /// Floating-point constant.

// base identifiers of classified tokens --------------------------------------

const sal_uInt8 BIFF_TOKID_ARRAY                = 0x00;     /// Array constant.
const sal_uInt8 BIFF_TOKID_FUNC                 = 0x01;     /// Function, fixed number of arguments.
const sal_uInt8 BIFF_TOKID_FUNCVAR              = 0x02;     /// Function, variable number of arguments.
const sal_uInt8 BIFF_TOKID_NAME                 = 0x03;     /// Defined name.
const sal_uInt8 BIFF_TOKID_REF                  = 0x04;     /// 2D cell reference.
const sal_uInt8 BIFF_TOKID_AREA                 = 0x05;     /// 2D area reference.
const sal_uInt8 BIFF_TOKID_MEMAREA              = 0x06;     /// Constant reference subexpression.
const sal_uInt8 BIFF_TOKID_MEMERR               = 0x07;     /// Deleted reference subexpression.
const sal_uInt8 BIFF_TOKID_MEMNOMEM             = 0x08;     /// Constant reference subexpression without result.
const sal_uInt8 BIFF_TOKID_MEMFUNC              = 0x09;     /// Variable reference subexpression.
const sal_uInt8 BIFF_TOKID_REFERR               = 0x0A;     /// Deleted 2D cell reference.
const sal_uInt8 BIFF_TOKID_AREAERR              = 0x0B;     /// Deleted 2D area reference.
const sal_uInt8 BIFF_TOKID_REFN                 = 0x0C;     /// Relative 2D cell reference (in names).
const sal_uInt8 BIFF_TOKID_AREAN                = 0x0D;     /// Relative 2D area reference (in names).
const sal_uInt8 BIFF_TOKID_MEMAREAN             = 0x0E;     /// Reference subexpression (in names).
const sal_uInt8 BIFF_TOKID_MEMNOMEMN            = 0x0F;     /// Reference subexpression (in names) without result.
const sal_uInt8 BIFF_TOKID_FUNCCE               = 0x18;
const sal_uInt8 BIFF_TOKID_NAMEX                = 0x19;     /// External reference.
const sal_uInt8 BIFF_TOKID_REF3D                = 0x1A;     /// 3D cell reference.
const sal_uInt8 BIFF_TOKID_AREA3D               = 0x1B;     /// 3D area reference.
const sal_uInt8 BIFF_TOKID_REFERR3D             = 0x1C;     /// Deleted 3D cell reference.
const sal_uInt8 BIFF_TOKID_AREAERR3D            = 0x1D;     /// Deleted 3D area reference

// specific token constants ---------------------------------------------------

const sal_uInt8 BIFF_TOK_ARRAY_DOUBLE           = 0;        /// Double value in an array.
const sal_uInt8 BIFF_TOK_ARRAY_STRING           = 1;        /// String value in an array.
const sal_uInt8 BIFF_TOK_ARRAY_BOOL             = 2;        /// Boolean value in an array.
const sal_uInt8 BIFF_TOK_ARRAY_ERROR            = 4;        /// Error code in an array.

const sal_uInt8 BIFF_TOK_BOOL_FALSE             = 0;        /// FALSE value of a tBool token.
const sal_uInt8 BIFF_TOK_BOOL_TRUE              = 1;        /// TRUE value of a tBool token.

const sal_uInt8 BIFF_TOK_ATTR_VOLATILE          = 0x01;     /// Volatile function.
const sal_uInt8 BIFF_TOK_ATTR_IF                = 0x02;     /// Start of true condition in IF function.
const sal_uInt8 BIFF_TOK_ATTR_CHOOSE            = 0x04;     /// Jump array of CHOOSE function.
const sal_uInt8 BIFF_TOK_ATTR_SKIP              = 0x08;     /// Skip tokens.
const sal_uInt8 BIFF_TOK_ATTR_SUM               = 0x10;     /// SUM function with one parameter.
const sal_uInt8 BIFF_TOK_ATTR_ASSIGN            = 0x20;     /// BASIC style assignment.
const sal_uInt8 BIFF_TOK_ATTR_SPACE             = 0x40;     /// Spaces in formula representation.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_VOLATILE    = 0x41;     /// Leading spaces and volatile formula.
const sal_uInt8 BIFF_TOK_ATTR_IFERROR           = 0x80;     /// Start of condition in IFERROR function (BIFF12 only).

const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP          = 0x00;     /// Spaces before next token.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_BR          = 0x01;     /// Line breaks before next token.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP_OPEN     = 0x02;     /// Spaces before opening parenthesis.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_BR_OPEN     = 0x03;     /// Line breaks before opening parenthesis.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP_CLOSE    = 0x04;     /// Spaces before closing parenthesis.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_BR_CLOSE    = 0x05;     /// Line breaks before closing parenthesis.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP_PRE      = 0x06;     /// Spaces before formula (BIFF3).

const sal_uInt16 BIFF_TOK_FUNCVAR_CMD           = 0x8000;   /// Macro command.
const sal_uInt16 BIFF_TOK_FUNCVAR_FUNCIDMASK    = 0x7FFF;   /// Mask for function/command index.
const sal_uInt8 BIFF_TOK_FUNCVAR_CMDPROMPT      = 0x80;     /// User prompt for macro commands.
const sal_uInt8 BIFF_TOK_FUNCVAR_COUNTMASK      = 0x7F;     /// Mask for parameter count.

const sal_uInt16 BIFF12_TOK_REF_COLMASK         = 0x3FFF;   /// Mask to extract column from reference (BIFF12).
const sal_Int32 BIFF12_TOK_REF_ROWMASK          = 0xFFFFF;  /// Mask to extract row from reference (BIFF12).
const sal_uInt16 BIFF12_TOK_REF_COLREL          = 0x4000;   /// True = column is relative (BIFF12).
const sal_uInt16 BIFF12_TOK_REF_ROWREL          = 0x8000;   /// True = row is relative (BIFF12).

const sal_uInt16 BIFF_TOK_REF_COLMASK           = 0x00FF;   /// Mask to extract BIFF8 column from reference.
const sal_uInt16 BIFF_TOK_REF_ROWMASK           = 0x3FFF;   /// Mask to extract BIFF2-BIFF5 row from reference.
const sal_uInt16 BIFF_TOK_REF_COLREL            = 0x4000;   /// True = column is relative.
const sal_uInt16 BIFF_TOK_REF_ROWREL            = 0x8000;   /// True = row is relative.

const sal_uInt16 BIFF12_TOK_TABLE_COLUMN         = 0x0001;   /// Table reference: Single column.
const sal_uInt16 BIFF12_TOK_TABLE_COLRANGE       = 0x0002;   /// Table reference: Range of columns.
const sal_uInt16 BIFF12_TOK_TABLE_ALL            = 0x0004;   /// Table reference: Special [#All] range.
const sal_uInt16 BIFF12_TOK_TABLE_HEADERS        = 0x0008;   /// Table reference: Special [#Headers] range.
const sal_uInt16 BIFF12_TOK_TABLE_DATA           = 0x0010;   /// Table reference: Special [#Data] range.
const sal_uInt16 BIFF12_TOK_TABLE_TOTALS         = 0x0020;   /// Table reference: Special [#Totals] range.
const sal_uInt16 BIFF12_TOK_TABLE_THISROW        = 0x0040;   /// Table reference: Special [#This Row] range.
const sal_uInt16 BIFF12_TOK_TABLE_SP_BRACKETS    = 0x0080;   /// Table reference: Spaces in outer brackets.
const sal_uInt16 BIFF12_TOK_TABLE_SP_SEP         = 0x0100;   /// Table reference: Spaces after separators.
const sal_uInt16 BIFF12_TOK_TABLE_ROW            = 0x0200;   /// Table reference: Single row.
const sal_uInt16 BIFF12_TOK_TABLE_CELL           = 0x0400;   /// Table reference: Single cell.

const sal_uInt8 BIFF_TOK_NLR_ERR                = 0x01;     /// NLR: Invalid/deleted.
const sal_uInt8 BIFF_TOK_NLR_ROWR               = 0x02;     /// NLR: Row index.
const sal_uInt8 BIFF_TOK_NLR_COLR               = 0x03;     /// NLR: Column index.
const sal_uInt8 BIFF_TOK_NLR_ROWV               = 0x06;     /// NLR: Value in row.
const sal_uInt8 BIFF_TOK_NLR_COLV               = 0x07;     /// NLR: Value in column.
const sal_uInt8 BIFF_TOK_NLR_RANGE              = 0x0A;     /// NLR: Range.
const sal_uInt8 BIFF_TOK_NLR_SRANGE             = 0x0B;     /// Stacked NLR: Range.
const sal_uInt8 BIFF_TOK_NLR_SROWR              = 0x0C;     /// Stacked NLR: Row index.
const sal_uInt8 BIFF_TOK_NLR_SCOLR              = 0x0D;     /// Stacked NLR: Column index.
const sal_uInt8 BIFF_TOK_NLR_SROWV              = 0x0E;     /// Stacked NLR: Value in row.
const sal_uInt8 BIFF_TOK_NLR_SCOLV              = 0x0F;     /// Stacked NLR: Value in column.
const sal_uInt8 BIFF_TOK_NLR_RANGEERR           = 0x10;     /// NLR: Invalid/deleted range.
const sal_uInt8 BIFF_TOK_NLR_SXNAME             = 0x1D;     /// NLR: Pivot table name.
const sal_uInt16 BIFF_TOK_NLR_REL               = 0x8000;   /// True = NLR is relative.
const sal_uInt16 BIFF_TOK_NLR_MASK              = 0x3FFF;   /// Mask to extract BIFF8 column from NLR.

const sal_uInt32 BIFF_TOK_NLR_ADDREL            = 0x80000000;   /// NLR relative (in appended data).
const sal_uInt32 BIFF_TOK_NLR_ADDMASK           = 0x3FFFFFFF;   /// Mask for number of appended ranges.

// function constants ---------------------------------------------------------

const sal_uInt8 OOX_MAX_PARAMCOUNT              = 255;      /// Maximum parameter count for OOXML/BIFF12 files.
const sal_uInt8 BIFF_MAX_PARAMCOUNT             = 30;       /// Maximum parameter count for BIFF2-BIFF8 files.

const sal_uInt16 BIFF_FUNC_IF                   = 1;        /// Function identifier of the IF function.
const sal_uInt16 BIFF_FUNC_SUM                  = 4;        /// Function identifier of the SUM function.
const sal_uInt16 BIFF_FUNC_TRUE                 = 34;       /// Function identifier of the TRUE function.
const sal_uInt16 BIFF_FUNC_FALSE                = 35;       /// Function identifier of the FALSE function.
const sal_uInt16 BIFF_FUNC_ROWS                 = 76;       /// Function identifier of the ROWS function.
const sal_uInt16 BIFF_FUNC_COLUMNS              = 77;       /// Function identifier of the COLUMNS function.
const sal_uInt16 BIFF_FUNC_OFFSET               = 78;       /// Function identifier of the OFFSET function.
const sal_uInt16 BIFF_FUNC_EXTERNCALL           = 255;      /// BIFF function id of the EXTERN.CALL function.
const sal_uInt16 BIFF_FUNC_FLOOR                = 285;      /// Function identifier of the FLOOR function.
const sal_uInt16 BIFF_FUNC_CEILING              = 288;      /// Function identifier of the CEILING function.
const sal_uInt16 BIFF_FUNC_HYPERLINK            = 359;      /// Function identifier of the HYPERLINK function.
const sal_uInt16 BIFF_FUNC_WEEKNUM              = 465;      /// Function identifier of the WEEKNUM function.

// Formula type ===============================================================

/** Enumerates all possible types of a formula. */
enum FormulaType
{
    FORMULATYPE_CELL,           /// Simple cell formula, or reference to a shared formula name.
    FORMULATYPE_ARRAY,          /// Array (matrix) formula.
    FORMULATYPE_SHAREDFORMULA,  /// Shared formula definition.
    FORMULATYPE_CONDFORMAT,     /// Condition of a conditional format rule.
    FORMULATYPE_VALIDATION,     /// Condition of a data validation.
    FORMULATYPE_DEFINEDNAME     /// Definition of a defined name.
};

// Reference helpers ==========================================================

/** A 2D formula cell reference struct with relative flags. */
struct BinSingleRef2d
{
    sal_Int32           mnCol;              /// Column index.
    sal_Int32           mnRow;              /// Row index.
    bool                mbColRel;           /// True = relative column reference.
    bool                mbRowRel;           /// True = relative row reference.

    explicit            BinSingleRef2d();

    void                setBiff12Data( sal_uInt16 nCol, sal_Int32 nRow, bool bRelativeAsOffset );
    void                setBiff2Data( sal_uInt8 nCol, sal_uInt16 nRow, bool bRelativeAsOffset );
    void                setBiff8Data( sal_uInt16 nCol, sal_uInt16 nRow, bool bRelativeAsOffset );

    void                readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset );
    void                readBiff2Data( BiffInputStream& rStrm, bool bRelativeAsOffset );
    void                readBiff8Data( BiffInputStream& rStrm, bool bRelativeAsOffset );
};

// ----------------------------------------------------------------------------

/** A 2D formula cell range reference struct with relative flags. */
struct BinComplexRef2d
{
    BinSingleRef2d      maRef1;             /// Start (top-left) cell address.
    BinSingleRef2d      maRef2;             /// End (bottom-right) cell address.

    void                readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset );
    void                readBiff2Data( BiffInputStream& rStrm, bool bRelativeAsOffset );
    void                readBiff8Data( BiffInputStream& rStrm, bool bRelativeAsOffset );
};

// Token vector, token sequence ===============================================

typedef ::com::sun::star::sheet::FormulaToken       ApiToken;
typedef ::com::sun::star::uno::Sequence< ApiToken > ApiTokenSequence;

/** Contains the base address and type of a special token representing an array
    formula or a shared formula (sal_False), or a table operation (sal_True). */
typedef ::com::sun::star::beans::Pair< ::com::sun::star::table::CellAddress, sal_Bool > ApiSpecialTokenInfo;

/** A vector of formula tokens with additional convenience functions. */
class ApiTokenVector : public ::std::vector< ApiToken >
{
public:
    explicit            ApiTokenVector();

    /** Appends a new token with the passed op-code, returns its data field. */
    ::com::sun::star::uno::Any&
                        append( sal_Int32 nOpCode );

    /** Appends a new token with the passed op-code and data. */
    template< typename Type >
    inline void         append( sal_Int32 nOpCode, const Type& rData ) { append( nOpCode ) <<= rData; }
};

// Token sequence iterator ====================================================

/** Token sequence iterator that is able to skip space tokens. */
class ApiTokenIterator
{
public:
    explicit            ApiTokenIterator( const ApiTokenSequence& rTokens, sal_Int32 nSpacesOpCode, bool bSkipSpaces );
    inline bool         is() const { return mpToken != mpTokenEnd; }
    inline const ApiToken* get() const { return mpToken; }
    inline const ApiToken* operator->() const { return mpToken; }
    inline const ApiToken& operator*() const { return *mpToken; }

    ApiTokenIterator&   operator++();

private:
    void                skipSpaces();

private:
    const ApiToken*     mpToken;            /// Pointer to current token of the token sequence.
    const ApiToken*     mpTokenEnd;         /// Pointer behind last token of the token sequence.
    const sal_Int32     mnSpacesOpCode;     /// Op-code for whitespace tokens.
    const bool          mbSkipSpaces;       /// true = Skip whitespace tokens.
};

// List of API op-codes =======================================================

/** Contains all API op-codes needed to build formulas with tokens. */
struct ApiOpCodes
{
    // special
    sal_Int32           OPCODE_UNKNOWN;         /// Internal: function name unknown to mapper.
    sal_Int32           OPCODE_EXTERNAL;        /// External function call (e.g. add-ins).
    // formula structure
    sal_Int32           OPCODE_PUSH;            /// Op-code for common value operands.
    sal_Int32           OPCODE_MISSING;         /// Placeholder for a missing function parameter.
    sal_Int32           OPCODE_SPACES;          /// Spaces between other formula tokens.
    sal_Int32           OPCODE_NAME;            /// Index of a defined name.
    sal_Int32           OPCODE_DBAREA;          /// Index of a database area.
    sal_Int32           OPCODE_NLR;             /// Natural language reference.
    sal_Int32           OPCODE_DDE;             /// DDE link function.
    sal_Int32           OPCODE_MACRO;           /// Macro function call.
    sal_Int32           OPCODE_BAD;             /// Bad token (unknown name, formula error).
    sal_Int32           OPCODE_NONAME;          /// Function style #NAME? error.
    // separators
    sal_Int32           OPCODE_OPEN;            /// Opening parenthesis.
    sal_Int32           OPCODE_CLOSE;           /// Closing parenthesis.
    sal_Int32           OPCODE_SEP;             /// Function parameter separator.
    // array separators
    sal_Int32           OPCODE_ARRAY_OPEN;      /// Opening brace for constant arrays.
    sal_Int32           OPCODE_ARRAY_CLOSE;     /// Closing brace for constant arrays.
    sal_Int32           OPCODE_ARRAY_ROWSEP;    /// Row separator in constant arrays.
    sal_Int32           OPCODE_ARRAY_COLSEP;    /// Column separator in constant arrays.
    // unary operators
    sal_Int32           OPCODE_PLUS_SIGN;       /// Unary plus sign.
    sal_Int32           OPCODE_MINUS_SIGN;      /// Unary minus sign.
    sal_Int32           OPCODE_PERCENT;         /// Percent sign.
    // binary operators
    sal_Int32           OPCODE_ADD;             /// Addition operator.
    sal_Int32           OPCODE_SUB;             /// Subtraction operator.
    sal_Int32           OPCODE_MULT;            /// Multiplication operator.
    sal_Int32           OPCODE_DIV;             /// Division operator.
    sal_Int32           OPCODE_POWER;           /// Power operator.
    sal_Int32           OPCODE_CONCAT;          /// String concatenation operator.
    sal_Int32           OPCODE_EQUAL;           /// Compare equal operator.
    sal_Int32           OPCODE_NOT_EQUAL;       /// Compare not equal operator.
    sal_Int32           OPCODE_LESS;            /// Compare less operator.
    sal_Int32           OPCODE_LESS_EQUAL;      /// Compare less or equal operator.
    sal_Int32           OPCODE_GREATER;         /// Compare greater operator.
    sal_Int32           OPCODE_GREATER_EQUAL;   /// Compare greater or equal operator.
    sal_Int32           OPCODE_INTERSECT;       /// Range intersection operator.
    sal_Int32           OPCODE_LIST;            /// Range list operator.
    sal_Int32           OPCODE_RANGE;           /// Range operator.
};

// Function parameter info ====================================================

/** Enumerates validity modes for a function parameter. */
enum FuncParamValidity
{
    FUNC_PARAM_NONE = 0,        /// Default for an unspecified entry in a C-array.
    FUNC_PARAM_REGULAR,         /// Parameter supported by Calc and Excel.
    FUNC_PARAM_CALCONLY,        /// Parameter supported by Calc only.
    FUNC_PARAM_EXCELONLY        /// Parameter supported by Excel only.
};

/** Enumerates different types of token class conversion in function parameters. */
enum FuncParamConversion
{
    FUNC_PARAMCONV_ORG,         /// Use original class of current token.
    FUNC_PARAMCONV_VAL,         /// Convert tokens to VAL class.
    FUNC_PARAMCONV_ARR,         /// Convert tokens to ARR class.
    FUNC_PARAMCONV_RPT,         /// Repeat parent conversion in VALTYPE parameters.
    FUNC_PARAMCONV_RPX,         /// Repeat parent conversion in REFTYPE parameters.
    FUNC_PARAMCONV_RPO          /// Repeat parent conversion in operands of operators.
};

/** Structure that contains all needed information for a parameter in a
    function.

    The member meValid specifies which application supports the parameter. If
    set to CALCONLY, import filters have to insert a default value for this
    parameter, and export filters have to skip the parameter. If set to
    EXCELONLY, import filters have to skip the parameter, and export filters
    have to insert a default value for this parameter.

    The member mbValType specifies whether the parameter requires tokens to be
    of value type (VAL or ARR class).

        If set to false, the parameter is called to be REFTYPE. Tokens with REF
        default class can be inserted for the parameter (e.g. tAreaR tokens).

        If set to true, the parameter is called to be VALTYPE. Tokens with REF
        class need to be converted to VAL tokens first (e.g. tAreaR will be
        converted to tAreaV), and further conversion is done according to this
        new token class.

    The member meConv specifies how to convert the current token class of the
    token inserted for the parameter. If the token class is still REF this
    means that the token has default REF class and the parameter is REFTYPE
    (see member mbValType), the token will not be converted at all and remains
    in REF class. Otherwise, token class conversion is depending on the actual
    token class of the return value of the function containing this parameter.
    The function may return REF class (tFuncR, tFuncVarR, tFuncCER), or it may
    return VAL or ARR class (tFuncV, tFuncA, tFuncVarV, tFuncVarA, tFuncCEV,
    tFuncCEA). Even if the function is able to return REF class, it may return
    VAL or ARR class instead due to the VALTYPE data type of the parent
    function parameter that calls the own function. Example: The INDIRECT
    function returns REF class by default. But if called from a VALTYPE
    function parameter, e.g. in the formula =ABS(INDIRECT("A1")), it returns
    VAL or ARR class instead. Additionally, the repeating conversion types RPT
    and RPX rely on the conversion executed for the function token class.

        1) ORG:
        Use the original class of the token (VAL or ARR), regardless of any
        conversion done for the function return class.

        2) VAL:
        Convert ARR tokens to VAL class, regardless of any conversion done for
        the function return class.

        3) ARR:
        Convert VAL tokens to ARR class, regardless of any conversion done for
        the function return class.

        4) RPT:
        If the own function returns REF class (thus it is called from a REFTYPE
        parameter, see above), and the parent conversion type (for the function
        return class) was ORG, VAL, or ARR, ignore that conversion and always
        use VAL conversion for the own token instead. If the parent conversion
        type was RPT or RPX, repeat the conversion that would have been used if
        the function would return value type.
        If the own function returns value type (VAL or ARR class, see above),
        and the parent conversion type (for the function return class) was ORG,
        VAL, ARR, or RPT, repeat this conversion for the own token. If the
        parent conversion type was RPX, always use ORG conversion type for the
        own token instead.

        5) RPX:
        This type of conversion only occurs in functions returning VAL class by
        default. If the own token is value type, and the VAL return class of
        the own function has been changed to ARR class (due to direct ARR
        conversion, or due to ARR conversion repeated by RPT or RPX), set the
        own token to ARR type. Otherwise use the original token type (VAL
        conversion from parent parameter will not be repeated at all). If
        nested functions have RPT or value-type RPX parameters, they will not
        repeat this conversion type, but will use ORG conversion instead (see
        description of RPT above).

        6) RPO:
        This type of conversion is only used for the operands of all operators
        (unary and binary arithmetic operators, comparison operators, and range
        operators). It is not used for function parameters. On conversion, it
        will be replaced by the last conversion type that was not the RPO
        conversion. This leads to a slightly different behaviour than the RPT
        conversion for operands in conjunction with a parent RPX conversion.
 */
struct FunctionParamInfo
{
    FuncParamValidity   meValid;        /// Parameter validity.
    FuncParamConversion meConv;         /// Token class conversion type.
    bool                mbValType;      /// Data type (false = REFTYPE, true = VALTYPE).
};

// Function data ==============================================================

/** This enumeration contains constants for all known external libraries
    containing supported sheet functions. */
enum FunctionLibraryType
{
    FUNCLIB_UNKNOWN = 0,        /// Unknown library (must be zero).
    FUNCLIB_EUROTOOL            /// EuroTool add-in with EUROCONVERT function.
};

// ----------------------------------------------------------------------------

/** Represents information for a spreadsheet function.

    The member mpParamInfos points to a C-array of type information structures
    for all parameters of the function. The last initialized structure
    describing a regular parameter (member meValid == FUNC_PARAM_REGULAR) in
    this array is used repeatedly for all following parameters supported by a
    function.
 */
struct FunctionInfo
{
    ::rtl::OUString     maOdfFuncName;      /// ODF function name.
    ::rtl::OUString     maOoxFuncName;      /// OOXML function name.
    ::rtl::OUString     maBiffMacroName;    /// Expected macro name in EXTERN.CALL function.
    ::rtl::OUString     maExtProgName;      /// Programmatic function name for external functions.
    FunctionLibraryType meFuncLibType;      /// The external library this function is part of.
    sal_Int32           mnApiOpCode;        /// API function opcode.
    sal_uInt16          mnBiff12FuncId;     /// BIFF12 function identifier.
    sal_uInt16          mnBiffFuncId;       /// BIFF2-BIFF8 function identifier.
    sal_uInt8           mnMinParamCount;    /// Minimum number of parameters.
    sal_uInt8           mnMaxParamCount;    /// Maximum number of parameters.
    sal_uInt8           mnRetClass;         /// BIFF token class of the return value.
    const FunctionParamInfo* mpParamInfos;  /// Information about all parameters.
    bool                mbParamPairs;       /// True = optional parameters are expected to appear in pairs.
    bool                mbVolatile;         /// True = volatile function.
    bool                mbExternal;         /// True = external function in Calc.
    bool                mbMacroFunc;        /// True = macro sheet function or command.
    bool                mbVarParam;         /// True = use a tFuncVar token, also if min/max are equal.
};

typedef RefVector< FunctionInfo > FunctionInfoVector;

// Function info parameter class iterator =====================================

/** Iterator working on the mpParamInfos member of the FunctionInfo struct.

    This iterator can be used to iterate through the array containing the
    token class conversion information of function parameters. This iterator
    repeats the last valid structure in the array - it stops automatically
    before the first empty array entry or before the end of the array, even for
    repeated calls to the increment operator.
 */
class FunctionParamInfoIterator
{
public:
    explicit            FunctionParamInfoIterator( const FunctionInfo& rFuncInfo );

    bool                isCalcOnlyParam() const;
    bool                isExcelOnlyParam() const;
    FunctionParamInfoIterator& operator++();

private:
    const FunctionParamInfo* mpParamInfo;
    const FunctionParamInfo* mpParamInfoEnd;
    bool                mbParamPairs;
};

// Base function provider =====================================================

struct FunctionProviderImpl;

/** Provides access to function info structs for all available sheet functions.
 */
class FunctionProvider  // not derived from WorkbookHelper to make it usable in file dumpers
{
public:
    explicit            FunctionProvider( FilterType eFilter, BiffType eBiff, bool bImportFilter,
                                          bool bCallerKnowsAboutMacroExport );
    virtual             ~FunctionProvider();

    /** Returns the function info for an OOXML function name, or 0 on error. */
    const FunctionInfo* getFuncInfoFromOoxFuncName( const ::rtl::OUString& rFuncName ) const;

    /** Returns the function info for a BIFF12 function index, or 0 on error. */
    const FunctionInfo* getFuncInfoFromBiff12FuncId( sal_uInt16 nFuncId ) const;

    /** Returns the function info for a BIFF2-BIFF8 function index, or 0 on error. */
    const FunctionInfo* getFuncInfoFromBiffFuncId( sal_uInt16 nFuncId ) const;

    /** Returns the function info for a macro function referred by the
        EXTERN.CALL function, or 0 on error. */
    const FunctionInfo* getFuncInfoFromMacroName( const ::rtl::OUString& rFuncName ) const;

    /** Returns the library type associated with the passed URL of a function
        library (function add-in). */
    FunctionLibraryType getFuncLibTypeFromLibraryName( const ::rtl::OUString& rLibraryName ) const;

protected:
    /** Returns the list of all function infos. */
    const FunctionInfoVector& getFuncs() const;

private:
    typedef ::boost::shared_ptr< FunctionProviderImpl > FunctionProviderImplRef;
    FunctionProviderImplRef mxFuncImpl;     /// Shared implementation between all copies of the provider.
};

// Op-code and function provider ==============================================

struct OpCodeProviderImpl;

/** Provides access to API op-codes for all available formula tokens and to
    function info structs for all available sheet functions.
 */
class OpCodeProvider : public FunctionProvider // not derived from WorkbookHelper to make it usable as UNO service
{
public:
    explicit            OpCodeProvider(
                            const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxModelFactory,
                            FilterType eFilter, BiffType eBiff, bool bImportFilter,
                            bool bCallerKnowsAboutMacroExport = false );
    virtual             ~OpCodeProvider();

    /** Returns the structure containing all token op-codes for operators and
        special tokens used by the Calc document and its formula parser. */
    const ApiOpCodes&   getOpCodes() const;

    /** Returns the function info for an API token, or 0 on error. */
    const FunctionInfo* getFuncInfoFromApiToken( const ApiToken& rToken ) const;

    /** Returns the op-code map that is used by the OOXML formula parser. */
    ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaOpCodeMapEntry >
                        getOoxParserMap() const;

private:
    typedef ::boost::shared_ptr< OpCodeProviderImpl > OpCodeProviderImplRef;
    OpCodeProviderImplRef mxOpCodeImpl;     /// Shared implementation between all copies of the provider.
};

// API formula parser wrapper =================================================

/** A wrapper around the FormulaParser service provided by the Calc document. */
class ApiParserWrapper : public OpCodeProvider
{
public:
    explicit            ApiParserWrapper(
                            const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxModelFactory,
                            const OpCodeProvider& rOpCodeProv );

    /** Returns read/write access to the formula parser property set. */
    inline PropertySet& getParserProperties() { return maParserProps; }

    /** Calls the XFormulaParser::parseFormula() function of the API parser. */
    ApiTokenSequence    parseFormula(
                            const ::rtl::OUString& rFormula,
                            const ::com::sun::star::table::CellAddress& rRefPos );

private:
    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaParser >
                        mxParser;
    PropertySet         maParserProps;
};

// Formula parser/printer base class for filters ==============================

/** Base class for import formula parsers and export formula compilers. */
class FormulaProcessorBase : public OpCodeProvider, protected ApiOpCodes, public WorkbookHelper
{
public:
    explicit            FormulaProcessorBase( const WorkbookHelper& rHelper );

    // ------------------------------------------------------------------------

    /** Generates a cell address string in A1 notation from the passed cell
        address.

        @param rAddress  The cell address containing column and row index.
        @param bAbsolute  True = adds dollar signs before column and row.
     */
    static ::rtl::OUString generateAddress2dString(
                            const ::com::sun::star::table::CellAddress& rAddress,
                            bool bAbsolute );

    /** Generates a cell address string in A1 notation from the passed binary
        cell address.

        @param rAddress  The cell address containing column and row index.
        @param bAbsolute  True = adds dollar signs before column and row.
     */
    static ::rtl::OUString generateAddress2dString(
                            const BinAddress& rAddress,
                            bool bAbsolute );

    // ------------------------------------------------------------------------

    /** Generates a string in Calc formula notation from the passed string.

        @param rString  The string value.

        @return  The string enclosed in double quotes, where all contained
            quote characters are doubled.
     */
    static ::rtl::OUString generateApiString( const ::rtl::OUString& rString );

    /** Generates an array string in Calc formula notation from the passed
        matrix with Any's containing double values or strings.

        @param rMatrix  The matrix containing double values or strings.
     */
    static ::rtl::OUString generateApiArray( const Matrix< ::com::sun::star::uno::Any >& rMatrix );

    // ------------------------------------------------------------------------

    /** Tries to extract a single cell reference from a formula token sequence.

        @param rTokens  The token sequence to be parsed. Should contain exactly
            one address token or cell range address token. The token sequence
            may contain whitespace tokens.

        @return  If the token sequence is valid, this function returns an Any
            containing a com.sun.star.sheet.SingleReference object, or a
            com.sun.star.sheet.ComplexReference object. If the token sequence
            contains too many, or unexpected tokens, an empty Any is returned.
     */
    ::com::sun::star::uno::Any
                        extractReference( const ApiTokenSequence& rTokens ) const;

    /** Tries to extract a cell range address from a formula token sequence.

        @param orAddress  (output parameter) If the token sequence is valid,
            this parameter will contain the extracted cell range address. If
            the token sequence contains unexpected tokens, nothing meaningful
            is inserted, and the function returns false.

        @param rTokens  The token sequence to be parsed. Should contain exactly
            one cell range address token. The token sequence may contain
            whitespace tokens.

        @param bAllowRelative  True = it is allowed that rTokens contains
            relative references (based on cell A1 of the current sheet).
            False = only real absolute references will be accepted.

        @return  True, if the token sequence contains a valid cell range
            address which has been extracted to orRange, false otherwise.
     */
    bool                extractCellRange(
                            ::com::sun::star::table::CellRangeAddress& orRange,
                            const ApiTokenSequence& rTokens,
                            bool bAllowRelative ) const;

    /** Tries to extract a cell range list from a formula token sequence.

        @param orRanges  (output parameter) If the token sequence is valid,
            this parameter will contain the extracted cell range list. Deleted
            cells or cell ranges (shown as #REF! error in a formula) will be
            skipped. If the token sequence contains unexpected tokens, an empty
            list is returned here.

        @param rTokens  The token sequence to be parsed. Should contain cell
            address tokens or cell range address tokens, separated by the
            standard function parameter separator token. The token sequence may
            contain parentheses and whitespace tokens.

        @param bAllowRelative  True = it is allowed that rTokens contains
            relative references (based on cell A1 of the current sheet).
            False = only real absolute references will be accepted.

        @param nFilterBySheet  If non-negative, this function returns only cell
            ranges located in the specified sheet, otherwise returns all cell
            ranges contained in the token sequence.
     */
    void                extractCellRangeList(
                            ApiCellRangeList& orRanges,
                            const ApiTokenSequence& rTokens,
                            bool bAllowRelative,
                            sal_Int32 nFilterBySheet = -1 ) const;

    /** Tries to extract a string from a formula token sequence.

        @param orString  (output parameter) The extracted string.

        @param rTokens  The token sequence to be parsed. Should contain exactly
            one string token, may contain whitespace tokens.

        @return  True = token sequence is valid, output parameter orString
            contains the string extracted from the token sequence.
     */
    bool                extractString(
                            ::rtl::OUString& orString,
                            const ApiTokenSequence& rTokens ) const;

    /** Tries to extract information about a special token used for array
        formulas, shared formulas, or table operations.

        @param orTokenInfo  (output parameter) The extracted information about
            the token. Contains the base address and the token type (sal_False
            for array or shared formulas, sal_True for table operations).

        @param rTokens  The token sequence to be parsed. If it contains exactly
            one OPCODE_BAD token with special token information, this
            information will be extracted.

        @return  True = token sequence is valid, output parameter orTokenInfo
            contains the token information extracted from the token sequence.
     */
    bool                extractSpecialTokenInfo(
                            ApiSpecialTokenInfo& orTokenInfo,
                            const ApiTokenSequence& rTokens ) const;

    /** Converts a single string with separators in the passed formula token
        sequence to a list of string tokens.

        @param orTokens  (input/output parameter) Expects a single string token
            in this token sequence (whitespace tokens are allowed). The string
            is split into substrings. A list of string tokens separated with
            parameter separator tokens is returned in this psrameter.

        @param cStringSep  The separator character used to split the input
            string.

        @param bTrimLeadingSpaces  True = removes leading whitespace from all
            substrings inserted into the formula token sequence.
     */
    void                convertStringToStringList(
                            ApiTokenSequence& orTokens,
                            sal_Unicode cStringSep,
                            bool bTrimLeadingSpaces ) const;
};

// ============================================================================

} // namespace xls
} // namespace oox

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */