xref: /aoo41x/main/sc/source/filter/excel/xeformula.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 #include "xeformula.hxx"
32 
33 #include <list>
34 #include <map>
35 #include <memory>
36 #include "addincol.hxx"
37 #include "compiler.hxx"
38 #include "document.hxx"
39 #include "externalrefmgr.hxx"
40 #include "rangelst.hxx"
41 #include "token.hxx"
42 #include "tokenarray.hxx"
43 #include "xehelper.hxx"
44 #include "xelink.hxx"
45 #include "xename.hxx"
46 #include "xestream.hxx"
47 
48 using namespace ::formula;
49 
50 // External reference log =====================================================
51 
52 XclExpRefLogEntry::XclExpRefLogEntry() :
53     mpUrl( 0 ),
54     mpFirstTab( 0 ),
55     mpLastTab( 0 ),
56     mnFirstXclTab( EXC_TAB_DELETED ),
57     mnLastXclTab( EXC_TAB_DELETED )
58 {
59 }
60 
61 // Formula compiler ===========================================================
62 
63 namespace {
64 
65 /** Wrapper structure for a processed Calc formula token with additional
66     settings (whitespaces). */
67 struct XclExpScToken
68 {
69     const FormulaToken* mpScToken;          /// Currently processed Calc token.
70     sal_uInt8           mnSpaces;           /// Number of spaces before the Calc token.
71 
72     inline explicit     XclExpScToken() : mpScToken( 0 ), mnSpaces( 0 ) {}
73     inline bool         Is() const { return mpScToken != 0; }
74     inline StackVar     GetType() const { return mpScToken ? mpScToken->GetType() : static_cast< StackVar >( svUnknown ); }
75     inline OpCode       GetOpCode() const { return mpScToken ? mpScToken->GetOpCode() : static_cast< OpCode >( ocNone ); }
76 };
77 
78 // ----------------------------------------------------------------------------
79 
80 /** Effective token class conversion types. */
81 enum XclExpClassConv
82 {
83     EXC_CLASSCONV_ORG,          /// Keep original class of the token.
84     EXC_CLASSCONV_VAL,          /// Convert ARR tokens to VAL class (REF remains uncahnged).
85     EXC_CLASSCONV_ARR           /// Convert VAL tokens to ARR class (REF remains uncahnged).
86 };
87 
88 // ----------------------------------------------------------------------------
89 
90 /** Token class conversion and position of a token in the token array. */
91 struct XclExpTokenConvInfo
92 {
93     sal_uInt16          mnTokPos;       /// Position of the token in the token array.
94     XclFuncParamConv    meConv;         /// Token class conversion type.
95     bool                mbValType;      /// Data type (false = REFTYPE, true = VALTYPE).
96 };
97 
98 /** Vector of token position and conversion for all operands of an operator,
99     or for all parameters of a function. */
100 struct XclExpOperandList : public ::std::vector< XclExpTokenConvInfo >
101 {
102     inline explicit     XclExpOperandList() { reserve( 2 ); }
103     void                AppendOperand( sal_uInt16 nTokPos, XclFuncParamConv eConv, bool bValType );
104 };
105 
106 void XclExpOperandList::AppendOperand( sal_uInt16 nTokPos, XclFuncParamConv eConv, bool bValType )
107 {
108     resize( size() + 1 );
109     XclExpTokenConvInfo& rConvInfo = back();
110     rConvInfo.mnTokPos = nTokPos;
111     rConvInfo.meConv = eConv;
112     rConvInfo.mbValType = bValType;
113 }
114 
115 typedef ScfRef< XclExpOperandList > XclExpOperandListRef;
116 typedef ::std::vector< XclExpOperandListRef > XclExpOperandListVector;
117 
118 // ----------------------------------------------------------------------------
119 
120 /** Encapsulates all data needed for a call to an external function (macro, add-in). */
121 struct XclExpExtFuncData
122 {
123     String              maFuncName;         /// Name of the function.
124     bool                mbVBasic;           /// True = Visual Basic macro call.
125     bool                mbHidden;           /// True = Create hidden defined name.
126 
127     inline explicit     XclExpExtFuncData() : mbVBasic( false ), mbHidden( false ) {}
128     void                Set( const String& rFuncName, bool bVBasic, bool bHidden );
129 };
130 
131 void XclExpExtFuncData::Set( const String& rFuncName, bool bVBasic, bool bHidden )
132 {
133     maFuncName = rFuncName;
134     mbVBasic = bVBasic;
135     mbHidden = bHidden;
136 }
137 
138 // ----------------------------------------------------------------------------
139 
140 /** Encapsulates all data needed to process an entire function. */
141 class XclExpFuncData
142 {
143 public:
144     explicit            XclExpFuncData(
145                             const XclExpScToken& rTokData,
146                             const XclFunctionInfo& rFuncInfo,
147                             const XclExpExtFuncData& rExtFuncData );
148 
149     inline const FormulaToken& GetScToken() const { return *mrTokData.mpScToken; }
150     inline OpCode       GetOpCode() const { return mrFuncInfo.meOpCode; }
151     inline sal_uInt16   GetXclFuncIdx() const { return mrFuncInfo.mnXclFunc; }
152     inline bool         IsVolatile() const { return mrFuncInfo.IsVolatile(); }
153     inline bool         IsFixedParamCount() const { return mrFuncInfo.IsFixedParamCount(); }
154     inline bool         IsMacroFunc() const { return mrFuncInfo.IsMacroFunc(); }
155     inline sal_uInt8    GetSpaces() const { return mrTokData.mnSpaces; }
156     inline const XclExpExtFuncData& GetExtFuncData() const { return maExtFuncData; }
157     inline sal_uInt8    GetReturnClass() const { return mrFuncInfo.mnRetClass; }
158 
159     const XclFuncParamInfo& GetParamInfo() const;
160     bool                IsCalcOnlyParam() const;
161     bool                IsExcelOnlyParam() const;
162     void                IncParamInfoIdx();
163 
164     inline sal_uInt8    GetMinParamCount() const { return mrFuncInfo.mnMinParamCount; }
165     inline sal_uInt8    GetMaxParamCount() const { return mrFuncInfo.mnMaxParamCount; }
166     inline sal_uInt8    GetParamCount() const { return static_cast< sal_uInt8 >( mxOperands->size() ); }
167     void                FinishParam( sal_uInt16 nTokPos );
168     inline XclExpOperandListRef GetOperandList() const { return mxOperands; }
169 
170     inline ScfUInt16Vec& GetAttrPosVec() { return maAttrPosVec; }
171     inline void         AppendAttrPos( sal_uInt16 nPos ) { maAttrPosVec.push_back( nPos ); }
172 
173 private:
174     ScfUInt16Vec        maAttrPosVec;       /// Token array positions of tAttr tokens.
175     const XclExpScToken& mrTokData;         /// Data about processed function name token.
176     const XclFunctionInfo& mrFuncInfo;      /// Constant data about processed function.
177     XclExpExtFuncData   maExtFuncData;      /// Data for external functions (macro, add-in).
178     XclExpOperandListRef mxOperands;        /// Class conversion and position of all parameters.
179     const XclFuncParamInfo* mpParamInfo;    /// Information for current parameter.
180 };
181 
182 XclExpFuncData::XclExpFuncData( const XclExpScToken& rTokData,
183         const XclFunctionInfo& rFuncInfo, const XclExpExtFuncData& rExtFuncData ) :
184     mrTokData( rTokData ),
185     mrFuncInfo( rFuncInfo ),
186     maExtFuncData( rExtFuncData ),
187     mxOperands( new XclExpOperandList ),
188     mpParamInfo( rFuncInfo.mpParamInfos )
189 {
190     DBG_ASSERT( mrTokData.mpScToken, "XclExpFuncData::XclExpFuncData - missing core token" );
191     // set name of an add-in function
192     if( (maExtFuncData.maFuncName.Len() == 0) && dynamic_cast< const FormulaExternalToken* >( mrTokData.mpScToken ) )
193         maExtFuncData.Set( GetScToken().GetExternal(), true, false );
194 }
195 
196 const XclFuncParamInfo& XclExpFuncData::GetParamInfo() const
197 {
198     static const XclFuncParamInfo saInvalidInfo = { EXC_PARAM_NONE, EXC_PARAMCONV_ORG, false };
199     return mpParamInfo ? *mpParamInfo : saInvalidInfo;
200 }
201 
202 bool XclExpFuncData::IsCalcOnlyParam() const
203 {
204     return mpParamInfo && (mpParamInfo->meValid == EXC_PARAM_CALCONLY);
205 }
206 
207 bool XclExpFuncData::IsExcelOnlyParam() const
208 {
209     return mpParamInfo && (mpParamInfo->meValid == EXC_PARAM_EXCELONLY);
210 }
211 
212 void XclExpFuncData::IncParamInfoIdx()
213 {
214     if( mpParamInfo )
215     {
216         // move pointer to next entry, if something explicit follows
217         if( (static_cast<size_t>(mpParamInfo - mrFuncInfo.mpParamInfos + 1) < EXC_FUNCINFO_PARAMINFO_COUNT) && (mpParamInfo[ 1 ].meValid != EXC_PARAM_NONE) )
218             ++mpParamInfo;
219         // if last parameter type is 'Excel-only' or 'Calc-only', do not repeat it
220         else if( IsExcelOnlyParam() || IsCalcOnlyParam() )
221             mpParamInfo = 0;
222         // otherwise: repeat last parameter class
223     }
224 }
225 
226 void XclExpFuncData::FinishParam( sal_uInt16 nTokPos )
227 {
228     // write token class conversion info for this parameter
229     const XclFuncParamInfo& rParamInfo = GetParamInfo();
230     mxOperands->AppendOperand( nTokPos, rParamInfo.meConv, rParamInfo.mbValType );
231     // move to next parameter info structure
232     IncParamInfoIdx();
233 }
234 
235 // compiler configuration -----------------------------------------------------
236 
237 /** Type of token class handling. */
238 enum XclExpFmlaClassType
239 {
240     EXC_CLASSTYPE_CELL,         /// Cell formula, shared formula.
241     EXC_CLASSTYPE_ARRAY,        /// Array formula, conditional formatting, data validation.
242     EXC_CLASSTYPE_NAME          /// Defined name, range list.
243 };
244 
245 /** Configuration data of the formula compiler. */
246 struct XclExpCompConfig
247 {
248     XclFormulaType      meType;         /// Type of the formula to be created.
249     XclExpFmlaClassType meClassType;    /// Token class handling type.
250     bool                mbLocalLinkMgr; /// True = local (per-sheet) link manager, false = global.
251     bool                mbFromCell;     /// True = Any kind of cell formula (cell, array, shared).
252     bool                mb3DRefOnly;    /// True = Only 3D references allowed (e.g. names).
253     bool                mbAllowArrays;  /// True = Allow inline arrays.
254 };
255 
256 /** The table containing configuration data for all formula types. */
257 static const XclExpCompConfig spConfigTable[] =
258 {
259     // formula type         token class type     lclLM  inCell 3dOnly allowArray
260     { EXC_FMLATYPE_CELL,    EXC_CLASSTYPE_CELL,  true,  true,  false, true  },
261     { EXC_FMLATYPE_SHARED,  EXC_CLASSTYPE_CELL,  true,  true,  false, true  },
262     { EXC_FMLATYPE_MATRIX,  EXC_CLASSTYPE_ARRAY, true,  true,  false, true  },
263     { EXC_FMLATYPE_CONDFMT, EXC_CLASSTYPE_ARRAY, true,  false, false, false },
264     { EXC_FMLATYPE_DATAVAL, EXC_CLASSTYPE_ARRAY, true,  false, false, false },
265     { EXC_FMLATYPE_NAME,    EXC_CLASSTYPE_NAME,  false, false, true,  true  },
266     { EXC_FMLATYPE_CHART,   EXC_CLASSTYPE_NAME,  true,  false, true,  true  },
267     { EXC_FMLATYPE_CONTROL, EXC_CLASSTYPE_NAME,  true,  false, false, false },
268     { EXC_FMLATYPE_WQUERY,  EXC_CLASSTYPE_NAME,  true,  false, true,  false },
269     { EXC_FMLATYPE_LISTVAL, EXC_CLASSTYPE_NAME,  true,  false, false, false }
270 };
271 
272 // ----------------------------------------------------------------------------
273 
274 /** Working data of the formula compiler. Used to push onto a stack for recursive calls. */
275 struct XclExpCompData
276 {
277     typedef ScfRef< ScTokenArray > ScTokenArrayRef;
278 
279     const XclExpCompConfig& mrCfg;          /// Configuration for current formula type.
280     ScTokenArrayRef     mxOwnScTokArr;      /// Own clone of a Calc token array.
281     XclTokenArrayIterator maTokArrIt;       /// Iterator in Calc token array.
282     XclExpLinkManager*  mpLinkMgr;          /// Link manager for current context (local/global).
283     XclExpRefLog*       mpRefLog;           /// Log for external references.
284     const ScAddress*    mpScBasePos;        /// Current cell position of the formula.
285 
286     ScfUInt8Vec         maTokVec;           /// Byte vector containing token data.
287     ScfUInt8Vec         maExtDataVec;       /// Byte vector containing extended data (arrays, stacked NLRs).
288     XclExpOperandListVector maOpListVec;    /// Formula structure, maps operators to their operands.
289     ScfUInt16Vec        maOpPosStack;       /// Stack with positions of operand tokens waiting for an operator.
290     bool                mbStopAtSep;        /// True = Stop subexpression creation at an ocSep token.
291     bool                mbVolatile;         /// True = Formula contains volatile function.
292     bool                mbOk;               /// Current state of the compiler.
293 
294     explicit            XclExpCompData( const XclExpCompConfig* pCfg );
295 };
296 
297 XclExpCompData::XclExpCompData( const XclExpCompConfig* pCfg ) :
298     mrCfg( pCfg ? *pCfg : spConfigTable[ 0 ] ),
299     mpLinkMgr( 0 ),
300     mpRefLog( 0 ),
301     mpScBasePos( 0 ),
302     mbStopAtSep( false ),
303     mbVolatile( false ),
304     mbOk( pCfg != 0 )
305 {
306     DBG_ASSERT( pCfg, "XclExpFmlaCompImpl::Init - unknown formula type" );
307 }
308 
309 } // namespace
310 
311 // ----------------------------------------------------------------------------
312 
313 /** Implementation class of the export formula compiler. */
314 class XclExpFmlaCompImpl : protected XclExpRoot, protected XclTokenArrayHelper
315 {
316 public:
317     explicit            XclExpFmlaCompImpl( const XclExpRoot& rRoot );
318 
319     /** Creates an Excel token array from the passed Calc token array. */
320     XclTokenArrayRef    CreateFormula(
321                             XclFormulaType eType, const ScTokenArray& rScTokArr,
322                             const ScAddress* pScBasePos = 0, XclExpRefLog* pRefLog = 0 );
323     /** Creates a single error token containing the passed error code. */
324     XclTokenArrayRef    CreateErrorFormula( sal_uInt8 nErrCode );
325     /** Creates a single token for a special cell reference. */
326     XclTokenArrayRef    CreateSpecialRefFormula( sal_uInt8 nTokenId, const XclAddress& rXclPos );
327     /** Creates a single tNameXR token for a reference to an external name. */
328     XclTokenArrayRef    CreateNameXFormula( sal_uInt16 nExtSheet, sal_uInt16 nExtName );
329 
330     /** Returns true, if the passed formula type allows 3D references only. */
331     bool                Is3DRefOnly( XclFormulaType eType ) const;
332 
333     // ------------------------------------------------------------------------
334 private:
335     const XclExpCompConfig* GetConfigForType( XclFormulaType eType ) const;
336     inline sal_uInt16   GetSize() const { return static_cast< sal_uInt16 >( mxData->maTokVec.size() ); }
337 
338     void                Init( XclFormulaType eType );
339     void                Init( XclFormulaType eType, const ScTokenArray& rScTokArr,
340                             const ScAddress* pScBasePos, XclExpRefLog* pRefLog );
341 
342     void                RecalcTokenClasses();
343     void                RecalcTokenClass( const XclExpTokenConvInfo& rConvInfo, XclFuncParamConv ePrevConv, XclExpClassConv ePrevClassConv, bool bWasRefClass );
344 
345     void                FinalizeFormula();
346     XclTokenArrayRef    CreateTokenArray();
347 
348     // compiler ---------------------------------------------------------------
349     // XclExpScToken: pass-by-value and return-by-value is intended
350 
351     const FormulaToken* GetNextRawToken();
352     const FormulaToken* PeekNextRawToken( bool bSkipSpaces ) const;
353 
354     bool                GetNextToken( XclExpScToken& rTokData );
355     XclExpScToken       GetNextToken();
356 
357     XclExpScToken       Expression( XclExpScToken aTokData, bool bInParentheses, bool bStopAtSep );
358     XclExpScToken       SkipExpression( XclExpScToken aTokData, bool bStopAtSep );
359 
360     XclExpScToken       OrTerm( XclExpScToken aTokData, bool bInParentheses );
361     XclExpScToken       AndTerm( XclExpScToken aTokData, bool bInParentheses );
362     XclExpScToken       CompareTerm( XclExpScToken aTokData, bool bInParentheses );
363     XclExpScToken       ConcatTerm( XclExpScToken aTokData, bool bInParentheses );
364     XclExpScToken       AddSubTerm( XclExpScToken aTokData, bool bInParentheses );
365     XclExpScToken       MulDivTerm( XclExpScToken aTokData, bool bInParentheses );
366     XclExpScToken       PowTerm( XclExpScToken aTokData, bool bInParentheses );
367     XclExpScToken       UnaryPostTerm( XclExpScToken aTokData, bool bInParentheses );
368     XclExpScToken       UnaryPreTerm( XclExpScToken aTokData, bool bInParentheses );
369     XclExpScToken       ListTerm( XclExpScToken aTokData, bool bInParentheses );
370     XclExpScToken       IntersectTerm( XclExpScToken aTokData, bool& rbHasRefOp );
371     XclExpScToken       RangeTerm( XclExpScToken aTokData, bool& rbHasRefOp );
372     XclExpScToken       Factor( XclExpScToken aTokData );
373 
374     // formula structure ------------------------------------------------------
375 
376     void                ProcessDouble( const XclExpScToken& rTokData );
377     void                ProcessString( const XclExpScToken& rTokData );
378     void                ProcessError( const XclExpScToken& rTokData );
379     void                ProcessMissing( const XclExpScToken& rTokData );
380     void                ProcessBad( const XclExpScToken& rTokData );
381     void                ProcessParentheses( const XclExpScToken& rTokData );
382     void                ProcessBoolean( const XclExpScToken& rTokData );
383     void                ProcessDdeLink( const XclExpScToken& rTokData );
384     void                ProcessExternal( const XclExpScToken& rTokData );
385     void                ProcessMatrix( const XclExpScToken& rTokData );
386 
387     void                ProcessFunction( const XclExpScToken& rTokData );
388     void                PrepareFunction( XclExpFuncData& rFuncData );
389     void                FinishFunction( XclExpFuncData& rFuncData, sal_uInt8 nCloseSpaces );
390     void                FinishIfFunction( XclExpFuncData& rFuncData );
391     void                FinishChooseFunction( XclExpFuncData& rFuncData );
392 
393     XclExpScToken       ProcessParam( XclExpScToken aTokData, XclExpFuncData& rFuncData );
394     void                PrepareParam( XclExpFuncData& rFuncData );
395     void                FinishParam( XclExpFuncData& rFuncData );
396     void                AppendDefaultParam( XclExpFuncData& rFuncData );
397     void                AppendTrailingParam( XclExpFuncData& rFuncData );
398 
399     // reference handling -----------------------------------------------------
400 
401     SCTAB               GetScTab( const ScSingleRefData& rRefData ) const;
402     bool                IsRef2D( const ScSingleRefData& rRefData ) const;
403     bool                IsRef2D( const ScComplexRefData& rRefData ) const;
404 
405     void                ConvertRefData( ScSingleRefData& rRefData, XclAddress& rXclPos,
406                             bool bNatLangRef, bool bTruncMaxCol, bool bTruncMaxRow ) const;
407     void                ConvertRefData( ScComplexRefData& rRefData, XclRange& rXclRange,
408                             bool bNatLangRef ) const;
409 
410     XclExpRefLogEntry*  GetNewRefLogEntry();
411     void                ProcessCellRef( const XclExpScToken& rTokData );
412     void                ProcessRangeRef( const XclExpScToken& rTokData );
413     void                ProcessExternalCellRef( const XclExpScToken& rTokData );
414     void                ProcessExternalRangeRef( const XclExpScToken& rTokData );
415     void                ProcessDefinedName( const XclExpScToken& rTokData );
416     void                ProcessExternalName( const XclExpScToken& rTokData );
417     void                ProcessDatabaseArea( const XclExpScToken& rTokData );
418 
419     // token vector -----------------------------------------------------------
420 
421     void                PushOperandPos( sal_uInt16 nTokPos );
422     void                PushOperatorPos( sal_uInt16 nTokPos, const XclExpOperandListRef& rxOperands );
423     sal_uInt16          PopOperandPos();
424 
425     void                Append( sal_uInt8 nData );
426     void                Append( sal_uInt8 nData, size_t nCount );
427     void                Append( sal_uInt16 nData );
428     void                Append( sal_uInt32 nData );
429     void                Append( double fData );
430     void                Append( const String& rString );
431 
432     void                AppendAddress( const XclAddress& rXclPos );
433     void                AppendRange( const XclRange& rXclRange );
434 
435     void                AppendSpaceToken( sal_uInt8 nType, sal_uInt8 nCount );
436 
437     void                AppendOperandTokenId( sal_uInt8 nTokenId, sal_uInt8 nSpaces = 0 );
438     void                AppendIntToken( sal_uInt16 nValue, sal_uInt8 nSpaces = 0 );
439     void                AppendNumToken( double fValue, sal_uInt8 nSpaces = 0 );
440     void                AppendBoolToken( bool bValue, sal_uInt8 nSpaces = 0 );
441     void                AppendErrorToken( sal_uInt8 nErrCode, sal_uInt8 nSpaces = 0 );
442     void                AppendMissingToken( sal_uInt8 nSpaces = 0 );
443     void                AppendNameToken( sal_uInt16 nNameIdx, sal_uInt8 nSpaces = 0 );
444     void                AppendMissingNameToken( const String& rName, sal_uInt8 nSpaces = 0 );
445     void                AppendNameXToken( sal_uInt16 nExtSheet, sal_uInt16 nExtName, sal_uInt8 nSpaces = 0 );
446     void                AppendMacroCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces = 0 );
447     void                AppendAddInCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces = 0 );
448     void                AppendEuroToolCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces = 0 );
449 
450     void                AppendOperatorTokenId( sal_uInt8 nTokenId, const XclExpOperandListRef& rxOperands, sal_uInt8 nSpaces = 0 );
451     void                AppendUnaryOperatorToken( sal_uInt8 nTokenId, sal_uInt8 nSpaces = 0 );
452     void                AppendBinaryOperatorToken( sal_uInt8 nTokenId, bool bValType, sal_uInt8 nSpaces = 0 );
453     void                AppendLogicalOperatorToken( sal_uInt16 nXclFuncIdx, sal_uInt8 nOpCount );
454     void                AppendFuncToken( const XclExpFuncData& rFuncData );
455 
456     void                AppendParenToken( sal_uInt8 nOpenSpaces = 0, sal_uInt8 nCloseSpaces = 0 );
457     void                AppendJumpToken( XclExpFuncData& rFuncData, sal_uInt8 nAttrType );
458 
459     void                InsertZeros( sal_uInt16 nInsertPos, sal_uInt16 nInsertSize );
460     void                Overwrite( sal_uInt16 nWriteToPos, sal_uInt16 nOffset );
461 
462     void                UpdateAttrGoto( sal_uInt16 nAttrPos );
463 
464     bool                IsSpaceToken( sal_uInt16 nPos ) const;
465     void                RemoveTrailingParen();
466 
467     void                AppendExt( sal_uInt8 nData );
468     void                AppendExt( sal_uInt8 nData, size_t nCount );
469     void                AppendExt( sal_uInt16 nData );
470     void                AppendExt( sal_uInt32 nData );
471     void                AppendExt( double fData );
472     void                AppendExt( const String& rString );
473 
474     // ------------------------------------------------------------------------
475 private:
476     typedef ::std::map< XclFormulaType, XclExpCompConfig >  XclExpCompConfigMap;
477     typedef ScfRef< XclExpCompData >                        XclExpCompDataRef;
478     typedef ::std::vector< XclExpCompDataRef >              XclExpCompDataVector;
479 
480     XclExpCompConfigMap maCfgMap;       /// Compiler configuration map for all formula types.
481     XclFunctionProvider maFuncProv;     /// Excel function data provider.
482     XclExpCompDataRef   mxData;         /// Working data for current formula.
483     XclExpCompDataVector maDataStack;   /// Stack for working data, when compiler is called recursively.
484     const XclBiff       meBiff;         /// Cached BIFF version to save GetBiff() calls.
485     const SCsCOL        mnMaxAbsCol;    /// Maximum column index.
486     const SCsROW        mnMaxAbsRow;    /// Maximum row index.
487     const SCsCOL        mnMaxScCol;     /// Maximum column index in Calc itself.
488     const SCsROW        mnMaxScRow;     /// Maximum row index in Calc itself.
489     const sal_uInt16    mnMaxColMask;   /// Mask to delete invalid bits in column fields.
490     const sal_uInt16    mnMaxRowMask;   /// Mask to delete invalid bits in row fields.
491 };
492 
493 // ----------------------------------------------------------------------------
494 
495 XclExpFmlaCompImpl::XclExpFmlaCompImpl( const XclExpRoot& rRoot ) :
496     XclExpRoot( rRoot ),
497     maFuncProv( rRoot ),
498     meBiff( rRoot.GetBiff() ),
499     mnMaxAbsCol( static_cast< SCsCOL >( rRoot.GetXclMaxPos().Col() ) ),
500     mnMaxAbsRow( static_cast< SCsROW >( rRoot.GetXclMaxPos().Row() ) ),
501     mnMaxScCol( static_cast< SCsCOL >( rRoot.GetScMaxPos().Col() ) ),
502     mnMaxScRow( static_cast< SCsROW >( rRoot.GetScMaxPos().Row() ) ),
503     mnMaxColMask( static_cast< sal_uInt16 >( rRoot.GetXclMaxPos().Col() ) ),
504     mnMaxRowMask( static_cast< sal_uInt16 >( rRoot.GetXclMaxPos().Row() ) )
505 {
506     // build the configuration map
507     for( const XclExpCompConfig* pEntry = spConfigTable; pEntry != STATIC_ARRAY_END( spConfigTable ); ++pEntry )
508         maCfgMap[ pEntry->meType ] = *pEntry;
509 }
510 
511 XclTokenArrayRef XclExpFmlaCompImpl::CreateFormula( XclFormulaType eType,
512         const ScTokenArray& rScTokArr, const ScAddress* pScBasePos, XclExpRefLog* pRefLog )
513 {
514     // initialize the compiler
515     Init( eType, rScTokArr, pScBasePos, pRefLog );
516 
517     // start compilation, if initialization didn't fail
518     if( mxData->mbOk )
519     {
520         XclExpScToken aTokData( GetNextToken() );
521         sal_uInt16 nScError = rScTokArr.GetCodeError();
522         if( (nScError != 0) && (!aTokData.Is() || (aTokData.GetOpCode() == ocStop)) )
523         {
524             // #i50253# convert simple ocStop token to error code formula (e.g. =#VALUE!)
525             AppendErrorToken( XclTools::GetXclErrorCode( nScError ), aTokData.mnSpaces );
526         }
527         else if( aTokData.Is() )
528         {
529             aTokData = Expression( aTokData, false, false );
530         }
531         else
532         {
533             DBG_ERRORFILE( "XclExpFmlaCompImpl::CreateFormula - empty token array" );
534             mxData->mbOk = false;
535         }
536 
537         if( mxData->mbOk )
538         {
539             // #i44907# auto-generated SUBTOTAL formula cells have trailing ocStop token
540             mxData->mbOk = !aTokData.Is() || (aTokData.GetOpCode() == ocStop);
541             DBG_ASSERT( mxData->mbOk, "XclExpFmlaCompImpl::CreateFormula - unknown garbage behind formula" );
542         }
543     }
544 
545     // finalize (add tAttrVolatile token, calculate all token classes)
546     RecalcTokenClasses();
547     FinalizeFormula();
548 
549     // leave recursive call, create and return the final token array
550     return CreateTokenArray();
551 }
552 
553 XclTokenArrayRef XclExpFmlaCompImpl::CreateErrorFormula( sal_uInt8 nErrCode )
554 {
555     Init( EXC_FMLATYPE_NAME );
556     AppendErrorToken( nErrCode );
557     return CreateTokenArray();
558 }
559 
560 XclTokenArrayRef XclExpFmlaCompImpl::CreateSpecialRefFormula( sal_uInt8 nTokenId, const XclAddress& rXclPos )
561 {
562     Init( EXC_FMLATYPE_NAME );
563     AppendOperandTokenId( nTokenId );
564     Append( rXclPos.mnRow );
565     Append( rXclPos.mnCol );    // do not use AppendAddress(), we always need 16-bit column here
566     return CreateTokenArray();
567 }
568 
569 XclTokenArrayRef XclExpFmlaCompImpl::CreateNameXFormula( sal_uInt16 nExtSheet, sal_uInt16 nExtName )
570 {
571     Init( EXC_FMLATYPE_NAME );
572     AppendNameXToken( nExtSheet, nExtName );
573     return CreateTokenArray();
574 }
575 
576 bool XclExpFmlaCompImpl::Is3DRefOnly( XclFormulaType eType ) const
577 {
578     const XclExpCompConfig* pCfg = GetConfigForType( eType );
579     return pCfg && pCfg->mb3DRefOnly;
580 }
581 
582 // private --------------------------------------------------------------------
583 
584 const XclExpCompConfig* XclExpFmlaCompImpl::GetConfigForType( XclFormulaType eType ) const
585 {
586     XclExpCompConfigMap::const_iterator aIt = maCfgMap.find( eType );
587     DBG_ASSERT( aIt != maCfgMap.end(), "XclExpFmlaCompImpl::GetConfigForType - unknown formula type" );
588     return (aIt == maCfgMap.end()) ? 0 : &aIt->second;
589 }
590 
591 void XclExpFmlaCompImpl::Init( XclFormulaType eType )
592 {
593     // compiler invoked recursively? - store old working data
594     if( mxData.get() )
595         maDataStack.push_back( mxData );
596     // new compiler working data structure
597     mxData.reset( new XclExpCompData( GetConfigForType( eType ) ) );
598 }
599 
600 void XclExpFmlaCompImpl::Init( XclFormulaType eType, const ScTokenArray& rScTokArr,
601         const ScAddress* pScBasePos, XclExpRefLog* pRefLog )
602 {
603     // common initialization
604     Init( eType );
605 
606     // special initialization
607     if( mxData->mbOk ) switch( mxData->mrCfg.meType )
608     {
609         case EXC_FMLATYPE_CELL:
610         case EXC_FMLATYPE_MATRIX:
611         case EXC_FMLATYPE_CHART:
612             mxData->mbOk = pScBasePos != 0;
613             DBG_ASSERT( mxData->mbOk, "XclExpFmlaCompImpl::Init - missing cell address" );
614             mxData->mpScBasePos = pScBasePos;
615         break;
616         case EXC_FMLATYPE_SHARED:
617             mxData->mbOk = pScBasePos != 0;
618             DBG_ASSERT( mxData->mbOk, "XclExpFmlaCompImpl::Init - missing cell address" );
619             // clone the passed token array, convert references relative to current cell position
620             mxData->mxOwnScTokArr.reset( rScTokArr.Clone() );
621             ScCompiler::MoveRelWrap( *mxData->mxOwnScTokArr, GetDocPtr(), *pScBasePos, MAXCOL, MAXROW );
622             // don't remember pScBasePos in mxData->mpScBasePos, shared formulas use real relative refs
623         break;
624         default:;
625     }
626 
627     if( mxData->mbOk )
628     {
629         // link manager to be used
630         mxData->mpLinkMgr = mxData->mrCfg.mbLocalLinkMgr ? &GetLocalLinkManager() : &GetGlobalLinkManager();
631 
632         // token array iterator (use cloned token array if present)
633         mxData->maTokArrIt.Init( mxData->mxOwnScTokArr.is() ? *mxData->mxOwnScTokArr : rScTokArr, false );
634         mxData->mpRefLog = pRefLog;
635     }
636 }
637 
638 void XclExpFmlaCompImpl::RecalcTokenClasses()
639 {
640     if( mxData->mbOk )
641     {
642         mxData->mbOk = mxData->maOpPosStack.size() == 1;
643         DBG_ASSERT( mxData->mbOk, "XclExpFmlaCompImpl::RecalcTokenClasses - position of root token expected on stack" );
644         if( mxData->mbOk )
645         {
646             /*  Cell and array formulas start with VAL conversion and VALTYPE
647                 parameter type, defined names start with ARR conversion and
648                 REFTYPE parameter type for the root token. */
649             XclExpOperandList aOperands;
650             bool bNameFmla = mxData->mrCfg.meClassType == EXC_CLASSTYPE_NAME;
651             XclFuncParamConv eParamConv = bNameFmla ? EXC_PARAMCONV_ARR : EXC_PARAMCONV_VAL;
652             XclExpClassConv eClassConv = bNameFmla ? EXC_CLASSCONV_ARR : EXC_CLASSCONV_VAL;
653             XclExpTokenConvInfo aConvInfo = { PopOperandPos(), eParamConv, !bNameFmla };
654             RecalcTokenClass( aConvInfo, eParamConv, eClassConv, bNameFmla );
655         }
656 
657         // clear operand vectors (calls to the expensive InsertZeros() may follow)
658         mxData->maOpListVec.clear();
659         mxData->maOpPosStack.clear();
660     }
661 }
662 
663 void XclExpFmlaCompImpl::RecalcTokenClass( const XclExpTokenConvInfo& rConvInfo,
664         XclFuncParamConv ePrevConv, XclExpClassConv ePrevClassConv, bool bWasRefClass )
665 {
666     DBG_ASSERT( rConvInfo.mnTokPos < GetSize(), "XclExpFmlaCompImpl::RecalcTokenClass - invalid token position" );
667     sal_uInt8& rnTokenId = mxData->maTokVec[ rConvInfo.mnTokPos ];
668     sal_uInt8 nTokClass = GetTokenClass( rnTokenId );
669 
670     // REF tokens in VALTYPE parameters behave like VAL tokens
671     if( rConvInfo.mbValType && (nTokClass == EXC_TOKCLASS_REF) )
672         ChangeTokenClass( rnTokenId, nTokClass = EXC_TOKCLASS_VAL );
673 
674     // replace RPO conversion of operator with parent conversion
675     XclFuncParamConv eConv = (rConvInfo.meConv == EXC_PARAMCONV_RPO) ? ePrevConv : rConvInfo.meConv;
676 
677     // find the effective token class conversion to be performed for this token
678     XclExpClassConv eClassConv = EXC_CLASSCONV_ORG;
679     switch( eConv )
680     {
681         case EXC_PARAMCONV_ORG:
682             // conversion is forced independent of parent conversion
683             eClassConv = EXC_CLASSCONV_ORG;
684         break;
685         case EXC_PARAMCONV_VAL:
686             // conversion is forced independent of parent conversion
687             eClassConv = EXC_CLASSCONV_VAL;
688         break;
689         case EXC_PARAMCONV_ARR:
690             // conversion is forced independent of parent conversion
691             eClassConv = EXC_CLASSCONV_ARR;
692         break;
693         case EXC_PARAMCONV_RPT:
694             switch( ePrevConv )
695             {
696                 case EXC_PARAMCONV_ORG:
697                 case EXC_PARAMCONV_VAL:
698                 case EXC_PARAMCONV_ARR:
699                     /*  If parent token has REF class (REF token in REFTYPE
700                         function parameter), then RPT does not repeat the
701                         previous explicit ORG or ARR conversion, but always
702                         falls back to VAL conversion. */
703                     eClassConv = bWasRefClass ? EXC_CLASSCONV_VAL : ePrevClassConv;
704                 break;
705                 case EXC_PARAMCONV_RPT:
706                     // nested RPT repeats the previous effective conversion
707                     eClassConv = ePrevClassConv;
708                 break;
709                 case EXC_PARAMCONV_RPX:
710                     /*  If parent token has REF class (REF token in REFTYPE
711                         function parameter), then RPX repeats the previous
712                         effective conversion (wich will be either ORG or ARR,
713                         but never VAL), otherwise falls back to ORG conversion. */
714                     eClassConv = bWasRefClass ? ePrevClassConv : EXC_CLASSCONV_ORG;
715                 break;
716                 case EXC_PARAMCONV_RPO: // does not occur
717                 break;
718             }
719         break;
720         case EXC_PARAMCONV_RPX:
721             /*  If current token still has REF class, set previous effective
722                 conversion as current conversion. This will not have an effect
723                 on the REF token but is needed for RPT parameters of this
724                 function that want to repeat this conversion type. If current
725                 token is VAL or ARR class, the previous ARR conversion will be
726                 repeated on the token, but VAL conversion will not. */
727             eClassConv = ((nTokClass == EXC_TOKCLASS_REF) || (ePrevClassConv == EXC_CLASSCONV_ARR)) ?
728                 ePrevClassConv : EXC_CLASSCONV_ORG;
729         break;
730         case EXC_PARAMCONV_RPO: // does not occur (see above)
731         break;
732     }
733 
734     // do the token class conversion
735     switch( eClassConv )
736     {
737         case EXC_CLASSCONV_ORG:
738             /*  Cell formulas: leave the current token class. Cell formulas
739                 are the only type of formulas where all tokens can keep
740                 their original token class.
741                 Array and defined name formulas: convert VAL to ARR. */
742             if( (mxData->mrCfg.meClassType != EXC_CLASSTYPE_CELL) && (nTokClass == EXC_TOKCLASS_VAL) )
743                 ChangeTokenClass( rnTokenId, nTokClass = EXC_TOKCLASS_ARR );
744         break;
745         case EXC_CLASSCONV_VAL:
746             // convert ARR to VAL
747             if( nTokClass == EXC_TOKCLASS_ARR )
748                 ChangeTokenClass( rnTokenId, nTokClass = EXC_TOKCLASS_VAL );
749         break;
750         case EXC_CLASSCONV_ARR:
751             // convert VAL to ARR
752             if( nTokClass == EXC_TOKCLASS_VAL )
753                 ChangeTokenClass( rnTokenId, nTokClass = EXC_TOKCLASS_ARR );
754         break;
755     }
756 
757     // do conversion for nested operands, if token is an operator or function
758     if( rConvInfo.mnTokPos < mxData->maOpListVec.size() )
759         if( const XclExpOperandList* pOperands = mxData->maOpListVec[ rConvInfo.mnTokPos ].get() )
760             for( XclExpOperandList::const_iterator aIt = pOperands->begin(), aEnd = pOperands->end(); aIt != aEnd; ++aIt )
761                 RecalcTokenClass( *aIt, eConv, eClassConv, nTokClass == EXC_TOKCLASS_REF );
762 }
763 
764 void XclExpFmlaCompImpl::FinalizeFormula()
765 {
766     if( mxData->mbOk )
767     {
768         // Volatile? Add a tAttrVolatile token at the beginning of the token array.
769         if( mxData->mbVolatile )
770         {
771             // tAttrSpace token can be extended with volatile flag
772             if( !IsSpaceToken( 0 ) )
773             {
774                 InsertZeros( 0, 4 );
775                 mxData->maTokVec[ 0 ] = EXC_TOKID_ATTR;
776             }
777             mxData->maTokVec[ 1 ] |= EXC_TOK_ATTR_VOLATILE;
778         }
779 
780         // Token array too long? -> error
781         mxData->mbOk = mxData->maTokVec.size() <= EXC_TOKARR_MAXLEN;
782     }
783 
784     if( !mxData->mbOk )
785     {
786         // Any unrecoverable error? -> Create a =#NA formula.
787         mxData->maTokVec.clear();
788         mxData->maExtDataVec.clear();
789         mxData->mbVolatile = false;
790         AppendErrorToken( EXC_ERR_NA );
791     }
792 }
793 
794 XclTokenArrayRef XclExpFmlaCompImpl::CreateTokenArray()
795 {
796     // create the Excel token array from working data before resetting mxData
797     DBG_ASSERT( mxData->mrCfg.mbAllowArrays || mxData->maExtDataVec.empty(), "XclExpFmlaCompImpl::CreateTokenArray - unexpected extended data" );
798     if( !mxData->mrCfg.mbAllowArrays )
799         mxData->maExtDataVec.clear();
800     XclTokenArrayRef xTokArr( new XclTokenArray( mxData->maTokVec, mxData->maExtDataVec, mxData->mbVolatile ) );
801     mxData.reset();
802 
803     // compiler invoked recursively? - restore old working data
804     if( !maDataStack.empty() )
805     {
806         mxData = maDataStack.back();
807         maDataStack.pop_back();
808     }
809 
810     return xTokArr;
811 }
812 
813 // compiler -------------------------------------------------------------------
814 
815 const FormulaToken* XclExpFmlaCompImpl::GetNextRawToken()
816 {
817     const FormulaToken* pScToken = mxData->maTokArrIt.Get();
818     ++mxData->maTokArrIt;
819     return pScToken;
820 }
821 
822 const FormulaToken* XclExpFmlaCompImpl::PeekNextRawToken( bool bSkipSpaces ) const
823 {
824     /*  Returns pointer to next raw token in the token array. The token array
825         iterator already points to the next token (A call to GetNextToken()
826         always increases the iterator), so this function just returns the token
827         the iterator points to. To skip space tokens, a copy of the iterator is
828         created and set to the passed skip-spaces mode. If spaces have to be
829         skipped, and the iterator currently points to a space token, the
830         constructor will move it to the next non-space token. */
831     XclTokenArrayIterator aTempIt( mxData->maTokArrIt, bSkipSpaces );
832     return aTempIt.Get();
833 }
834 
835 bool XclExpFmlaCompImpl::GetNextToken( XclExpScToken& rTokData )
836 {
837     rTokData.mpScToken = GetNextRawToken();
838     rTokData.mnSpaces = (rTokData.GetOpCode() == ocSpaces) ? rTokData.mpScToken->GetByte() : 0;
839     while( rTokData.GetOpCode() == ocSpaces )
840         rTokData.mpScToken = GetNextRawToken();
841     return rTokData.Is();
842 }
843 
844 XclExpScToken XclExpFmlaCompImpl::GetNextToken()
845 {
846     XclExpScToken aTokData;
847     GetNextToken( aTokData );
848     return aTokData;
849 }
850 
851 namespace {
852 
853 /** Returns the Excel token ID of a comparison operator or EXC_TOKID_NONE. */
854 inline sal_uInt8 lclGetCompareTokenId( OpCode eOpCode )
855 {
856     switch( eOpCode )
857     {
858         case ocLess:            return EXC_TOKID_LT;
859         case ocLessEqual:       return EXC_TOKID_LE;
860         case ocEqual:           return EXC_TOKID_EQ;
861         case ocGreaterEqual:    return EXC_TOKID_GE;
862         case ocGreater:         return EXC_TOKID_GT;
863         case ocNotEqual:        return EXC_TOKID_NE;
864         default:;
865     }
866     return EXC_TOKID_NONE;
867 }
868 
869 /** Returns the Excel token ID of a string concatenation operator or EXC_TOKID_NONE. */
870 inline sal_uInt8 lclGetConcatTokenId( OpCode eOpCode )
871 {
872     return (eOpCode == ocAmpersand) ? EXC_TOKID_CONCAT : EXC_TOKID_NONE;
873 }
874 
875 /** Returns the Excel token ID of an addition/subtraction operator or EXC_TOKID_NONE. */
876 inline sal_uInt8 lclGetAddSubTokenId( OpCode eOpCode )
877 {
878     switch( eOpCode )
879     {
880         case ocAdd:     return EXC_TOKID_ADD;
881         case ocSub:     return EXC_TOKID_SUB;
882         default:;
883     }
884     return EXC_TOKID_NONE;
885 }
886 
887 /** Returns the Excel token ID of a multiplication/division operator or EXC_TOKID_NONE. */
888 inline sal_uInt8 lclGetMulDivTokenId( OpCode eOpCode )
889 {
890     switch( eOpCode )
891     {
892         case ocMul:     return EXC_TOKID_MUL;
893         case ocDiv:     return EXC_TOKID_DIV;
894         default:;
895     }
896     return EXC_TOKID_NONE;
897 }
898 
899 /** Returns the Excel token ID of a power operator or EXC_TOKID_NONE. */
900 inline sal_uInt8 lclGetPowTokenId( OpCode eOpCode )
901 {
902     return (eOpCode == ocPow) ? EXC_TOKID_POWER : EXC_TOKID_NONE;
903 }
904 
905 /** Returns the Excel token ID of a trailing unary operator or EXC_TOKID_NONE. */
906 inline sal_uInt8 lclGetUnaryPostTokenId( OpCode eOpCode )
907 {
908     return (eOpCode == ocPercentSign) ? EXC_TOKID_PERCENT : EXC_TOKID_NONE;
909 }
910 
911 /** Returns the Excel token ID of a leading unary operator or EXC_TOKID_NONE. */
912 inline sal_uInt8 lclGetUnaryPreTokenId( OpCode eOpCode )
913 {
914     switch( eOpCode )
915     {
916         case ocAdd:     return EXC_TOKID_UPLUS;     // +(1)
917         case ocNeg:     return EXC_TOKID_UMINUS;    // NEG(1)
918         case ocNegSub:  return EXC_TOKID_UMINUS;    // -(1)
919         default:;
920     }
921     return EXC_TOKID_NONE;
922 }
923 
924 /** Returns the Excel token ID of a reference list operator or EXC_TOKID_NONE. */
925 inline sal_uInt8 lclGetListTokenId( OpCode eOpCode, bool bStopAtSep )
926 {
927     return ((eOpCode == ocUnion) || (!bStopAtSep && (eOpCode == ocSep))) ? EXC_TOKID_LIST : EXC_TOKID_NONE;
928 }
929 
930 /** Returns the Excel token ID of a reference intersection operator or EXC_TOKID_NONE. */
931 inline sal_uInt8 lclGetIntersectTokenId( OpCode eOpCode )
932 {
933     return (eOpCode == ocIntersect) ? EXC_TOKID_ISECT : EXC_TOKID_NONE;
934 }
935 
936 /** Returns the Excel token ID of a reference range operator or EXC_TOKID_NONE. */
937 inline sal_uInt8 lclGetRangeTokenId( OpCode eOpCode )
938 {
939     return (eOpCode == ocRange) ? EXC_TOKID_RANGE : EXC_TOKID_NONE;
940 }
941 
942 } // namespace
943 
944 XclExpScToken XclExpFmlaCompImpl::Expression( XclExpScToken aTokData, bool bInParentheses, bool bStopAtSep )
945 {
946     if( mxData->mbOk && aTokData.Is() )
947     {
948         // remember old stop-at-ocSep mode, restored below
949         bool bOldStopAtSep = mxData->mbStopAtSep;
950         mxData->mbStopAtSep = bStopAtSep;
951         // start compilation of the subexpression
952         aTokData = OrTerm( aTokData, bInParentheses );
953         // restore old stop-at-ocSep mode
954         mxData->mbStopAtSep = bOldStopAtSep;
955     }
956     return aTokData;
957 }
958 
959 XclExpScToken XclExpFmlaCompImpl::SkipExpression( XclExpScToken aTokData, bool bStopAtSep )
960 {
961     while( mxData->mbOk && aTokData.Is() && (aTokData.GetOpCode() != ocClose) && (!bStopAtSep || (aTokData.GetOpCode() != ocSep)) )
962     {
963         if( aTokData.GetOpCode() == ocOpen )
964         {
965             aTokData = SkipExpression( GetNextToken(), false );
966             if( mxData->mbOk ) mxData->mbOk = aTokData.GetOpCode() == ocClose;
967         }
968         aTokData = GetNextToken();
969     }
970     return aTokData;
971 }
972 
973 XclExpScToken XclExpFmlaCompImpl::OrTerm( XclExpScToken aTokData, bool bInParentheses )
974 {
975     aTokData = AndTerm( aTokData, bInParentheses );
976     sal_uInt8 nParamCount = 1;
977     while( mxData->mbOk && (aTokData.GetOpCode() == ocOr) )
978     {
979         RemoveTrailingParen();
980         aTokData = AndTerm( GetNextToken(), bInParentheses );
981         RemoveTrailingParen();
982         ++nParamCount;
983         if( mxData->mbOk ) mxData->mbOk = nParamCount <= EXC_FUNC_MAXPARAM;
984     }
985     if( mxData->mbOk && (nParamCount > 1) )
986         AppendLogicalOperatorToken( EXC_FUNCID_OR, nParamCount );
987     return aTokData;
988 }
989 
990 XclExpScToken XclExpFmlaCompImpl::AndTerm( XclExpScToken aTokData, bool bInParentheses )
991 {
992     aTokData = CompareTerm( aTokData, bInParentheses );
993     sal_uInt8 nParamCount = 1;
994     while( mxData->mbOk && (aTokData.GetOpCode() == ocAnd) )
995     {
996         RemoveTrailingParen();
997         aTokData = CompareTerm( GetNextToken(), bInParentheses );
998         RemoveTrailingParen();
999         ++nParamCount;
1000         if( mxData->mbOk ) mxData->mbOk = nParamCount <= EXC_FUNC_MAXPARAM;
1001     }
1002     if( mxData->mbOk && (nParamCount > 1) )
1003         AppendLogicalOperatorToken( EXC_FUNCID_AND, nParamCount );
1004     return aTokData;
1005 }
1006 
1007 XclExpScToken XclExpFmlaCompImpl::CompareTerm( XclExpScToken aTokData, bool bInParentheses )
1008 {
1009     aTokData = ConcatTerm( aTokData, bInParentheses );
1010     sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
1011     while( mxData->mbOk && ((nOpTokenId = lclGetCompareTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
1012     {
1013         sal_uInt8 nSpaces = aTokData.mnSpaces;
1014         aTokData = ConcatTerm( GetNextToken(), bInParentheses );
1015         AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
1016     }
1017     return aTokData;
1018 }
1019 
1020 XclExpScToken XclExpFmlaCompImpl::ConcatTerm( XclExpScToken aTokData, bool bInParentheses )
1021 {
1022     aTokData = AddSubTerm( aTokData, bInParentheses );
1023     sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
1024     while( mxData->mbOk && ((nOpTokenId = lclGetConcatTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
1025     {
1026         sal_uInt8 nSpaces = aTokData.mnSpaces;
1027         aTokData = AddSubTerm( GetNextToken(), bInParentheses );
1028         AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
1029     }
1030     return aTokData;
1031 }
1032 
1033 XclExpScToken XclExpFmlaCompImpl::AddSubTerm( XclExpScToken aTokData, bool bInParentheses )
1034 {
1035     aTokData = MulDivTerm( aTokData, bInParentheses );
1036     sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
1037     while( mxData->mbOk && ((nOpTokenId = lclGetAddSubTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
1038     {
1039         sal_uInt8 nSpaces = aTokData.mnSpaces;
1040         aTokData = MulDivTerm( GetNextToken(), bInParentheses );
1041         AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
1042     }
1043     return aTokData;
1044 }
1045 
1046 XclExpScToken XclExpFmlaCompImpl::MulDivTerm( XclExpScToken aTokData, bool bInParentheses )
1047 {
1048     aTokData = PowTerm( aTokData, bInParentheses );
1049     sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
1050     while( mxData->mbOk && ((nOpTokenId = lclGetMulDivTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
1051     {
1052         sal_uInt8 nSpaces = aTokData.mnSpaces;
1053         aTokData = PowTerm( GetNextToken(), bInParentheses );
1054         AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
1055     }
1056     return aTokData;
1057 }
1058 
1059 XclExpScToken XclExpFmlaCompImpl::PowTerm( XclExpScToken aTokData, bool bInParentheses )
1060 {
1061     aTokData = UnaryPostTerm( aTokData, bInParentheses );
1062     sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
1063     while( mxData->mbOk && ((nOpTokenId = lclGetPowTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
1064     {
1065         sal_uInt8 nSpaces = aTokData.mnSpaces;
1066         aTokData = UnaryPostTerm( GetNextToken(), bInParentheses );
1067         AppendBinaryOperatorToken( nOpTokenId, true, nSpaces );
1068     }
1069     return aTokData;
1070 }
1071 
1072 XclExpScToken XclExpFmlaCompImpl::UnaryPostTerm( XclExpScToken aTokData, bool bInParentheses )
1073 {
1074     aTokData = UnaryPreTerm( aTokData, bInParentheses );
1075     sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
1076     while( mxData->mbOk && ((nOpTokenId = lclGetUnaryPostTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
1077     {
1078         AppendUnaryOperatorToken( nOpTokenId, aTokData.mnSpaces );
1079         GetNextToken( aTokData );
1080     }
1081     return aTokData;
1082 }
1083 
1084 XclExpScToken XclExpFmlaCompImpl::UnaryPreTerm( XclExpScToken aTokData, bool bInParentheses )
1085 {
1086     sal_uInt8 nOpTokenId = mxData->mbOk ? lclGetUnaryPreTokenId( aTokData.GetOpCode() ) : EXC_TOKID_NONE;
1087     if( nOpTokenId != EXC_TOKID_NONE )
1088     {
1089         sal_uInt8 nSpaces = aTokData.mnSpaces;
1090         aTokData = UnaryPreTerm( GetNextToken(), bInParentheses );
1091         AppendUnaryOperatorToken( nOpTokenId, nSpaces );
1092     }
1093     else
1094     {
1095         aTokData = ListTerm( aTokData, bInParentheses );
1096     }
1097     return aTokData;
1098 }
1099 
1100 XclExpScToken XclExpFmlaCompImpl::ListTerm( XclExpScToken aTokData, bool bInParentheses )
1101 {
1102     sal_uInt16 nSubExprPos = GetSize();
1103     bool bHasAnyRefOp = false;
1104     bool bHasListOp = false;
1105     aTokData = IntersectTerm( aTokData, bHasAnyRefOp );
1106     sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
1107     while( mxData->mbOk && ((nOpTokenId = lclGetListTokenId( aTokData.GetOpCode(), mxData->mbStopAtSep )) != EXC_TOKID_NONE) )
1108     {
1109         sal_uInt8 nSpaces = aTokData.mnSpaces;
1110         aTokData = IntersectTerm( GetNextToken(), bHasAnyRefOp );
1111         AppendBinaryOperatorToken( nOpTokenId, false, nSpaces );
1112         bHasAnyRefOp = bHasListOp = true;
1113     }
1114     if( bHasAnyRefOp )
1115     {
1116         // add a tMemFunc token enclosing the entire reference subexpression
1117         sal_uInt16 nSubExprSize = GetSize() - nSubExprPos;
1118         InsertZeros( nSubExprPos, 3 );
1119         mxData->maTokVec[ nSubExprPos ] = GetTokenId( EXC_TOKID_MEMFUNC, EXC_TOKCLASS_REF );
1120         Overwrite( nSubExprPos + 1, nSubExprSize );
1121         // update the operand/operator stack (set the list expression as operand of the tMemFunc)
1122         XclExpOperandListRef xOperands( new XclExpOperandList );
1123         xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_VAL, false );
1124         PushOperatorPos( nSubExprPos, xOperands );
1125     }
1126     // #i86439# enclose list operator into parentheses, e.g. Calc's =AREAS(A1~A2) to Excel's =AREAS((A1;A2))
1127     if( bHasListOp && !bInParentheses )
1128         AppendParenToken();
1129     return aTokData;
1130 }
1131 
1132 XclExpScToken XclExpFmlaCompImpl::IntersectTerm( XclExpScToken aTokData, bool& rbHasRefOp )
1133 {
1134     aTokData = RangeTerm( aTokData, rbHasRefOp );
1135     sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
1136     while( mxData->mbOk && ((nOpTokenId = lclGetIntersectTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
1137     {
1138         sal_uInt8 nSpaces = aTokData.mnSpaces;
1139         aTokData = RangeTerm( GetNextToken(), rbHasRefOp );
1140         AppendBinaryOperatorToken( nOpTokenId, false, nSpaces );
1141         rbHasRefOp = true;
1142     }
1143     return aTokData;
1144 }
1145 
1146 XclExpScToken XclExpFmlaCompImpl::RangeTerm( XclExpScToken aTokData, bool& rbHasRefOp )
1147 {
1148     aTokData = Factor( aTokData );
1149     sal_uInt8 nOpTokenId = EXC_TOKID_NONE;
1150     while( mxData->mbOk && ((nOpTokenId = lclGetRangeTokenId( aTokData.GetOpCode() )) != EXC_TOKID_NONE) )
1151     {
1152         sal_uInt8 nSpaces = aTokData.mnSpaces;
1153         aTokData = Factor( GetNextToken() );
1154         AppendBinaryOperatorToken( nOpTokenId, false, nSpaces );
1155         rbHasRefOp = true;
1156     }
1157     return aTokData;
1158 }
1159 
1160 XclExpScToken XclExpFmlaCompImpl::Factor( XclExpScToken aTokData )
1161 {
1162     if( !mxData->mbOk || !aTokData.Is() ) return XclExpScToken();
1163 
1164     switch( aTokData.GetType() )
1165     {
1166         case svUnknown:             mxData->mbOk = false;                   break;
1167         case svDouble:              ProcessDouble( aTokData );              break;
1168         case svString:              ProcessString( aTokData );              break;
1169 #if 0   // erAck
1170         case svError:               ProcessError( aTokData );               break;
1171 #endif
1172         case svSingleRef:           ProcessCellRef( aTokData );             break;
1173         case svDoubleRef:           ProcessRangeRef( aTokData );            break;
1174         case svExternalSingleRef:   ProcessExternalCellRef( aTokData );     break;
1175         case svExternalDoubleRef:   ProcessExternalRangeRef( aTokData );    break;
1176         case svExternalName:        ProcessExternalName( aTokData );        break;
1177         case svMatrix:              ProcessMatrix( aTokData );              break;
1178         case svExternal:            ProcessExternal( aTokData );            break;
1179 
1180         default: switch( aTokData.GetOpCode() )
1181         {
1182             case ocNone:        /* do nothing */                    break;
1183             case ocMissing:     ProcessMissing( aTokData );         break;
1184             case ocBad:         ProcessBad( aTokData );             break;
1185             case ocOpen:        ProcessParentheses( aTokData );     break;
1186             case ocName:        ProcessDefinedName( aTokData );     break;
1187             case ocDBArea:      ProcessDatabaseArea( aTokData );    break;
1188             case ocFalse:
1189             case ocTrue:        ProcessBoolean( aTokData );         break;
1190             case ocDde:         ProcessDdeLink( aTokData );         break;
1191             default:            ProcessFunction( aTokData );
1192         }
1193     }
1194 
1195     return GetNextToken();
1196 }
1197 
1198 // formula structure ----------------------------------------------------------
1199 
1200 void XclExpFmlaCompImpl::ProcessDouble( const XclExpScToken& rTokData )
1201 {
1202     double fValue = rTokData.mpScToken->GetDouble();
1203     double fInt;
1204     double fFrac = modf( fValue, &fInt );
1205     if( (fFrac == 0.0) && (0.0 <= fInt) && (fInt <= 65535.0) )
1206         AppendIntToken( static_cast< sal_uInt16 >( fInt ), rTokData.mnSpaces );
1207     else
1208         AppendNumToken( fValue, rTokData.mnSpaces );
1209 }
1210 
1211 void XclExpFmlaCompImpl::ProcessString( const XclExpScToken& rTokData )
1212 {
1213     AppendOperandTokenId( EXC_TOKID_STR, rTokData.mnSpaces );
1214     Append( rTokData.mpScToken->GetString() );
1215 }
1216 
1217 void XclExpFmlaCompImpl::ProcessError( const XclExpScToken& rTokData )
1218 {
1219 #if 0   // erAck
1220     AppendErrorToken( XclTools::GetXclErrorCode( rTokData.mpScToken->GetError() ), rTokData.mnSpaces );
1221 #else
1222     (void)rTokData; // compiler warning
1223 #endif
1224 }
1225 
1226 void XclExpFmlaCompImpl::ProcessMissing( const XclExpScToken& rTokData )
1227 {
1228     AppendMissingToken( rTokData.mnSpaces );
1229 }
1230 
1231 void XclExpFmlaCompImpl::ProcessBad( const XclExpScToken& rTokData )
1232 {
1233     AppendErrorToken( EXC_ERR_NA, rTokData.mnSpaces );
1234 }
1235 
1236 void XclExpFmlaCompImpl::ProcessParentheses( const XclExpScToken& rTokData )
1237 {
1238     XclExpScToken aTokData = Expression( GetNextToken(), true, false );
1239     mxData->mbOk = aTokData.GetOpCode() == ocClose;
1240     AppendParenToken( rTokData.mnSpaces, aTokData.mnSpaces );
1241 }
1242 
1243 void XclExpFmlaCompImpl::ProcessBoolean( const XclExpScToken& rTokData )
1244 {
1245     mxData->mbOk = GetNextToken().GetOpCode() == ocOpen;
1246     if( mxData->mbOk ) mxData->mbOk = GetNextToken().GetOpCode() == ocClose;
1247     if( mxData->mbOk )
1248         AppendBoolToken( rTokData.GetOpCode() == ocTrue, rTokData.mnSpaces );
1249 }
1250 
1251 namespace {
1252 
1253 inline bool lclGetTokenString( String& rString, const XclExpScToken& rTokData )
1254 {
1255     bool bIsStr = (rTokData.GetType() == svString) && (rTokData.GetOpCode() == ocPush);
1256     if( bIsStr )
1257         rString = rTokData.mpScToken->GetString();
1258     return bIsStr;
1259 }
1260 
1261 } // namespace
1262 
1263 void XclExpFmlaCompImpl::ProcessDdeLink( const XclExpScToken& rTokData )
1264 {
1265     String aApplic, aTopic, aItem;
1266 
1267     mxData->mbOk = GetNextToken().GetOpCode() == ocOpen;
1268     if( mxData->mbOk ) mxData->mbOk = lclGetTokenString( aApplic, GetNextToken() );
1269     if( mxData->mbOk ) mxData->mbOk = GetNextToken().GetOpCode() == ocSep;
1270     if( mxData->mbOk ) mxData->mbOk = lclGetTokenString( aTopic, GetNextToken() );
1271     if( mxData->mbOk ) mxData->mbOk = GetNextToken().GetOpCode() == ocSep;
1272     if( mxData->mbOk ) mxData->mbOk = lclGetTokenString( aItem, GetNextToken() );
1273     if( mxData->mbOk ) mxData->mbOk = GetNextToken().GetOpCode() == ocClose;
1274     if( mxData->mbOk ) mxData->mbOk = aApplic.Len() && aTopic.Len() && aItem.Len();
1275     if( mxData->mbOk )
1276     {
1277         sal_uInt16 nExtSheet, nExtName;
1278         if( mxData->mpLinkMgr && mxData->mpLinkMgr->InsertDde( nExtSheet, nExtName, aApplic, aTopic, aItem ) )
1279             AppendNameXToken( nExtSheet, nExtName, rTokData.mnSpaces );
1280         else
1281             AppendErrorToken( EXC_ERR_NA, rTokData.mnSpaces );
1282     }
1283 }
1284 
1285 void XclExpFmlaCompImpl::ProcessExternal( const XclExpScToken& rTokData )
1286 {
1287     /*  #i47228# Excel import generates svExternal/ocMacro tokens for invalid
1288         names and for external/invalid function calls. This function looks for
1289         the next token in the token array. If it is an opening parenthesis, the
1290         token is processed as external function call, otherwise as undefined name. */
1291     const FormulaToken* pNextScToken = PeekNextRawToken( true );
1292     if( !pNextScToken || (pNextScToken->GetOpCode() != ocOpen) )
1293         AppendMissingNameToken( rTokData.mpScToken->GetExternal(), rTokData.mnSpaces );
1294     else
1295         ProcessFunction( rTokData );
1296 }
1297 
1298 void XclExpFmlaCompImpl::ProcessMatrix( const XclExpScToken& rTokData )
1299 {
1300     const ScMatrix* pMatrix = static_cast< const ScToken* >( rTokData.mpScToken )->GetMatrix();
1301     if( pMatrix && mxData->mrCfg.mbAllowArrays )
1302     {
1303         SCSIZE nScCols, nScRows;
1304         pMatrix->GetDimensions( nScCols, nScRows );
1305         DBG_ASSERT( (nScCols > 0) && (nScRows > 0), "XclExpFmlaCompImpl::ProcessMatrix - invalid matrix size" );
1306         sal_uInt16 nCols = ::limit_cast< sal_uInt16 >( nScCols, 0, 256 );
1307         sal_uInt16 nRows = ::limit_cast< sal_uInt16 >( nScRows, 0, 1024 );
1308 
1309         // create the tArray token
1310         AppendOperandTokenId( GetTokenId( EXC_TOKID_ARRAY, EXC_TOKCLASS_ARR ), rTokData.mnSpaces );
1311         Append( static_cast< sal_uInt8 >( (meBiff == EXC_BIFF8) ? (nCols - 1) : nCols ) );
1312         Append( static_cast< sal_uInt16 >( (meBiff == EXC_BIFF8) ? (nRows - 1) : nRows ) );
1313         Append( static_cast< sal_uInt32 >( 0 ) );
1314 
1315         // create the extended data containing the array values
1316         AppendExt( static_cast< sal_uInt8 >( (meBiff == EXC_BIFF8) ? (nCols - 1) : nCols ) );
1317         AppendExt( static_cast< sal_uInt16 >( (meBiff == EXC_BIFF8) ? (nRows - 1) : nRows ) );
1318         for( SCSIZE nScRow = 0; nScRow < nScRows; ++nScRow )
1319         {
1320             for( SCSIZE nScCol = 0; nScCol < nScCols; ++nScCol )
1321             {
1322                 ScMatValType nType;
1323                 const ScMatrixValue* pMatVal = pMatrix->Get( nScCol, nScRow, nType );
1324                 DBG_ASSERT( pMatVal, "XclExpFmlaCompImpl::ProcessMatrix - missing matrix value" );
1325                 if( ScMatrix::IsValueType( nType ) )    // value, boolean, or error
1326                 {
1327                     if( ScMatrix::IsBooleanType( nType ) )
1328                     {
1329                         AppendExt( EXC_CACHEDVAL_BOOL );
1330                         AppendExt( static_cast< sal_uInt8 >( pMatVal->GetBoolean() ? 1 : 0 ) );
1331                         AppendExt( 0, 7 );
1332                     }
1333                     else if( sal_uInt16 nErr = pMatVal->GetError() )
1334                     {
1335                         AppendExt( EXC_CACHEDVAL_ERROR );
1336                         AppendExt( XclTools::GetXclErrorCode( nErr ) );
1337                         AppendExt( 0, 7 );
1338                     }
1339                     else
1340                     {
1341                         AppendExt( EXC_CACHEDVAL_DOUBLE );
1342                         AppendExt( pMatVal->fVal );
1343                     }
1344                 }
1345                 else    // string or empty
1346                 {
1347                     const String& rStr = pMatVal->GetString();
1348                     if( rStr.Len() == 0 )
1349                     {
1350                         AppendExt( EXC_CACHEDVAL_EMPTY );
1351                         AppendExt( 0, 8 );
1352                     }
1353                     else
1354                     {
1355                         AppendExt( EXC_CACHEDVAL_STRING );
1356                         AppendExt( rStr );
1357                     }
1358                 }
1359             }
1360         }
1361     }
1362     else
1363     {
1364         // array in places that do not allow it (cond fmts, data validation)
1365         AppendErrorToken( EXC_ERR_NA, rTokData.mnSpaces );
1366     }
1367 }
1368 
1369 void XclExpFmlaCompImpl::ProcessFunction( const XclExpScToken& rTokData )
1370 {
1371     OpCode eOpCode = rTokData.GetOpCode();
1372     const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromOpCode( eOpCode );
1373 
1374     XclExpExtFuncData aExtFuncData;
1375 
1376     // no exportable function found - try to create an external macro call
1377     if( !pFuncInfo && (eOpCode >= SC_OPCODE_START_NO_PAR) )
1378     {
1379         const String& rFuncName = ScCompiler::GetNativeSymbol( eOpCode );
1380         if( rFuncName.Len() )
1381         {
1382             aExtFuncData.Set( rFuncName, true, false );
1383             pFuncInfo = maFuncProv.GetFuncInfoFromOpCode( ocMacro );
1384         }
1385     }
1386 
1387     mxData->mbOk = pFuncInfo != 0;
1388     if( !mxData->mbOk ) return;
1389 
1390     // functions simulated by a macro call in file format
1391     if( pFuncInfo->IsMacroFunc() )
1392         aExtFuncData.Set( pFuncInfo->GetMacroFuncName(), false, true );
1393 
1394     XclExpFuncData aFuncData( rTokData, *pFuncInfo, aExtFuncData );
1395     XclExpScToken aTokData;
1396 
1397     // preparations for special functions, before function processing starts
1398     PrepareFunction( aFuncData );
1399 
1400     enum { STATE_START, STATE_OPEN, STATE_PARAM, STATE_SEP, STATE_CLOSE, STATE_END }
1401         eState = STATE_START;
1402     while( eState != STATE_END ) switch( eState )
1403     {
1404         case STATE_START:
1405             mxData->mbOk = GetNextToken( aTokData ) && (aTokData.GetOpCode() == ocOpen);
1406             eState = mxData->mbOk ? STATE_OPEN : STATE_END;
1407         break;
1408         case STATE_OPEN:
1409             mxData->mbOk = GetNextToken( aTokData );
1410             eState = mxData->mbOk ? ((aTokData.GetOpCode() == ocClose) ? STATE_CLOSE : STATE_PARAM) : STATE_END;
1411         break;
1412         case STATE_PARAM:
1413             aTokData = ProcessParam( aTokData, aFuncData );
1414             switch( aTokData.GetOpCode() )
1415             {
1416                 case ocSep:     eState = STATE_SEP;                 break;
1417                 case ocClose:   eState = STATE_CLOSE;               break;
1418                 default:        mxData->mbOk = false;
1419             }
1420             if( !mxData->mbOk ) eState = STATE_END;
1421         break;
1422         case STATE_SEP:
1423             mxData->mbOk = (aFuncData.GetParamCount() < EXC_FUNC_MAXPARAM) && GetNextToken( aTokData );
1424             eState = mxData->mbOk ? STATE_PARAM : STATE_END;
1425         break;
1426         case STATE_CLOSE:
1427             FinishFunction( aFuncData, aTokData.mnSpaces );
1428             eState = STATE_END;
1429         break;
1430         default:;
1431     }
1432 }
1433 
1434 void XclExpFmlaCompImpl::PrepareFunction( XclExpFuncData& rFuncData )
1435 {
1436     switch( rFuncData.GetOpCode() )
1437     {
1438         case ocCosecant:                // simulate CSC(x) by (1/SIN(x))
1439         case ocSecant:                  // simulate SEC(x) by (1/COS(x))
1440         case ocCot:                     // simulate COT(x) by (1/TAN(x))
1441         case ocCosecantHyp:             // simulate CSCH(x) by (1/SINH(x))
1442         case ocSecantHyp:               // simulate SECH(x) by (1/COSH(x))
1443         case ocCotHyp:                  // simulate COTH(x) by (1/TANH(x))
1444             AppendIntToken( 1 );
1445         break;
1446         case ocArcCot:                  // simulate ACOT(x) by (PI/2-ATAN(x))
1447             AppendNumToken( F_PI2 );
1448         break;
1449         default:;
1450     }
1451 }
1452 
1453 void XclExpFmlaCompImpl::FinishFunction( XclExpFuncData& rFuncData, sal_uInt8 nCloseSpaces )
1454 {
1455     // append missing parameters required in Excel, may modify param count
1456     AppendTrailingParam( rFuncData );
1457 
1458     // check if parameter count fits into the limits of the function
1459     sal_uInt8 nParamCount = rFuncData.GetParamCount();
1460     if( (rFuncData.GetMinParamCount() <= nParamCount) && (nParamCount <= rFuncData.GetMaxParamCount()) )
1461     {
1462         // first put the tAttrSpace tokens, they must not be included in tAttrGoto handling
1463         AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP_CLOSE, nCloseSpaces );
1464         AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP, rFuncData.GetSpaces() );
1465 
1466         // add tAttrGoto tokens for IF or CHOOSE functions
1467         switch( rFuncData.GetOpCode() )
1468         {
1469             case ocIf:
1470             case ocChose:
1471                 AppendJumpToken( rFuncData, EXC_TOK_ATTR_GOTO );
1472             break;
1473             default:;
1474         }
1475 
1476         // put the tFunc or tFuncVar token (or another special token, e.g. tAttrSum)
1477         AppendFuncToken( rFuncData );
1478 
1479         // update volatile flag - is set if at least one used function is volatile
1480         mxData->mbVolatile |= rFuncData.IsVolatile();
1481 
1482         // update jump tokens for specific functions, add additional tokens
1483         switch( rFuncData.GetOpCode() )
1484         {
1485             case ocIf:
1486                 FinishIfFunction( rFuncData );
1487             break;
1488             case ocChose:
1489                 FinishChooseFunction( rFuncData );
1490             break;
1491 
1492             case ocCosecant:                // simulate CSC(x) by (1/SIN(x))
1493             case ocSecant:                  // simulate SEC(x) by (1/COS(x))
1494             case ocCot:                     // simulate COT(x) by (1/TAN(x))
1495             case ocCosecantHyp:             // simulate CSCH(x) by (1/SINH(x))
1496             case ocSecantHyp:               // simulate SECH(x) by (1/COSH(x))
1497             case ocCotHyp:                  // simulate COTH(x) by (1/TANH(x))
1498                 AppendBinaryOperatorToken( EXC_TOKID_DIV, true );
1499                 AppendParenToken();
1500             break;
1501             case ocArcCot:                  // simulate ACOT(x) by (PI/2-ATAN(x))
1502                 AppendBinaryOperatorToken( EXC_TOKID_SUB, true );
1503                 AppendParenToken();
1504             break;
1505 
1506             default:;
1507         }
1508     }
1509     else
1510         mxData->mbOk = false;
1511 }
1512 
1513 void XclExpFmlaCompImpl::FinishIfFunction( XclExpFuncData& rFuncData )
1514 {
1515     sal_uInt16 nParamCount = rFuncData.GetParamCount();
1516     DBG_ASSERT( (nParamCount == 2) || (nParamCount == 3), "XclExpFmlaCompImpl::FinishIfFunction - wrong parameter count" );
1517     const ScfUInt16Vec& rAttrPos = rFuncData.GetAttrPosVec();
1518     DBG_ASSERT( nParamCount == rAttrPos.size(), "XclExpFmlaCompImpl::FinishIfFunction - wrong number of tAttr tokens" );
1519     // update tAttrIf token following the condition parameter
1520     Overwrite( rAttrPos[ 0 ] + 2, static_cast< sal_uInt16 >( rAttrPos[ 1 ] - rAttrPos[ 0 ] ) );
1521     // update the tAttrGoto tokens following true and false parameters
1522     UpdateAttrGoto( rAttrPos[ 1 ] );
1523     if( nParamCount == 3 )
1524         UpdateAttrGoto( rAttrPos[ 2 ] );
1525 }
1526 
1527 void XclExpFmlaCompImpl::FinishChooseFunction( XclExpFuncData& rFuncData )
1528 {
1529     sal_uInt16 nParamCount = rFuncData.GetParamCount();
1530     ScfUInt16Vec& rAttrPos = rFuncData.GetAttrPosVec();
1531     DBG_ASSERT( nParamCount == rAttrPos.size(), "XclExpFmlaCompImpl::FinishChooseFunction - wrong number of tAttr tokens" );
1532     // number of choices is parameter count minus 1
1533     sal_uInt16 nChoices = nParamCount - 1;
1534     // tAttrChoose token contains number of choices
1535     Overwrite( rAttrPos[ 0 ] + 2, nChoices );
1536     // cache position of the jump table (follows number of choices in tAttrChoose token)
1537     sal_uInt16 nJumpArrPos = rAttrPos[ 0 ] + 4;
1538     // size of jump table: number of choices, plus 1 for error position
1539     sal_uInt16 nJumpArrSize = 2 * (nChoices + 1);
1540     // insert the jump table into the tAttrChoose token
1541     InsertZeros( nJumpArrPos, nJumpArrSize );
1542     // update positions of tAttrGoto tokens after jump table insertion
1543     sal_uInt16 nIdx;
1544     for( nIdx = 1; nIdx < nParamCount; ++nIdx )
1545         rAttrPos[ nIdx ] = rAttrPos[ nIdx ] + nJumpArrSize;
1546     // update the tAttrGoto tokens (they contain a value one-less to real distance)
1547     for( nIdx = 1; nIdx < nParamCount; ++nIdx )
1548         UpdateAttrGoto( rAttrPos[ nIdx ] );
1549     // update the distances in the jump table
1550     Overwrite( nJumpArrPos, nJumpArrSize );
1551     for( nIdx = 1; nIdx < nParamCount; ++nIdx )
1552         Overwrite( nJumpArrPos + 2 * nIdx, static_cast< sal_uInt16 >( rAttrPos[ nIdx ] + 4 - nJumpArrPos ) );
1553 }
1554 
1555 XclExpScToken XclExpFmlaCompImpl::ProcessParam( XclExpScToken aTokData, XclExpFuncData& rFuncData )
1556 {
1557     if( rFuncData.IsCalcOnlyParam() )
1558     {
1559         // skip Calc-only parameter, stop at next ocClose or ocSep
1560         aTokData = SkipExpression( aTokData, true );
1561         rFuncData.IncParamInfoIdx();
1562     }
1563     else
1564     {
1565         // insert Excel-only parameters, modifies param count and class in rFuncData
1566         while( rFuncData.IsExcelOnlyParam() )
1567             AppendDefaultParam( rFuncData );
1568 
1569         // process the parameter, stop at next ocClose or ocSep
1570         PrepareParam( rFuncData );
1571         /*  #i37355# insert tMissArg token for missing parameters --
1572             Excel import filter adds ocMissing token (handled in Factor()),
1573             but Calc itself does not do this if a new formula is entered. */
1574         switch( aTokData.GetOpCode() )
1575         {
1576             case ocSep:
1577             case ocClose:   AppendMissingToken();   break;  // empty parameter
1578             default:        aTokData = Expression( aTokData, false, true );
1579         }
1580         // finalize the parameter and add special tokens, e.g. for IF or CHOOSE parameters
1581         if( mxData->mbOk ) FinishParam( rFuncData );
1582     }
1583     return aTokData;
1584 }
1585 
1586 void XclExpFmlaCompImpl::PrepareParam( XclExpFuncData& rFuncData )
1587 {
1588     // index of this parameter is equal to number of already finished parameters
1589     sal_uInt8 nParamIdx = rFuncData.GetParamCount();
1590 
1591     switch( rFuncData.GetOpCode() )
1592     {
1593         case ocIf:
1594             switch( nParamIdx )
1595             {
1596                 // add a tAttrIf token before true-parameter (second parameter)
1597                 case 1:     AppendJumpToken( rFuncData, EXC_TOK_ATTR_IF );      break;
1598                 // add a tAttrGoto token before false-parameter (third parameter)
1599                 case 2:     AppendJumpToken( rFuncData, EXC_TOK_ATTR_GOTO );    break;
1600             }
1601         break;
1602 
1603         case ocChose:
1604             switch( nParamIdx )
1605             {
1606                 // do nothing for first parameter
1607                 case 0:                                                         break;
1608                 // add a tAttrChoose token before first value parameter (second parameter)
1609                 case 1:     AppendJumpToken( rFuncData, EXC_TOK_ATTR_CHOOSE );  break;
1610                 // add a tAttrGoto token before other value parameters
1611                 default:    AppendJumpToken( rFuncData, EXC_TOK_ATTR_GOTO );
1612             }
1613         break;
1614 
1615         case ocArcCotHyp:               // simulate ACOTH(x) by ATANH(1/(x))
1616             if( nParamIdx == 0 )
1617                 AppendIntToken( 1 );
1618         break;
1619         default:;
1620     }
1621 }
1622 
1623 void XclExpFmlaCompImpl::FinishParam( XclExpFuncData& rFuncData )
1624 {
1625     // increase parameter count, update operand stack
1626     rFuncData.FinishParam( PopOperandPos() );
1627 
1628     // append more tokens for parameters of some special functions
1629     sal_uInt8 nParamIdx = rFuncData.GetParamCount() - 1;
1630     switch( rFuncData.GetOpCode() )
1631     {
1632         case ocArcCotHyp:               // simulate ACOTH(x) by ATANH(1/(x))
1633             if( nParamIdx == 0 )
1634             {
1635                 AppendParenToken();
1636                 AppendBinaryOperatorToken( EXC_TOKID_DIV, true );
1637             }
1638         break;
1639         default:;
1640     }
1641 }
1642 
1643 void XclExpFmlaCompImpl::AppendDefaultParam( XclExpFuncData& rFuncData )
1644 {
1645     // prepare parameters of some special functions
1646     PrepareParam( rFuncData );
1647 
1648     switch( rFuncData.GetOpCode() )
1649     {
1650         case ocExternal:
1651             AppendAddInCallToken( rFuncData.GetExtFuncData() );
1652         break;
1653         case ocEuroConvert:
1654             AppendEuroToolCallToken( rFuncData.GetExtFuncData() );
1655         break;
1656         case ocMacro:
1657             AppendMacroCallToken( rFuncData.GetExtFuncData() );
1658         break;
1659         default:
1660         {
1661             DBG_ASSERT( rFuncData.IsMacroFunc(), "XclExpFmlaCompImpl::AppendDefaultParam - unknown opcode" );
1662             if( rFuncData.IsMacroFunc() )
1663                 AppendMacroCallToken( rFuncData.GetExtFuncData() );
1664             else
1665                 AppendMissingToken();   // to keep parameter count valid
1666         }
1667     }
1668 
1669     // update parameter count, add special parameter tokens
1670     FinishParam( rFuncData );
1671 }
1672 
1673 void XclExpFmlaCompImpl::AppendTrailingParam( XclExpFuncData& rFuncData )
1674 {
1675     sal_uInt8 nParamCount = rFuncData.GetParamCount();
1676     switch( rFuncData.GetOpCode() )
1677     {
1678         case ocIf:
1679             if( nParamCount == 1 )
1680             {
1681                 // #112262# Excel needs at least two parameters in IF function
1682                 PrepareParam( rFuncData );
1683                 AppendBoolToken( true );
1684                 FinishParam( rFuncData );
1685             }
1686         break;
1687 
1688         case ocRound:
1689         case ocRoundUp:
1690         case ocRoundDown:
1691             if( nParamCount == 1 )
1692             {
1693                 // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel
1694                 PrepareParam( rFuncData );
1695                 AppendIntToken( 0 );
1696                 FinishParam( rFuncData );
1697             }
1698         break;
1699 
1700         case ocIndex:
1701             if( nParamCount == 1 )
1702             {
1703                 // INDEX function needs at least 2 parameters in Excel
1704                 PrepareParam( rFuncData );
1705                 AppendMissingToken();
1706                 FinishParam( rFuncData );
1707             }
1708         break;
1709 
1710         case ocExternal:
1711         case ocMacro:
1712             // external or macro call without parameters needs the external name reference
1713             if( nParamCount == 0 )
1714                 AppendDefaultParam( rFuncData );
1715         break;
1716 
1717         case ocGammaDist:
1718             if( nParamCount == 3 )
1719             {
1720                 // GAMMADIST function needs 4 parameters in Excel
1721                 PrepareParam( rFuncData );
1722                 AppendIntToken( 1 );
1723                 FinishParam( rFuncData );
1724             }
1725         break;
1726 
1727         case ocPoissonDist:
1728             if( nParamCount == 2 )
1729             {
1730                 // POISSON function needs 3 parameters in Excel
1731                 PrepareParam( rFuncData );
1732                 AppendIntToken( 1 );
1733                 FinishParam( rFuncData );
1734             }
1735         break;
1736 
1737         case ocNormDist:
1738             if( nParamCount == 3 )
1739             {
1740                 // NORMDIST function needs 4 parameters in Excel
1741                 PrepareParam( rFuncData );
1742                 AppendBoolToken( true );
1743                 FinishParam( rFuncData );
1744             }
1745         break;
1746 
1747         case ocLogNormDist:
1748             switch( nParamCount )
1749              {
1750                 // LOGNORMDIST function needs 3 parameters in Excel
1751                 case 1:
1752                     PrepareParam( rFuncData );
1753                     AppendIntToken( 0 );
1754                     FinishParam( rFuncData );
1755                  // do not break, add next default parameter
1756                 case 2:
1757                     PrepareParam( rFuncData );
1758                     AppendIntToken( 1 );
1759                     FinishParam( rFuncData );
1760                     break;
1761                 default:;
1762              }
1763 
1764         break;
1765 
1766         default:
1767             // #i108420# function without parameters stored as macro call needs the external name reference
1768             if( (nParamCount == 0) && rFuncData.IsMacroFunc() )
1769                 AppendDefaultParam( rFuncData );
1770 
1771     }
1772 }
1773 
1774 // reference handling ---------------------------------------------------------
1775 
1776 namespace {
1777 
1778 inline bool lclIsRefRel2D( const ScSingleRefData& rRefData )
1779 {
1780     return rRefData.IsColRel() || rRefData.IsRowRel();
1781 }
1782 
1783 inline bool lclIsRefDel2D( const ScSingleRefData& rRefData )
1784 {
1785     return rRefData.IsColDeleted() || rRefData.IsRowDeleted();
1786 }
1787 
1788 inline bool lclIsRefRel2D( const ScComplexRefData& rRefData )
1789 {
1790     return lclIsRefRel2D( rRefData.Ref1 ) || lclIsRefRel2D( rRefData.Ref2 );
1791 }
1792 
1793 inline bool lclIsRefDel2D( const ScComplexRefData& rRefData )
1794 {
1795     return lclIsRefDel2D( rRefData.Ref1 ) || lclIsRefDel2D( rRefData.Ref2 );
1796 }
1797 
1798 } // namespace
1799 
1800 SCTAB XclExpFmlaCompImpl::GetScTab( const ScSingleRefData& rRefData ) const
1801 {
1802     bool bInvTab = rRefData.IsTabDeleted() || (!mxData->mpScBasePos && IsInGlobals() && rRefData.IsTabRel());
1803     return bInvTab ? SCTAB_INVALID : static_cast< SCTAB >( rRefData.nTab );
1804 }
1805 
1806 bool XclExpFmlaCompImpl::IsRef2D( const ScSingleRefData& rRefData ) const
1807 {
1808     /*  rRefData.IsFlag3D() determines if sheet name is always visible, even on
1809         the own sheet. If 3D references are allowed, the passed reference does
1810         not count as 2D reference. */
1811     return (!mxData->mpLinkMgr || !rRefData.IsFlag3D()) && !rRefData.IsTabDeleted() &&
1812         (rRefData.IsTabRel() ? (rRefData.nRelTab == 0) : (static_cast< SCTAB >( rRefData.nTab ) == GetCurrScTab()));
1813 }
1814 
1815 bool XclExpFmlaCompImpl::IsRef2D( const ScComplexRefData& rRefData ) const
1816 {
1817     return IsRef2D( rRefData.Ref1 ) && IsRef2D( rRefData.Ref2 );
1818 }
1819 
1820 void XclExpFmlaCompImpl::ConvertRefData(
1821     ScSingleRefData& rRefData, XclAddress& rXclPos,
1822     bool bNatLangRef, bool bTruncMaxCol, bool bTruncMaxRow ) const
1823 {
1824     if( mxData->mpScBasePos )
1825     {
1826         // *** reference position exists (cell, matrix) - convert to absolute ***
1827         rRefData.CalcAbsIfRel( *mxData->mpScBasePos );
1828 
1829         // convert column index
1830         SCsCOL& rnScCol = rRefData.nCol;
1831         if( bTruncMaxCol && (rnScCol == mnMaxScCol) )
1832             rnScCol = mnMaxAbsCol;
1833         else if( (rnScCol < 0) || (rnScCol > mnMaxAbsCol) )
1834             rRefData.SetColDeleted( sal_True );
1835         rXclPos.mnCol = static_cast< sal_uInt16 >( rnScCol ) & mnMaxColMask;
1836 
1837         // convert row index
1838         SCsROW& rnScRow = rRefData.nRow;
1839         if( bTruncMaxRow && (rnScRow == mnMaxScRow) )
1840             rnScRow = mnMaxAbsRow;
1841         else if( (rnScRow < 0) || (rnScRow > mnMaxAbsRow) )
1842             rRefData.SetRowDeleted( sal_True );
1843         rXclPos.mnRow = static_cast< sal_uInt16 >( rnScRow ) & mnMaxRowMask;
1844     }
1845     else
1846     {
1847         // *** no reference position (shared, names, condfmt) - use relative values ***
1848 
1849         // convert column index (2-step-cast ScsCOL->sal_Int16->sal_uInt16 to get all bits correctly)
1850         sal_Int16 nXclRelCol = static_cast< sal_Int16 >( rRefData.IsColRel() ? rRefData.nRelCol : rRefData.nCol );
1851         rXclPos.mnCol = static_cast< sal_uInt16 >( nXclRelCol ) & mnMaxColMask;
1852 
1853         // convert row index (2-step-cast ScsROW->sal_Int16->sal_uInt16 to get all bits correctly)
1854         sal_Int16 nXclRelRow = static_cast< sal_Int16 >( rRefData.IsRowRel() ? rRefData.nRelRow : rRefData.nRow );
1855         rXclPos.mnRow = static_cast< sal_uInt16 >( nXclRelRow ) & mnMaxRowMask;
1856 
1857         // resolve relative tab index if possible
1858         if( rRefData.IsTabRel() && !IsInGlobals() && (GetCurrScTab() < GetDoc().GetTableCount()) )
1859             rRefData.nTab = static_cast< SCsTAB >( GetCurrScTab() + rRefData.nRelTab );
1860     }
1861 
1862     // flags for relative column and row
1863     if( bNatLangRef )
1864     {
1865         DBG_ASSERT( meBiff == EXC_BIFF8, "XclExpFmlaCompImpl::ConvertRefData - NLRs only for BIFF8" );
1866         // Calc does not support absolute reference mode in natural language references
1867         ::set_flag( rXclPos.mnCol, EXC_TOK_NLR_REL );
1868     }
1869     else
1870     {
1871         sal_uInt16& rnRelField = (meBiff <= EXC_BIFF5) ? rXclPos.mnRow : rXclPos.mnCol;
1872         ::set_flag( rnRelField, EXC_TOK_REF_COLREL, rRefData.IsColRel() );
1873         ::set_flag( rnRelField, EXC_TOK_REF_ROWREL, rRefData.IsRowRel() );
1874     }
1875 }
1876 
1877 void XclExpFmlaCompImpl::ConvertRefData(
1878         ScComplexRefData& rRefData, XclRange& rXclRange, bool bNatLangRef ) const
1879 {
1880     // convert start and end of the range
1881     ConvertRefData( rRefData.Ref1, rXclRange.maFirst, bNatLangRef, false, false );
1882     bool bTruncMaxCol = !rRefData.Ref1.IsColDeleted() && (rRefData.Ref1.nCol == 0);
1883     bool bTruncMaxRow = !rRefData.Ref1.IsRowDeleted() && (rRefData.Ref1.nRow == 0);
1884     ConvertRefData( rRefData.Ref2, rXclRange.maLast, bNatLangRef, bTruncMaxCol, bTruncMaxRow );
1885 }
1886 
1887 XclExpRefLogEntry* XclExpFmlaCompImpl::GetNewRefLogEntry()
1888 {
1889     if( mxData->mpRefLog )
1890     {
1891         mxData->mpRefLog->resize( mxData->mpRefLog->size() + 1 );
1892         return &mxData->mpRefLog->back();
1893     }
1894     return 0;
1895 }
1896 
1897 void XclExpFmlaCompImpl::ProcessCellRef( const XclExpScToken& rTokData )
1898 {
1899     // get the Excel address components, adjust internal data in aRefData
1900     bool bNatLangRef = (meBiff == EXC_BIFF8) && mxData->mpScBasePos && (rTokData.GetOpCode() == ocColRowName);
1901     ScSingleRefData aRefData = static_cast< const ScToken* >( rTokData.mpScToken )->GetSingleRef();
1902     XclAddress aXclPos( ScAddress::UNINITIALIZED );
1903     ConvertRefData( aRefData, aXclPos, bNatLangRef, false, false );
1904 
1905     if( bNatLangRef )
1906     {
1907         DBG_ASSERT( aRefData.IsColRel() != aRefData.IsRowRel(),
1908             "XclExpFmlaCompImpl::ProcessCellRef - broken natural language reference" );
1909         // create tNlr token for natural language reference
1910         sal_uInt8 nSubId = aRefData.IsColRel() ? EXC_TOK_NLR_COLV : EXC_TOK_NLR_ROWV;
1911         AppendOperandTokenId( EXC_TOKID_NLR, rTokData.mnSpaces );
1912         Append( nSubId );
1913         AppendAddress( aXclPos );
1914     }
1915     else
1916     {
1917         // store external cell contents in CRN records
1918         if( mxData->mrCfg.mbFromCell && mxData->mpLinkMgr && mxData->mpScBasePos )
1919             mxData->mpLinkMgr->StoreCell( aRefData );
1920 
1921         // create the tRef, tRefErr, tRefN, tRef3d, or tRefErr3d token
1922         if( !mxData->mrCfg.mb3DRefOnly && IsRef2D( aRefData ) )
1923         {
1924             // 2D reference (not in defined names, but allowed in range lists)
1925             sal_uInt8 nBaseId = (!mxData->mpScBasePos && lclIsRefRel2D( aRefData )) ? EXC_TOKID_REFN :
1926                 (lclIsRefDel2D( aRefData ) ? EXC_TOKID_REFERR : EXC_TOKID_REF);
1927             AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
1928             AppendAddress( aXclPos );
1929         }
1930         else if( mxData->mpLinkMgr )    // 3D reference
1931         {
1932             // 1-based EXTERNSHEET index and 0-based Excel sheet index
1933             sal_uInt16 nExtSheet, nXclTab;
1934             mxData->mpLinkMgr->FindExtSheet( nExtSheet, nXclTab, GetScTab( aRefData ), GetNewRefLogEntry() );
1935             // write the token
1936             sal_uInt8 nBaseId = lclIsRefDel2D( aRefData ) ? EXC_TOKID_REFERR3D : EXC_TOKID_REF3D;
1937             AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
1938             Append( nExtSheet );
1939             if( meBiff <= EXC_BIFF5 )
1940             {
1941                 Append( 0, 8 );
1942                 Append( nXclTab );
1943                 Append( nXclTab );
1944             }
1945             AppendAddress( aXclPos );
1946         }
1947         else
1948         {
1949             // 3D ref in cond. format, or 2D ref in name
1950             AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces );
1951         }
1952     }
1953 }
1954 
1955 void XclExpFmlaCompImpl::ProcessRangeRef( const XclExpScToken& rTokData )
1956 {
1957     // get the Excel address components, adjust internal data in aRefData
1958     ScComplexRefData aRefData = static_cast< const ScToken* >( rTokData.mpScToken )->GetDoubleRef();
1959     XclRange aXclRange( ScAddress::UNINITIALIZED );
1960     ConvertRefData( aRefData, aXclRange, false );
1961 
1962     // store external cell contents in CRN records
1963     if( mxData->mrCfg.mbFromCell && mxData->mpLinkMgr && mxData->mpScBasePos )
1964         mxData->mpLinkMgr->StoreCellRange( aRefData );
1965 
1966     // create the tArea, tAreaErr, tAreaN, tArea3d, or tAreaErr3d token
1967     if( !mxData->mrCfg.mb3DRefOnly && IsRef2D( aRefData ) )
1968     {
1969         // 2D reference (not in name formulas, but allowed in range lists)
1970         sal_uInt8 nBaseId = (!mxData->mpScBasePos && lclIsRefRel2D( aRefData )) ? EXC_TOKID_AREAN :
1971              (lclIsRefDel2D( aRefData ) ? EXC_TOKID_AREAERR : EXC_TOKID_AREA);
1972         AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
1973         AppendRange( aXclRange );
1974     }
1975     else if( mxData->mpLinkMgr )    // 3D reference
1976     {
1977         // 1-based EXTERNSHEET index and 0-based Excel sheet indexes
1978         sal_uInt16 nExtSheet, nFirstXclTab, nLastXclTab;
1979         mxData->mpLinkMgr->FindExtSheet( nExtSheet, nFirstXclTab, nLastXclTab,
1980             GetScTab( aRefData.Ref1 ), GetScTab( aRefData.Ref2 ), GetNewRefLogEntry() );
1981         // write the token
1982         sal_uInt8 nBaseId = lclIsRefDel2D( aRefData ) ? EXC_TOKID_AREAERR3D : EXC_TOKID_AREA3D;
1983         AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
1984         Append( nExtSheet );
1985         if( meBiff <= EXC_BIFF5 )
1986         {
1987             Append( 0, 8 );
1988             Append( nFirstXclTab );
1989             Append( nLastXclTab );
1990         }
1991         AppendRange( aXclRange );
1992     }
1993     else
1994     {
1995         // 3D ref in cond. format, or 2D ref in name
1996         AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces );
1997     }
1998 }
1999 
2000 void XclExpFmlaCompImpl::ProcessExternalCellRef( const XclExpScToken& rTokData )
2001 {
2002     if( mxData->mpLinkMgr )
2003     {
2004         // get the Excel address components, adjust internal data in aRefData
2005         ScSingleRefData aRefData = static_cast< const ScToken* >( rTokData.mpScToken )->GetSingleRef();
2006         XclAddress aXclPos( ScAddress::UNINITIALIZED );
2007         ConvertRefData( aRefData, aXclPos, false, false, false );
2008 
2009         // store external cell contents in CRN records
2010         sal_uInt16 nFileId = rTokData.mpScToken->GetIndex();
2011         const String& rTabName = rTokData.mpScToken->GetString();
2012         if( mxData->mrCfg.mbFromCell && mxData->mpScBasePos )
2013             mxData->mpLinkMgr->StoreCell( nFileId, rTabName, aRefData );
2014 
2015         // 1-based EXTERNSHEET index and 0-based Excel sheet indexes
2016         sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab;
2017         mxData->mpLinkMgr->FindExtSheet( nFileId, rTabName, 1, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry() );
2018         // write the token
2019         sal_uInt8 nBaseId = lclIsRefDel2D( aRefData ) ? EXC_TOKID_REFERR3D : EXC_TOKID_REF3D;
2020         AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
2021         Append( nExtSheet );
2022         if( meBiff <= EXC_BIFF5 )
2023         {
2024             Append( 0, 8 );
2025             Append( nFirstSBTab );
2026             Append( nLastSBTab );
2027         }
2028         AppendAddress( aXclPos );
2029     }
2030     else
2031     {
2032         AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces );
2033     }
2034 }
2035 
2036 void XclExpFmlaCompImpl::ProcessExternalRangeRef( const XclExpScToken& rTokData )
2037 {
2038     if( mxData->mpLinkMgr )
2039     {
2040         // get the Excel address components, adjust internal data in aRefData
2041         ScComplexRefData aRefData = static_cast< const ScToken* >( rTokData.mpScToken )->GetDoubleRef();
2042         XclRange aXclRange( ScAddress::UNINITIALIZED );
2043         ConvertRefData( aRefData, aXclRange, false );
2044 
2045         // store external cell contents in CRN records
2046         sal_uInt16 nFileId = rTokData.mpScToken->GetIndex();
2047         const String& rTabName = rTokData.mpScToken->GetString();
2048         if( mxData->mrCfg.mbFromCell && mxData->mpScBasePos )
2049             mxData->mpLinkMgr->StoreCellRange( nFileId, rTabName, aRefData );
2050 
2051         // 1-based EXTERNSHEET index and 0-based Excel sheet indexes
2052         sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab;
2053         sal_uInt16 nTabSpan = static_cast< sal_uInt16 >( aRefData.Ref2.nTab - aRefData.Ref1.nTab + 1 );
2054         mxData->mpLinkMgr->FindExtSheet( nFileId, rTabName, nTabSpan, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry() );
2055         // write the token
2056         sal_uInt8 nBaseId = lclIsRefDel2D( aRefData ) ? EXC_TOKID_AREAERR3D : EXC_TOKID_AREA3D;
2057         AppendOperandTokenId( GetTokenId( nBaseId, EXC_TOKCLASS_REF ), rTokData.mnSpaces );
2058         Append( nExtSheet );
2059         if( meBiff <= EXC_BIFF5 )
2060         {
2061             Append( 0, 8 );
2062             Append( nFirstSBTab );
2063             Append( nLastSBTab );
2064         }
2065         AppendRange( aXclRange );
2066     }
2067     else
2068     {
2069         AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces );
2070     }
2071 }
2072 
2073 void XclExpFmlaCompImpl::ProcessDefinedName( const XclExpScToken& rTokData )
2074 {
2075     XclExpNameManager& rNameMgr = GetNameManager();
2076     sal_uInt16 nNameIdx = rNameMgr.InsertName( rTokData.mpScToken->GetIndex() );
2077     if( nNameIdx != 0 )
2078     {
2079         // global names always with tName token, local names dependent on config
2080         SCTAB nScTab = rNameMgr.GetScTab( nNameIdx );
2081         if( (nScTab == SCTAB_GLOBAL) || (!mxData->mrCfg.mb3DRefOnly && (nScTab == GetCurrScTab())) )
2082         {
2083             AppendNameToken( nNameIdx, rTokData.mnSpaces );
2084         }
2085         else if( mxData->mpLinkMgr )
2086         {
2087             // use the same special EXTERNNAME to refer to any local name
2088             sal_uInt16 nExtSheet = mxData->mpLinkMgr->FindExtSheet( EXC_EXTSH_OWNDOC );
2089             AppendNameXToken( nExtSheet, nNameIdx, rTokData.mnSpaces );
2090         }
2091         else
2092             AppendErrorToken( EXC_ERR_NAME, rTokData.mnSpaces );
2093         // volatile names (containing volatile functions)
2094         mxData->mbVolatile |= rNameMgr.IsVolatile( nNameIdx );
2095     }
2096     else
2097         AppendErrorToken( EXC_ERR_NAME, rTokData.mnSpaces );
2098 }
2099 
2100 void XclExpFmlaCompImpl::ProcessExternalName( const XclExpScToken& rTokData )
2101 {
2102     if( mxData->mpLinkMgr )
2103     {
2104         ScExternalRefManager& rExtRefMgr = *GetDoc().GetExternalRefManager();
2105         sal_uInt16 nFileId = rTokData.mpScToken->GetIndex();
2106         const String& rName = rTokData.mpScToken->GetString();
2107         ScExternalRefCache::TokenArrayRef xArray = rExtRefMgr.getRangeNameTokens( nFileId, rName );
2108         if( xArray.get() )
2109         {
2110             // store external cell contents in CRN records
2111             if( mxData->mpScBasePos )
2112             {
2113                 for( FormulaToken* pScToken = xArray->First(); pScToken; pScToken = xArray->Next() )
2114                 {
2115                     if( pScToken->GetOpCode() == ocExternalRef )
2116                     {
2117                         switch( pScToken->GetType() )
2118                         {
2119                             case svExternalSingleRef:
2120                             {
2121                                 ScSingleRefData aRefData = static_cast< ScToken* >( pScToken )->GetSingleRef();
2122                                 aRefData.CalcAbsIfRel( *mxData->mpScBasePos );
2123                                 mxData->mpLinkMgr->StoreCell( nFileId, pScToken->GetString(), aRefData );
2124                             }
2125                             break;
2126                             case svExternalDoubleRef:
2127                             {
2128                                 ScComplexRefData aRefData = static_cast< ScToken* >( pScToken )->GetDoubleRef();
2129                                 aRefData.CalcAbsIfRel( *mxData->mpScBasePos );
2130                                 mxData->mpLinkMgr->StoreCellRange( nFileId, pScToken->GetString(), aRefData );
2131                             }
2132                             default:
2133                                 ;   // nothing, avoid compiler warning
2134                         }
2135                     }
2136                 }
2137             }
2138 
2139             // insert the new external name and create the tNameX token
2140             sal_uInt16 nExtSheet, nExtName;
2141             const String* pFile = rExtRefMgr.getExternalFileName( nFileId );
2142             if( pFile && mxData->mpLinkMgr->InsertExtName( nExtSheet, nExtName, *pFile, rName, xArray ) )
2143             {
2144                 AppendNameXToken( nExtSheet, nExtName, rTokData.mnSpaces );
2145                 return;
2146             }
2147         }
2148     }
2149 
2150     // on any error: create a #NAME? error
2151     AppendErrorToken( EXC_ERR_NAME, rTokData.mnSpaces );
2152 }
2153 
2154 void XclExpFmlaCompImpl::ProcessDatabaseArea( const XclExpScToken& rTokData )
2155 {
2156     sal_uInt16 nNameIdx = GetNameManager().InsertDBRange( rTokData.mpScToken->GetIndex() );
2157     AppendNameToken( nNameIdx, rTokData.mnSpaces );
2158 }
2159 
2160 // token vector ---------------------------------------------------------------
2161 
2162 void XclExpFmlaCompImpl::PushOperandPos( sal_uInt16 nTokPos )
2163 {
2164     mxData->maOpPosStack.push_back( nTokPos );
2165 }
2166 
2167 void XclExpFmlaCompImpl::PushOperatorPos( sal_uInt16 nTokPos, const XclExpOperandListRef& rxOperands )
2168 {
2169     PushOperandPos( nTokPos );
2170     DBG_ASSERT( rxOperands.get(), "XclExpFmlaCompImpl::AppendOperatorTokenId - missing operand list" );
2171     if( mxData->maOpListVec.size() <= nTokPos )
2172         mxData->maOpListVec.resize( nTokPos + 1, XclExpOperandListRef() );
2173     mxData->maOpListVec[ nTokPos ] = rxOperands;
2174 }
2175 
2176 sal_uInt16 XclExpFmlaCompImpl::PopOperandPos()
2177 {
2178     DBG_ASSERT( !mxData->mbOk || !mxData->maOpPosStack.empty(), "XclExpFmlaCompImpl::PopOperandPos - token stack broken" );
2179     mxData->mbOk &= !mxData->maOpPosStack.empty();
2180     if( mxData->mbOk )
2181     {
2182         sal_uInt16 nTokPos = mxData->maOpPosStack.back();
2183         mxData->maOpPosStack.pop_back();
2184         return nTokPos;
2185     }
2186     return 0;
2187 }
2188 
2189 namespace {
2190 
2191 inline void lclAppend( ScfUInt8Vec& orVector, sal_uInt16 nData )
2192 {
2193     orVector.resize( orVector.size() + 2 );
2194     ShortToSVBT16( nData, &*(orVector.end() - 2) );
2195 }
2196 
2197 inline void lclAppend( ScfUInt8Vec& orVector, sal_uInt32 nData )
2198 {
2199     orVector.resize( orVector.size() + 4 );
2200     UInt32ToSVBT32( nData, &*(orVector.end() - 4) );
2201 }
2202 
2203 inline void lclAppend( ScfUInt8Vec& orVector, double fData )
2204 {
2205     orVector.resize( orVector.size() + 8 );
2206     DoubleToSVBT64( fData, &*(orVector.end() - 8) );
2207 }
2208 
2209 inline void lclAppend( ScfUInt8Vec& orVector, const XclExpRoot& rRoot, const String& rString, XclStrFlags nStrFlags )
2210 {
2211     XclExpStringRef xXclStr = XclExpStringHelper::CreateString( rRoot, rString, nStrFlags, EXC_TOK_STR_MAXLEN );
2212     size_t nSize = orVector.size();
2213     orVector.resize( nSize + xXclStr->GetSize() );
2214     xXclStr->WriteToMem( &orVector[ nSize ] );
2215 }
2216 
2217 } // namespace
2218 
2219 void XclExpFmlaCompImpl::Append( sal_uInt8 nData )
2220 {
2221     mxData->maTokVec.push_back( nData );
2222 }
2223 
2224 void XclExpFmlaCompImpl::Append( sal_uInt8 nData, size_t nCount )
2225 {
2226     mxData->maTokVec.resize( mxData->maTokVec.size() + nCount, nData );
2227 }
2228 
2229 void XclExpFmlaCompImpl::Append( sal_uInt16 nData )
2230 {
2231     lclAppend( mxData->maTokVec, nData );
2232 }
2233 
2234 void XclExpFmlaCompImpl::Append( sal_uInt32 nData )
2235 {
2236     lclAppend( mxData->maTokVec, nData );
2237 }
2238 
2239 void XclExpFmlaCompImpl::Append( double fData )
2240 {
2241     lclAppend( mxData->maTokVec, fData );
2242 }
2243 
2244 void XclExpFmlaCompImpl::Append( const String& rString )
2245 {
2246     lclAppend( mxData->maTokVec, GetRoot(), rString, EXC_STR_8BITLENGTH );
2247 }
2248 
2249 void XclExpFmlaCompImpl::AppendAddress( const XclAddress& rXclPos )
2250 {
2251     Append( rXclPos.mnRow );
2252     if( meBiff <= EXC_BIFF5 )
2253         Append( static_cast< sal_uInt8 >( rXclPos.mnCol ) );
2254     else
2255         Append( rXclPos.mnCol );
2256 }
2257 
2258 void XclExpFmlaCompImpl::AppendRange( const XclRange& rXclRange )
2259 {
2260     Append( rXclRange.maFirst.mnRow );
2261     Append( rXclRange.maLast.mnRow );
2262     if( meBiff <= EXC_BIFF5 )
2263     {
2264         Append( static_cast< sal_uInt8 >( rXclRange.maFirst.mnCol ) );
2265         Append( static_cast< sal_uInt8 >( rXclRange.maLast.mnCol ) );
2266     }
2267     else
2268     {
2269         Append( rXclRange.maFirst.mnCol );
2270         Append( rXclRange.maLast.mnCol );
2271     }
2272 }
2273 
2274 void XclExpFmlaCompImpl::AppendSpaceToken( sal_uInt8 nType, sal_uInt8 nCount )
2275 {
2276     if( nCount > 0 )
2277     {
2278         Append( EXC_TOKID_ATTR );
2279         Append( EXC_TOK_ATTR_SPACE );
2280         Append( nType );
2281         Append( nCount );
2282     }
2283 }
2284 
2285 void XclExpFmlaCompImpl::AppendOperandTokenId( sal_uInt8 nTokenId, sal_uInt8 nSpaces )
2286 {
2287     AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP, nSpaces );
2288     PushOperandPos( GetSize() );
2289     Append( nTokenId );
2290 }
2291 
2292 void XclExpFmlaCompImpl::AppendIntToken( sal_uInt16 nValue, sal_uInt8 nSpaces )
2293 {
2294     AppendOperandTokenId( EXC_TOKID_INT, nSpaces );
2295     Append( nValue );
2296 }
2297 
2298 void XclExpFmlaCompImpl::AppendNumToken( double fValue, sal_uInt8 nSpaces )
2299 {
2300     AppendOperandTokenId( EXC_TOKID_NUM, nSpaces );
2301     Append( fValue );
2302 }
2303 
2304 void XclExpFmlaCompImpl::AppendBoolToken( bool bValue, sal_uInt8 nSpaces )
2305 {
2306     AppendOperandTokenId( EXC_TOKID_BOOL, nSpaces );
2307     Append( bValue ? EXC_TOK_BOOL_TRUE : EXC_TOK_BOOL_FALSE );
2308 }
2309 
2310 void XclExpFmlaCompImpl::AppendErrorToken( sal_uInt8 nErrCode, sal_uInt8 nSpaces )
2311 {
2312     AppendOperandTokenId( EXC_TOKID_ERR, nSpaces );
2313     Append( nErrCode );
2314 }
2315 
2316 void XclExpFmlaCompImpl::AppendMissingToken( sal_uInt8 nSpaces )
2317 {
2318     AppendOperandTokenId( EXC_TOKID_MISSARG, nSpaces );
2319 }
2320 
2321 void XclExpFmlaCompImpl::AppendNameToken( sal_uInt16 nNameIdx, sal_uInt8 nSpaces )
2322 {
2323     if( nNameIdx > 0 )
2324     {
2325         AppendOperandTokenId( GetTokenId( EXC_TOKID_NAME, EXC_TOKCLASS_REF ), nSpaces );
2326         Append( nNameIdx );
2327         Append( 0, (meBiff <= EXC_BIFF5) ? 12 : 2 );
2328     }
2329     else
2330         AppendErrorToken( EXC_ERR_NAME );
2331 }
2332 
2333 void XclExpFmlaCompImpl::AppendMissingNameToken( const String& rName, sal_uInt8 nSpaces )
2334 {
2335     sal_uInt16 nNameIdx = GetNameManager().InsertRawName( rName );
2336     AppendNameToken( nNameIdx, nSpaces );
2337 }
2338 
2339 void XclExpFmlaCompImpl::AppendNameXToken( sal_uInt16 nExtSheet, sal_uInt16 nExtName, sal_uInt8 nSpaces )
2340 {
2341     AppendOperandTokenId( GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ), nSpaces );
2342     Append( nExtSheet );
2343     if( meBiff <= EXC_BIFF5 )
2344         Append( 0, 8 );
2345     Append( nExtName );
2346     Append( 0, (meBiff <= EXC_BIFF5) ? 12 : 2 );
2347 }
2348 
2349 void XclExpFmlaCompImpl::AppendMacroCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces )
2350 {
2351     sal_uInt16 nNameIdx = GetNameManager().InsertMacroCall( rExtFuncData.maFuncName, rExtFuncData.mbVBasic, true, rExtFuncData.mbHidden );
2352     AppendNameToken( nNameIdx, nSpaces );
2353 }
2354 
2355 void XclExpFmlaCompImpl::AppendAddInCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces )
2356 {
2357     String aXclFuncName;
2358     if( mxData->mpLinkMgr && ScGlobal::GetAddInCollection()->GetExcelName( rExtFuncData.maFuncName, GetUILanguage(), aXclFuncName ) )
2359     {
2360         sal_uInt16 nExtSheet, nExtName;
2361         if( mxData->mpLinkMgr->InsertAddIn( nExtSheet, nExtName, aXclFuncName ) )
2362         {
2363             AppendNameXToken( nExtSheet, nExtName, nSpaces );
2364             return;
2365         }
2366     }
2367     AppendMacroCallToken( rExtFuncData, nSpaces );
2368 }
2369 
2370 void XclExpFmlaCompImpl::AppendEuroToolCallToken( const XclExpExtFuncData& rExtFuncData, sal_uInt8 nSpaces )
2371 {
2372     sal_uInt16 nExtSheet, nExtName;
2373     if( mxData->mpLinkMgr && mxData->mpLinkMgr->InsertEuroTool( nExtSheet, nExtName, rExtFuncData.maFuncName ) )
2374         AppendNameXToken( nExtSheet, nExtName, nSpaces );
2375     else
2376         AppendMacroCallToken( rExtFuncData, nSpaces );
2377 }
2378 
2379 void XclExpFmlaCompImpl::AppendOperatorTokenId( sal_uInt8 nTokenId, const XclExpOperandListRef& rxOperands, sal_uInt8 nSpaces )
2380 {
2381     AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP, nSpaces );
2382     PushOperatorPos( GetSize(), rxOperands );
2383     Append( nTokenId );
2384 }
2385 
2386 void XclExpFmlaCompImpl::AppendUnaryOperatorToken( sal_uInt8 nTokenId, sal_uInt8 nSpaces )
2387 {
2388     XclExpOperandListRef xOperands( new XclExpOperandList );
2389     xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_RPO, true );
2390     AppendOperatorTokenId( nTokenId, xOperands, nSpaces );
2391 }
2392 
2393 void XclExpFmlaCompImpl::AppendBinaryOperatorToken( sal_uInt8 nTokenId, bool bValType, sal_uInt8 nSpaces )
2394 {
2395     XclExpOperandListRef xOperands( new XclExpOperandList );
2396     xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_RPO, bValType );
2397     xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_RPO, bValType );
2398     AppendOperatorTokenId( nTokenId, xOperands, nSpaces );
2399 }
2400 
2401 void XclExpFmlaCompImpl::AppendLogicalOperatorToken( sal_uInt16 nXclFuncIdx, sal_uInt8 nOpCount )
2402 {
2403     XclExpOperandListRef xOperands( new XclExpOperandList );
2404     for( sal_uInt8 nOpIdx = 0; nOpIdx < nOpCount; ++nOpIdx  )
2405         xOperands->AppendOperand( PopOperandPos(), EXC_PARAMCONV_RPX, false );
2406     AppendOperatorTokenId( GetTokenId( EXC_TOKID_FUNCVAR, EXC_TOKCLASS_VAL ), xOperands );
2407     Append( nOpCount );
2408     Append( nXclFuncIdx );
2409 }
2410 
2411 void XclExpFmlaCompImpl::AppendFuncToken( const XclExpFuncData& rFuncData )
2412 {
2413     sal_uInt16 nXclFuncIdx = rFuncData.GetXclFuncIdx();
2414     sal_uInt8 nParamCount = rFuncData.GetParamCount();
2415     sal_uInt8 nRetClass = rFuncData.GetReturnClass();
2416 
2417     if( (nXclFuncIdx == EXC_FUNCID_SUM) && (nParamCount == 1) )
2418     {
2419         // SUM with only one parameter
2420         AppendOperatorTokenId( EXC_TOKID_ATTR, rFuncData.GetOperandList() );
2421         Append( EXC_TOK_ATTR_SUM );
2422         Append( sal_uInt16( 0 ) );
2423     }
2424     else if( rFuncData.IsFixedParamCount() )
2425     {
2426         // fixed number of parameters
2427         AppendOperatorTokenId( GetTokenId( EXC_TOKID_FUNC, nRetClass ), rFuncData.GetOperandList() );
2428         Append( nXclFuncIdx );
2429     }
2430     else
2431     {
2432         // variable number of parameters
2433         AppendOperatorTokenId( GetTokenId( EXC_TOKID_FUNCVAR, nRetClass ), rFuncData.GetOperandList() );
2434         Append( nParamCount );
2435         Append( nXclFuncIdx );
2436     }
2437 }
2438 
2439 void XclExpFmlaCompImpl::AppendParenToken( sal_uInt8 nOpenSpaces, sal_uInt8 nCloseSpaces )
2440 {
2441     AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP_OPEN, nOpenSpaces );
2442     AppendSpaceToken( EXC_TOK_ATTR_SPACE_SP_CLOSE, nCloseSpaces );
2443     Append( EXC_TOKID_PAREN );
2444 }
2445 
2446 void XclExpFmlaCompImpl::AppendJumpToken( XclExpFuncData& rFuncData, sal_uInt8 nAttrType )
2447 {
2448     // store the start position of the token
2449     rFuncData.AppendAttrPos( GetSize() );
2450     // create the tAttr token
2451     Append( EXC_TOKID_ATTR );
2452     Append( nAttrType );
2453     Append( sal_uInt16( 0 ) );  // placeholder that will be updated later
2454 }
2455 
2456 void XclExpFmlaCompImpl::InsertZeros( sal_uInt16 nInsertPos, sal_uInt16 nInsertSize )
2457 {
2458     // insert zeros into the token array
2459     DBG_ASSERT( nInsertPos < mxData->maTokVec.size(), "XclExpFmlaCompImpl::Insert - invalid position" );
2460     mxData->maTokVec.insert( mxData->maTokVec.begin() + nInsertPos, nInsertSize, 0 );
2461 
2462     // update positions of operands waiting for an operator
2463     for( ScfUInt16Vec::iterator aIt = mxData->maOpPosStack.begin(), aEnd = mxData->maOpPosStack.end(); aIt != aEnd; ++aIt )
2464         if( nInsertPos <= *aIt )
2465             *aIt = *aIt + nInsertSize;
2466 
2467     // update operand lists of all operator tokens
2468     if( nInsertPos < mxData->maOpListVec.size() )
2469         mxData->maOpListVec.insert( mxData->maOpListVec.begin() + nInsertPos, nInsertSize, XclExpOperandListRef() );
2470     for( XclExpOperandListVector::iterator aIt = mxData->maOpListVec.begin(), aEnd = mxData->maOpListVec.end(); aIt != aEnd; ++aIt )
2471         if( aIt->get() )
2472             for( XclExpOperandList::iterator aIt2 = (*aIt)->begin(), aEnd2 = (*aIt)->end(); aIt2 != aEnd2; ++aIt2 )
2473                 if( nInsertPos <= aIt2->mnTokPos )
2474                     aIt2->mnTokPos = aIt2->mnTokPos + nInsertSize;
2475 }
2476 
2477 void XclExpFmlaCompImpl::Overwrite( sal_uInt16 nWriteToPos, sal_uInt16 nOffset )
2478 {
2479     DBG_ASSERT( static_cast< size_t >( nWriteToPos + 1 ) < mxData->maTokVec.size(), "XclExpFmlaCompImpl::Overwrite - invalid position" );
2480     ShortToSVBT16( nOffset, &mxData->maTokVec[ nWriteToPos ] );
2481 }
2482 
2483 void XclExpFmlaCompImpl::UpdateAttrGoto( sal_uInt16 nAttrPos )
2484 {
2485     /*  tAttrGoto contains distance from end of tAttr token to position behind
2486         the function token (for IF or CHOOSE function), which is currently at
2487         the end of the token array. Additionally this distance is decreased by
2488         one, for whatever reason. So we have to subtract 4 and 1 from the
2489         distance between the tAttr token start and the end of the token array. */
2490     Overwrite( nAttrPos + 2, static_cast< sal_uInt16 >( GetSize() - nAttrPos - 5 ) );
2491 }
2492 
2493 bool XclExpFmlaCompImpl::IsSpaceToken( sal_uInt16 nPos ) const
2494 {
2495     return
2496         (static_cast< size_t >( nPos + 4 ) <= mxData->maTokVec.size()) &&
2497         (mxData->maTokVec[ nPos ] == EXC_TOKID_ATTR) &&
2498         (mxData->maTokVec[ nPos + 1 ] == EXC_TOK_ATTR_SPACE);
2499 }
2500 
2501 void XclExpFmlaCompImpl::RemoveTrailingParen()
2502 {
2503     // remove trailing tParen token
2504     if( !mxData->maTokVec.empty() && (mxData->maTokVec.back() == EXC_TOKID_PAREN) )
2505         mxData->maTokVec.pop_back();
2506     // remove remaining tAttrSpace tokens
2507     while( (mxData->maTokVec.size() >= 4) && IsSpaceToken( GetSize() - 4 ) )
2508         mxData->maTokVec.erase( mxData->maTokVec.end() - 4, mxData->maTokVec.end() );
2509 }
2510 
2511 void XclExpFmlaCompImpl::AppendExt( sal_uInt8 nData )
2512 {
2513     mxData->maExtDataVec.push_back( nData );
2514 }
2515 
2516 void XclExpFmlaCompImpl::AppendExt( sal_uInt8 nData, size_t nCount )
2517 {
2518     mxData->maExtDataVec.resize( mxData->maExtDataVec.size() + nCount, nData );
2519 }
2520 
2521 void XclExpFmlaCompImpl::AppendExt( sal_uInt16 nData )
2522 {
2523     lclAppend( mxData->maExtDataVec, nData );
2524 }
2525 
2526 void XclExpFmlaCompImpl::AppendExt( sal_uInt32 nData )
2527 {
2528     lclAppend( mxData->maExtDataVec, nData );
2529 }
2530 
2531 void XclExpFmlaCompImpl::AppendExt( double fData )
2532 {
2533     lclAppend( mxData->maExtDataVec, fData );
2534 }
2535 
2536 void XclExpFmlaCompImpl::AppendExt( const String& rString )
2537 {
2538     lclAppend( mxData->maExtDataVec, GetRoot(), rString, (meBiff == EXC_BIFF8) ? EXC_STR_DEFAULT : EXC_STR_8BITLENGTH );
2539 }
2540 
2541 // ============================================================================
2542 
2543 namespace {
2544 
2545 void lclInitOwnTab( ScSingleRefData& rRef, const ScAddress& rScPos, SCTAB nCurrScTab, bool b3DRefOnly )
2546 {
2547     if( b3DRefOnly )
2548     {
2549         // no reduction to 2D reference, if global link manager is used
2550         rRef.SetFlag3D( sal_True );
2551     }
2552     else if( rScPos.Tab() == nCurrScTab )
2553     {
2554         rRef.SetTabRel( sal_True );
2555         rRef.nRelTab = 0;
2556     }
2557 }
2558 
2559 void lclPutCellToTokenArray( ScTokenArray& rScTokArr, const ScAddress& rScPos, SCTAB nCurrScTab, bool b3DRefOnly )
2560 {
2561     ScSingleRefData aRef;
2562     aRef.InitAddress( rScPos );
2563     lclInitOwnTab( aRef, rScPos, nCurrScTab, b3DRefOnly );
2564     rScTokArr.AddSingleReference( aRef );
2565 }
2566 
2567 void lclPutRangeToTokenArray( ScTokenArray& rScTokArr, const ScRange& rScRange, SCTAB nCurrScTab, bool b3DRefOnly )
2568 {
2569     if( rScRange.aStart == rScRange.aEnd )
2570     {
2571         lclPutCellToTokenArray( rScTokArr, rScRange.aStart, nCurrScTab, b3DRefOnly );
2572     }
2573     else
2574     {
2575         ScComplexRefData aRef;
2576         aRef.InitRange( rScRange );
2577         lclInitOwnTab( aRef.Ref1, rScRange.aStart, nCurrScTab, b3DRefOnly );
2578         lclInitOwnTab( aRef.Ref2, rScRange.aEnd, nCurrScTab, b3DRefOnly );
2579         rScTokArr.AddDoubleReference( aRef );
2580     }
2581 }
2582 
2583 } // namespace
2584 
2585 // ----------------------------------------------------------------------------
2586 
2587 XclExpFormulaCompiler::XclExpFormulaCompiler( const XclExpRoot& rRoot ) :
2588     XclExpRoot( rRoot ),
2589     mxImpl( new XclExpFmlaCompImpl( rRoot ) )
2590 {
2591 }
2592 
2593 XclExpFormulaCompiler::~XclExpFormulaCompiler()
2594 {
2595 }
2596 
2597 XclTokenArrayRef XclExpFormulaCompiler::CreateFormula(
2598         XclFormulaType eType, const ScTokenArray& rScTokArr,
2599         const ScAddress* pScBasePos, XclExpRefLog* pRefLog )
2600 {
2601     return mxImpl->CreateFormula( eType, rScTokArr, pScBasePos, pRefLog );
2602 }
2603 
2604 XclTokenArrayRef XclExpFormulaCompiler::CreateFormula( XclFormulaType eType, const ScAddress& rScPos )
2605 {
2606     ScTokenArray aScTokArr;
2607     lclPutCellToTokenArray( aScTokArr, rScPos, GetCurrScTab(), mxImpl->Is3DRefOnly( eType ) );
2608     return mxImpl->CreateFormula( eType, aScTokArr );
2609 }
2610 
2611 XclTokenArrayRef XclExpFormulaCompiler::CreateFormula( XclFormulaType eType, const ScRange& rScRange )
2612 {
2613     ScTokenArray aScTokArr;
2614     lclPutRangeToTokenArray( aScTokArr, rScRange, GetCurrScTab(), mxImpl->Is3DRefOnly( eType ) );
2615     return mxImpl->CreateFormula( eType, aScTokArr );
2616 }
2617 
2618 XclTokenArrayRef XclExpFormulaCompiler::CreateFormula( XclFormulaType eType, const ScRangeList& rScRanges )
2619 {
2620     sal_uLong nCount = rScRanges.Count();
2621     if( nCount == 0 )
2622         return XclTokenArrayRef();
2623 
2624     ScTokenArray aScTokArr;
2625     SCTAB nCurrScTab = GetCurrScTab();
2626     bool b3DRefOnly = mxImpl->Is3DRefOnly( eType );
2627     for( sal_uLong nIdx = 0; nIdx < nCount; ++nIdx )
2628     {
2629         if( nIdx > 0 )
2630             aScTokArr.AddOpCode( ocUnion );
2631         lclPutRangeToTokenArray( aScTokArr, *rScRanges.GetObject( nIdx ), nCurrScTab, b3DRefOnly );
2632     }
2633     return mxImpl->CreateFormula( eType, aScTokArr );
2634 }
2635 
2636 XclTokenArrayRef XclExpFormulaCompiler::CreateErrorFormula( sal_uInt8 nErrCode )
2637 {
2638     return mxImpl->CreateErrorFormula( nErrCode );
2639 }
2640 
2641 XclTokenArrayRef XclExpFormulaCompiler::CreateSpecialRefFormula(
2642         sal_uInt8 nTokenId, const XclAddress& rXclPos )
2643 {
2644     return mxImpl->CreateSpecialRefFormula( nTokenId, rXclPos );
2645 }
2646 
2647 XclTokenArrayRef XclExpFormulaCompiler::CreateNameXFormula(
2648         sal_uInt16 nExtSheet, sal_uInt16 nExtName )
2649 {
2650     return mxImpl->CreateNameXFormula( nExtSheet, nExtName );
2651 }
2652 
2653 // ============================================================================
2654 
2655