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