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