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