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