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