1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
25 #include <osl/diagnose.h>
26 #include <sal/log.hxx>
28 #include <com/sun/star/sheet/FormulaToken.hpp>
29 #include <formula/errorcodes.hxx>
30 #include <formula/token.hxx>
31 #include <formula/tokenarray.hxx>
32 #include <formula/FormulaCompiler.hxx>
33 #include <formula/compiler.hxx>
34 #include <svl/sharedstringpool.hxx>
40 using namespace com::sun::star
;
43 // --- helpers --------------------------------------------------------------
45 static bool lcl_IsReference( OpCode eOp
, StackVar eType
)
48 (eOp
== ocPush
&& (eType
== svSingleRef
|| eType
== svDoubleRef
))
49 || (eOp
== ocColRowNameAuto
&& eType
== svDoubleRef
)
50 || (eOp
== ocColRowName
&& eType
== svSingleRef
)
51 || (eOp
== ocMatRef
&& eType
== svSingleRef
)
55 // --- class FormulaToken --------------------------------------------------------
57 FormulaToken::FormulaToken( StackVar eTypeP
, OpCode e
) :
58 eOp(e
), eType( eTypeP
), eRefCntPolicy(RefCntPolicy::ThreadSafe
), mnRefCnt(0)
62 FormulaToken::FormulaToken( const FormulaToken
& r
) :
63 eOp(r
.eOp
), eType( r
.eType
), eRefCntPolicy(RefCntPolicy::ThreadSafe
), mnRefCnt(0)
67 FormulaToken::~FormulaToken()
71 bool FormulaToken::IsFunction() const
73 return (eOp
!= ocPush
&& eOp
!= ocBad
&& eOp
!= ocColRowName
&&
74 eOp
!= ocColRowNameAuto
&& eOp
!= ocName
&& eOp
!= ocDBArea
&&
76 (GetByte() != 0 // x parameters
77 || (SC_OPCODE_START_NO_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_NO_PAR
) // no parameter
78 || FormulaCompiler::IsOpCodeJumpCommand( eOp
) // @ jump commands
79 || (SC_OPCODE_START_1_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_1_PAR
) // one parameter
80 || (SC_OPCODE_START_2_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_2_PAR
) // x parameters (cByte==0 in
82 || eOp
== ocMacro
|| eOp
== ocExternal
// macros, AddIns
83 || eOp
== ocAnd
|| eOp
== ocOr
// former binary, now x parameters
84 || (eOp
>= ocInternalBegin
&& eOp
<= ocInternalEnd
) // internal
89 sal_uInt8
FormulaToken::GetParamCount() const
91 if ( eOp
< SC_OPCODE_STOP_DIV
&& eOp
!= ocExternal
&& eOp
!= ocMacro
&&
92 !FormulaCompiler::IsOpCodeJumpCommand( eOp
) &&
93 eOp
!= ocPercentSign
)
94 return 0; // parameters and specials
95 // ocIf... jump commands not for FAP, have cByte then
96 //2do: bool parameter whether FAP or not?
98 return GetByte(); // all functions, also ocExternal and ocMacro
99 else if (SC_OPCODE_START_BIN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_BIN_OP
&& eOp
!= ocAnd
&& eOp
!= ocOr
)
100 return 2; // binary operators, compiler checked; OR and AND legacy but are functions
101 else if ((SC_OPCODE_START_UN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_UN_OP
) || eOp
== ocPercentSign
)
102 return 1; // unary operators, compiler checked
103 else if (SC_OPCODE_START_NO_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_NO_PAR
)
104 return 0; // no parameter
105 else if (FormulaCompiler::IsOpCodeJumpCommand( eOp
))
106 return 1; // only the condition counts as parameter
108 return 0; // all the rest, no Parameter, or
109 // if so then it should be in cByte
112 bool FormulaToken::IsExternalRef() const
117 case svExternalSingleRef
:
118 case svExternalDoubleRef
:
129 bool FormulaToken::IsRef() const
135 case svExternalSingleRef
:
136 case svExternalDoubleRef
:
139 if (eOp
== ocTableRef
)
146 bool FormulaToken::IsInForceArray() const
148 ParamClass eParam
= GetInForceArray();
149 return eParam
== ParamClass::ForceArray
|| eParam
== ParamClass::ReferenceOrForceArray
150 || eParam
== ParamClass::ReferenceOrRefArray
|| eParam
== ParamClass::ForceArrayReturn
;
153 bool FormulaToken::operator==( const FormulaToken
& rToken
) const
155 // don't compare reference count!
156 return eType
== rToken
.eType
&& GetOpCode() == rToken
.GetOpCode();
160 // --- virtual dummy methods -------------------------------------------------
162 sal_uInt8
FormulaToken::GetByte() const
164 // ok to be called for any derived class
168 void FormulaToken::SetByte( sal_uInt8
)
170 assert( !"virtual dummy called" );
173 ParamClass
FormulaToken::GetInForceArray() const
175 // ok to be called for any derived class
176 return (eOp
== ocPush
&& eType
== svMatrix
) ? ParamClass::ForceArrayReturn
: ParamClass::Unknown
;
179 void FormulaToken::SetInForceArray( ParamClass
)
181 assert( !"virtual dummy called" );
184 double FormulaToken::GetDouble() const
186 // This Get is worth an assert.
187 assert( !"virtual dummy called" );
191 double & FormulaToken::GetDoubleAsReference()
193 // This Get is worth an assert.
194 assert( !"virtual dummy called" );
195 static double fVal
= 0.0;
199 sal_Int16
FormulaToken::GetDoubleType() const
201 SAL_WARN( "formula.core", "FormulaToken::GetDoubleType: virtual dummy called" );
205 void FormulaToken::SetDoubleType( sal_Int16
)
207 assert( !"virtual dummy called" );
210 const svl::SharedString INVALID_STRING
;
212 const svl::SharedString
& FormulaToken::GetString() const
214 SAL_WARN( "formula.core", "FormulaToken::GetString: virtual dummy called" );
215 return INVALID_STRING
; // invalid string
218 void FormulaToken::SetString( const svl::SharedString
& )
220 assert( !"virtual dummy called" );
223 sal_uInt16
FormulaToken::GetIndex() const
225 SAL_WARN( "formula.core", "FormulaToken::GetIndex: virtual dummy called" );
229 void FormulaToken::SetIndex( sal_uInt16
)
231 assert( !"virtual dummy called" );
234 sal_Int16
FormulaToken::GetSheet() const
236 SAL_WARN( "formula.core", "FormulaToken::GetSheet: virtual dummy called" );
240 void FormulaToken::SetSheet( sal_Int16
)
242 assert( !"virtual dummy called" );
245 sal_Unicode
FormulaToken::GetChar() const
247 // This Get is worth an assert.
248 assert( !"virtual dummy called" );
252 short* FormulaToken::GetJump() const
254 SAL_WARN( "formula.core", "FormulaToken::GetJump: virtual dummy called" );
259 const OUString
& FormulaToken::GetExternal() const
261 SAL_WARN( "formula.core", "FormulaToken::GetExternal: virtual dummy called" );
262 static OUString aDummyString
;
266 FormulaToken
* FormulaToken::GetFAPOrigToken() const
268 SAL_WARN( "formula.core", "FormulaToken::GetFAPOrigToken: virtual dummy called" );
272 FormulaError
FormulaToken::GetError() const
274 SAL_WARN( "formula.core", "FormulaToken::GetError: virtual dummy called" );
275 return FormulaError::NONE
;
278 void FormulaToken::SetError( FormulaError
)
280 assert( !"virtual dummy called" );
283 const ScSingleRefData
* FormulaToken::GetSingleRef() const
285 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
289 ScSingleRefData
* FormulaToken::GetSingleRef()
291 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
295 const ScComplexRefData
* FormulaToken::GetDoubleRef() const
297 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
301 ScComplexRefData
* FormulaToken::GetDoubleRef()
303 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
307 const ScSingleRefData
* FormulaToken::GetSingleRef2() const
309 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
313 ScSingleRefData
* FormulaToken::GetSingleRef2()
315 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
319 const ScMatrix
* FormulaToken::GetMatrix() const
321 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
325 ScMatrix
* FormulaToken::GetMatrix()
327 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
331 ScJumpMatrix
* FormulaToken::GetJumpMatrix() const
333 OSL_FAIL( "FormulaToken::GetJumpMatrix: virtual dummy called" );
336 const std::vector
<ScComplexRefData
>* FormulaToken::GetRefList() const
338 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
342 std::vector
<ScComplexRefData
>* FormulaToken::GetRefList()
344 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
348 bool FormulaToken::TextEqual( const FormulaToken
& rToken
) const
350 return *this == rToken
;
353 // real implementations of virtual functions
356 sal_uInt8
FormulaSpaceToken::GetByte() const { return nByte
; }
357 sal_Unicode
FormulaSpaceToken::GetChar() const { return cChar
; }
358 bool FormulaSpaceToken::operator==( const FormulaToken
& r
) const
360 return FormulaToken::operator==( r
) && nByte
== r
.GetByte() &&
361 cChar
== r
.GetChar();
365 sal_uInt8
FormulaByteToken::GetByte() const { return nByte
; }
366 void FormulaByteToken::SetByte( sal_uInt8 n
) { nByte
= n
; }
367 ParamClass
FormulaByteToken::GetInForceArray() const { return eInForceArray
; }
368 void FormulaByteToken::SetInForceArray( ParamClass c
) { eInForceArray
= c
; }
369 bool FormulaByteToken::operator==( const FormulaToken
& r
) const
371 return FormulaToken::operator==( r
) && nByte
== r
.GetByte() &&
372 eInForceArray
== r
.GetInForceArray();
376 FormulaToken
* FormulaFAPToken::GetFAPOrigToken() const { return pOrigToken
.get(); }
377 bool FormulaFAPToken::operator==( const FormulaToken
& r
) const
379 return FormulaByteToken::operator==( r
) && pOrigToken
== r
.GetFAPOrigToken();
383 short* FormulaJumpToken::GetJump() const { return pJump
.get(); }
384 ParamClass
FormulaJumpToken::GetInForceArray() const { return eInForceArray
; }
385 void FormulaJumpToken::SetInForceArray( ParamClass c
) { eInForceArray
= c
; }
386 bool FormulaJumpToken::operator==( const FormulaToken
& r
) const
388 return FormulaToken::operator==( r
) && pJump
[0] == r
.GetJump()[0] &&
389 memcmp( pJump
.get()+1, r
.GetJump()+1, pJump
[0] * sizeof(short) ) == 0 &&
390 eInForceArray
== r
.GetInForceArray();
392 FormulaJumpToken::~FormulaJumpToken()
397 bool FormulaTokenArray::AddFormulaToken(
398 const sheet::FormulaToken
& rToken
, svl::SharedStringPool
& rSPool
, ExternalReferenceHelper
* /*pExtRef*/)
401 const OpCode eOpCode
= static_cast<OpCode
>(rToken
.OpCode
); //! assuming equal values for the moment
403 const uno::TypeClass eClass
= rToken
.Data
.getValueTypeClass();
406 case uno::TypeClass_VOID
:
407 // empty data -> use AddOpCode (does some special cases)
408 AddOpCode( eOpCode
);
410 case uno::TypeClass_DOUBLE
:
411 // double is only used for "push"
412 if ( eOpCode
== ocPush
)
413 AddDouble( rToken
.Data
.get
<double>() );
417 case uno::TypeClass_LONG
:
419 // long is svIndex, used for name / database area, or "byte" for spaces
420 sal_Int32 nValue
= rToken
.Data
.get
<sal_Int32
>();
421 if ( eOpCode
== ocDBArea
)
422 Add( new formula::FormulaIndexToken( eOpCode
, static_cast<sal_uInt16
>(nValue
) ) );
423 else if ( eOpCode
== ocTableRef
)
424 bError
= true; /* TODO: implementation */
425 else if ( eOpCode
== ocSpaces
)
426 Add( new formula::FormulaByteToken( ocSpaces
, static_cast<sal_uInt8
>(nValue
) ) );
431 case uno::TypeClass_STRING
:
433 OUString
aStrVal( rToken
.Data
.get
<OUString
>() );
434 if ( eOpCode
== ocPush
)
435 AddString(rSPool
.intern(aStrVal
));
436 else if ( eOpCode
== ocBad
)
438 else if ( eOpCode
== ocStringXML
)
439 AddStringXML( aStrVal
);
440 else if ( eOpCode
== ocExternal
|| eOpCode
== ocMacro
)
441 Add( new formula::FormulaExternalToken( eOpCode
, aStrVal
) );
442 else if ( eOpCode
== ocWhitespace
)
444 // Simply ignore empty string.
445 // Convention is one character repeated.
446 if (!aStrVal
.isEmpty())
447 Add( new formula::FormulaSpaceToken( static_cast<sal_uInt8
>(aStrVal
.getLength()), aStrVal
[0]));
450 bError
= true; // unexpected string: don't know what to do with it
455 } // switch ( eClass )
459 bool FormulaTokenArray::Fill(
460 const uno::Sequence
<sheet::FormulaToken
>& rSequence
,
461 svl::SharedStringPool
& rSPool
, ExternalReferenceHelper
* pExtRef
)
464 const sal_Int32 nCount
= rSequence
.getLength();
465 for (sal_Int32 nPos
=0; nPos
<nCount
; nPos
++)
467 bool bOneError
= AddFormulaToken(rSequence
[nPos
], rSPool
, pExtRef
);
470 AddOpCode( ocErrName
); // add something that indicates an error
477 void FormulaTokenArray::DelRPN()
481 FormulaToken
** p
= pRPN
;
482 for( sal_uInt16 i
= 0; i
< nRPN
; i
++ )
492 FormulaToken
* FormulaTokenArray::FirstToken() const
494 if (!pCode
|| nLen
== 0)
499 FormulaToken
* FormulaTokenArray::PeekPrev( sal_uInt16
& nIdx
) const
501 if (0 < nIdx
&& nIdx
<= nLen
)
502 return pCode
[--nIdx
];
506 FormulaToken
* FormulaTokenArray::FirstRPNToken() const
508 if (!pRPN
|| nRPN
== 0)
513 FormulaToken
* FormulaTokenArray::LastRPNToken() const
515 if (!pRPN
|| nRPN
== 0)
517 return pRPN
[nRPN
- 1];
520 bool FormulaTokenArray::HasReferences() const
522 for (auto i
: Tokens())
528 for (auto i
: RPNTokens())
537 bool FormulaTokenArray::HasExternalRef() const
539 for (auto i
: Tokens())
541 if (i
->IsExternalRef())
547 bool FormulaTokenArray::HasOpCode( OpCode eOp
) const
549 for (auto i
: Tokens())
551 if (i
->GetOpCode() == eOp
)
557 bool FormulaTokenArray::HasOpCodeRPN( OpCode eOp
) const
559 for (auto i
: RPNTokens())
561 if (i
->GetOpCode() == eOp
)
567 bool FormulaTokenArray::HasNameOrColRowName() const
569 for (auto i
: Tokens())
571 if (i
->GetType() == svIndex
|| i
->GetOpCode() == ocColRowName
)
577 bool FormulaTokenArray::HasOpCodes(const unordered_opcode_set
& rOpCodes
) const
579 for (auto i
: Tokens())
581 if (rOpCodes
.count(i
->GetOpCode()) > 0)
588 FormulaTokenArray::FormulaTokenArray() :
592 nError(FormulaError::NONE
),
593 nMode(ScRecalcMode::NORMAL
),
595 mbFromRangeName(false),
601 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray
& rArr
)
606 FormulaTokenArray::FormulaTokenArray( FormulaTokenArray
&& rArr
)
608 Move( std::move(rArr
) );
611 FormulaTokenArray::~FormulaTokenArray()
613 FormulaTokenArray::Clear();
616 void FormulaTokenArray::Finalize()
618 if( nLen
&& !mbFinalized
)
620 // Add() overallocates, so reallocate to the minimum needed size.
621 std::unique_ptr
<FormulaToken
*[]> newCode(new FormulaToken
*[ nLen
]);
622 std::copy(&pCode
[0], &pCode
[nLen
], newCode
.get());
623 pCode
= std::move( newCode
);
628 void FormulaTokenArray::Assign( const FormulaTokenArray
& r
)
634 bHyperLink
= r
.bHyperLink
;
635 mbFromRangeName
= r
.mbFromRangeName
;
636 mbShareable
= r
.mbShareable
;
637 mbFinalized
= r
.mbFinalized
;
643 pCode
.reset(new FormulaToken
*[ nLen
]);
645 memcpy( pp
, r
.pCode
.get(), nLen
* sizeof( FormulaToken
* ) );
646 for( sal_uInt16 i
= 0; i
< nLen
; i
++ )
652 pp
= pRPN
= new FormulaToken
*[ nRPN
];
653 memcpy( pp
, r
.pRPN
, nRPN
* sizeof( FormulaToken
* ) );
654 for( sal_uInt16 i
= 0; i
< nRPN
; i
++ )
659 void FormulaTokenArray::Move( FormulaTokenArray
&& r
)
661 pCode
= std::move(r
.pCode
);
670 bHyperLink
= r
.bHyperLink
;
671 mbFromRangeName
= r
.mbFromRangeName
;
672 mbShareable
= r
.mbShareable
;
673 mbFinalized
= r
.mbFinalized
;
676 /// Optimisation for efficiently creating StringXML placeholders
677 void FormulaTokenArray::Assign( sal_uInt16 nCode
, FormulaToken
**pTokens
)
680 assert( pCode
== nullptr );
683 pCode
.reset(new FormulaToken
*[ nLen
]);
686 for( sal_uInt16 i
= 0; i
< nLen
; i
++ )
688 FormulaToken
*t
= pTokens
[ i
];
689 assert( t
->GetOpCode() == ocStringXML
);
695 FormulaTokenArray
& FormulaTokenArray::operator=( const FormulaTokenArray
& rArr
)
705 FormulaTokenArray
& FormulaTokenArray::operator=( FormulaTokenArray
&& rArr
)
708 Move( std::move(rArr
) );
712 void FormulaTokenArray::Clear()
717 FormulaToken
** p
= pCode
.get();
718 for( sal_uInt16 i
= 0; i
< nLen
; i
++ )
725 nError
= FormulaError::NONE
;
728 mbFromRangeName
= false;
734 void FormulaTokenArray::CheckToken( const FormulaToken
& /*r*/ )
739 void FormulaTokenArray::CheckAllRPNTokens()
743 FormulaToken
** p
= pRPN
;
744 for( sal_uInt16 i
= 0; i
< nRPN
; i
++ )
746 CheckToken( *p
[ i
] );
751 FormulaToken
* FormulaTokenArray::AddToken( const FormulaToken
& r
)
753 return Add( r
.Clone() );
756 FormulaToken
* FormulaTokenArray::MergeArray( )
761 FormulaToken
* FormulaTokenArray::ReplaceToken( sal_uInt16 nOffset
, FormulaToken
* t
,
762 FormulaTokenArray::ReplaceMode eMode
)
768 FormulaToken
* p
= pCode
[nOffset
];
770 if (eMode
== CODE_AND_RPN
&& p
->GetRef() > 1)
772 for (sal_uInt16 i
=0; i
< nRPN
; ++i
)
779 if (p
->GetRef() == 1)
784 p
->DecRef(); // may be dead now
789 t
->DeleteIfZeroRef();
794 sal_uInt16
FormulaTokenArray::RemoveToken( sal_uInt16 nOffset
, sal_uInt16 nCount
)
798 SAL_WARN_IF( nOffset
+ nCount
> nLen
, "formula.core",
799 "FormulaTokenArray::RemoveToken - nOffset " << nOffset
<< " + nCount " << nCount
<< " > nLen " << nLen
);
800 const sal_uInt16 nStop
= ::std::min( static_cast<sal_uInt16
>(nOffset
+ nCount
), nLen
);
801 nCount
= nStop
- nOffset
;
802 for (sal_uInt16 j
= nOffset
; j
< nStop
; ++j
)
804 FormulaToken
* p
= pCode
[j
];
807 for (sal_uInt16 i
=0; i
< nRPN
; ++i
)
811 // Shift remaining tokens in pRPN down.
812 for (sal_uInt16 x
=i
+1; x
< nRPN
; ++x
)
819 if (p
->GetRef() == 1)
824 p
->DecRef(); // may be dead now
827 // Shift remaining tokens in pCode down.
828 for (sal_uInt16 x
= nStop
; x
< nLen
; ++x
)
830 pCode
[x
-nCount
] = pCode
[x
];
838 SAL_WARN("formula.core","FormulaTokenArray::RemoveToken - nOffset " << nOffset
<< " >= nLen " << nLen
);
843 FormulaToken
* FormulaTokenArray::Add( FormulaToken
* t
)
845 assert(!mbFinalized
);
848 t
->DeleteIfZeroRef();
852 // Allocating an array of size FORMULA_MAXTOKENS is simple, but that results in relatively large
853 // allocations that malloc() implementations usually do not handle as efficiently as smaller
854 // sizes (not only in terms of memory usage but also speed). Since most token arrays are going
855 // to be small, start with a small array and resize only if needed. Eventually Finalize() will
856 // reallocate the memory to size exactly matching the requirements.
857 const size_t MAX_FAST_TOKENS
= 32;
859 pCode
.reset(new FormulaToken
*[ MAX_FAST_TOKENS
]);
860 if( nLen
== MAX_FAST_TOKENS
)
862 FormulaToken
** tmp
= new FormulaToken
*[ FORMULA_MAXTOKENS
];
863 std::copy(&pCode
[0], &pCode
[MAX_FAST_TOKENS
], tmp
);
866 if( nLen
< FORMULA_MAXTOKENS
- 1 )
871 if( t
->GetOpCode() == ocArrayClose
)
877 t
->DeleteIfZeroRef();
878 if ( nLen
== FORMULA_MAXTOKENS
- 1 )
880 t
= new FormulaByteToken( ocStop
);
888 FormulaToken
* FormulaTokenArray::AddString( const svl::SharedString
& rStr
)
890 return Add( new FormulaStringToken( rStr
) );
893 FormulaToken
* FormulaTokenArray::AddDouble( double fVal
)
895 return Add( new FormulaDoubleToken( fVal
) );
898 void FormulaTokenArray::AddExternal( const sal_Unicode
* pStr
)
900 AddExternal( OUString( pStr
) );
903 FormulaToken
* FormulaTokenArray::AddExternal( const OUString
& rStr
,
904 OpCode eOp
/* = ocExternal */ )
906 return Add( new FormulaExternalToken( eOp
, rStr
) );
909 FormulaToken
* FormulaTokenArray::AddBad( const OUString
& rStr
)
911 return Add( new FormulaStringOpToken( ocBad
, svl::SharedString( rStr
) ) ); // string not interned
914 FormulaToken
* FormulaTokenArray::AddStringXML( const OUString
& rStr
)
916 return Add( new FormulaStringOpToken( ocStringXML
, svl::SharedString( rStr
) ) ); // string not interned
920 void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits
)
922 const unsigned nExclusive
= static_cast<sal_uInt8
>(nBits
& ScRecalcMode::EMask
);
926 if (nExclusive
& (nExclusive
- 1))
928 // More than one bit set, use highest priority.
929 for (nExBit
= 1; (nExBit
& static_cast<sal_uInt8
>(ScRecalcMode::EMask
)) != 0; nExBit
<<= 1)
931 if (nExclusive
& nExBit
)
937 // Only one bit is set.
940 // Set exclusive bit if priority is higher than existing.
941 if (nExBit
< static_cast<sal_uInt8
>(nMode
& ScRecalcMode::EMask
))
942 SetMaskedRecalcMode( static_cast<ScRecalcMode
>(nExBit
));
944 SetCombinedBitsRecalcMode( nBits
);
948 bool FormulaTokenArray::HasMatrixDoubleRefOps() const
950 if ( !pRPN
|| !nRPN
)
953 // RPN-Interpreter simulation.
954 // Simply assumes a double as return value of each function.
955 std::unique_ptr
<FormulaToken
*[]> pStack(new FormulaToken
* [nRPN
]);
956 FormulaToken
* pResult
= new FormulaDoubleToken( 0.0 );
958 for ( auto t
: RPNTokens() )
960 OpCode eOp
= t
->GetOpCode();
961 sal_uInt8 nParams
= t
->GetParamCount();
976 case ocGreaterEqual
:
978 for ( sal_uInt8 k
= nParams
; k
; k
-- )
980 if ( sp
>= k
&& pStack
[sp
-k
]->GetType() == svDoubleRef
)
990 // added to avoid warnings
993 if ( eOp
== ocPush
|| lcl_IsReference( eOp
, t
->GetType() ) )
995 else if (FormulaCompiler::IsOpCodeJumpCommand( eOp
))
996 { // ignore Jumps, pop previous Result (Condition)
1001 { // pop parameters, push result
1002 sp
= sal::static_int_cast
<short>( sp
- nParams
);
1005 SAL_WARN("formula.core", "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
1008 pStack
[sp
++] = pResult
;
1016 // --- Formula rewrite of a token array
1018 inline bool MissingConventionODF::isRewriteNeeded( OpCode eOp
) const
1031 return isPODF(); // rewrite only for PODF
1034 return isODFF(); // rewrite only for ODFF
1042 To be implemented yet:
1047 inline bool MissingConventionOOXML::isRewriteNeeded( OpCode eOp
)
1085 class FormulaMissingContext
1088 const FormulaToken
* mpFunc
;
1091 void Clear() { mpFunc
= nullptr; mnCurArg
= 0; }
1092 inline bool AddDefaultArg( FormulaTokenArray
* pNewArr
, int nArg
, double f
) const;
1093 bool AddMissingExternal( FormulaTokenArray
* pNewArr
) const;
1094 bool AddMissing( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const;
1095 void AddMoreArgs( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const;
1100 void FormulaMissingContext::AddMoreArgs( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const
1105 switch (rConv
.getConvention())
1107 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF
:
1108 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF
:
1110 switch (mpFunc
->GetOpCode())
1115 pNewArr
->AddOpCode( ocSep
);
1116 pNewArr
->AddDouble( 1.0 ); // 4th, Cumulative=true()
1122 pNewArr
->AddOpCode( ocSep
);
1123 pNewArr
->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1127 if ( mnCurArg
== 2 )
1129 pNewArr
->AddOpCode( ocSep
);
1130 pNewArr
->AddDouble( 1.0 ); // 4th, Cumulative=true()
1135 if ( mnCurArg
== 0 )
1137 pNewArr
->AddOpCode( ocSep
);
1138 pNewArr
->AddDouble( 0.0 ); // 2nd, mean = 0.0
1140 if ( mnCurArg
<= 1 )
1142 pNewArr
->AddOpCode( ocSep
);
1143 pNewArr
->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1147 if ( rConv
.isPODF() && mnCurArg
== 0 )
1149 pNewArr
->AddOpCode( ocSep
);
1150 pNewArr
->AddDouble( 10.0 ); // 2nd, basis 10
1158 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML
:
1160 switch (mpFunc
->GetOpCode())
1165 // Excel needs at least two parameters in IF function
1166 pNewArr
->AddOpCode( ocSep
);
1167 pNewArr
->AddOpCode( ocTrue
); // 2nd, true() as function
1168 pNewArr
->AddOpCode( ocOpen
); // so the result is of logical type
1169 pNewArr
->AddOpCode( ocClose
); // and survives roundtrip
1174 if ( mnCurArg
== 2 )
1176 pNewArr
->AddOpCode( ocSep
);
1177 pNewArr
->AddDouble( 0.0 ); // 4th, FullPrecision = false()
1184 pNewArr
->AddOpCode( ocSep
);
1185 pNewArr
->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1194 pNewArr
->AddOpCode( ocSep
);
1195 pNewArr
->AddDouble( 1.0 ); // 4th, Cumulative=true()
1201 if ( mnCurArg
== 0 )
1203 pNewArr
->AddOpCode( ocSep
);
1204 pNewArr
->AddDouble( 0.0 ); // 2nd, mean = 0.0
1206 if ( mnCurArg
<= 1 )
1208 pNewArr
->AddOpCode( ocSep
);
1209 pNewArr
->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1214 if ( mnCurArg
== 3 )
1216 pNewArr
->AddOpCode( ocSep
);
1217 pNewArr
->AddDouble( 0.0 ); // 5th, Cumulative = false()
1226 // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel
1227 pNewArr
->AddOpCode( ocSep
);
1228 pNewArr
->AddDouble( 0.0 ); // 2nd, 0.0
1241 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray
* pNewArr
, int nArg
, double f
) const
1243 if (mnCurArg
== nArg
)
1245 pNewArr
->AddDouble( f
);
1251 bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray
*pNewArr
) const
1253 // Only called for PODF, not ODFF. No need to distinguish.
1255 const OUString
&rName
= mpFunc
->GetExternal();
1257 // initial (fast) checks:
1258 sal_Int32 nLength
= rName
.getLength();
1262 sal_Unicode nLastChar
= rName
[ nLength
- 1];
1263 if ( nLastChar
!= 't' && nLastChar
!= 'm' )
1266 if (rName
.equalsIgnoreAsciiCase(
1267 "com.sun.star.sheet.addin.Analysis.getAccrint" ))
1269 return AddDefaultArg( pNewArr
, 4, 1000.0 );
1271 if (rName
.equalsIgnoreAsciiCase(
1272 "com.sun.star.sheet.addin.Analysis.getAccrintm" ))
1274 return AddDefaultArg( pNewArr
, 3, 1000.0 );
1279 bool FormulaMissingContext::AddMissing( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const
1285 const OpCode eOp
= mpFunc
->GetOpCode();
1287 switch (rConv
.getConvention())
1289 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF
:
1295 return AddDefaultArg( pNewArr
, 2, 1.0 ); // abs
1301 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF
:
1307 return AddDefaultArg( pNewArr
, 2, 1.0 ); // abs
1309 return AddDefaultArg( pNewArr
, 1, 2.0 );
1313 return AddDefaultArg( pNewArr
, 3, 0.0 );
1316 return AddDefaultArg( pNewArr
, 4, 0.0 );
1319 bRet
|= AddDefaultArg( pNewArr
, 2, 0.0 ); // pmt
1320 bRet
|= AddDefaultArg( pNewArr
, 3, 0.0 ); // [fp]v
1323 bRet
|= AddDefaultArg( pNewArr
, 1, 0.0 ); // pmt
1324 bRet
|= AddDefaultArg( pNewArr
, 3, 0.0 ); // fv
1325 bRet
|= AddDefaultArg( pNewArr
, 4, 0.0 ); // type
1328 return AddMissingExternal( pNewArr
);
1330 // --- more complex cases ---
1333 // FIXME: rather tough
1334 // if arg 3 (height) omitted, export arg1 (rows)
1341 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML
:
1346 return AddMissingExternal( pNewArr
);
1357 bool FormulaTokenArray::NeedsPodfRewrite( const MissingConventionODF
& rConv
)
1359 for ( auto i
: Tokens() )
1361 if ( rConv
.isRewriteNeeded( i
->GetOpCode()))
1367 bool FormulaTokenArray::NeedsOoxmlRewrite()
1369 for ( auto i
: Tokens() )
1371 if ( MissingConventionOOXML::isRewriteNeeded( i
->GetOpCode()))
1378 FormulaTokenArray
* FormulaTokenArray::RewriteMissing( const MissingConvention
& rConv
)
1380 const size_t nAlloc
= 256;
1381 FormulaMissingContext aCtx
[ nAlloc
];
1383 /* TODO: with some effort we might be able to merge the two almost
1384 * identical function stacks into one and generalize things, otherwise
1385 * adding yet another "omit argument" would be copypasta. */
1387 int aOpCodeAddressStack
[ nAlloc
]; // use of ADDRESS() function
1388 const int nOmitAddressArg
= 3; // ADDRESS() 4th parameter A1/R1C1
1390 int aOpCodeDcountStack
[ nAlloc
]; // use of DCOUNT()/DCOUNTA() function
1391 const int nOmitDcountArg
= 1; // DCOUNT() and DCOUNTA() 2nd parameter DatabaseField if 0
1393 sal_uInt16 nTokens
= GetLen() + 1;
1394 FormulaMissingContext
* pCtx
= (nAlloc
< nTokens
? new FormulaMissingContext
[nTokens
] : &aCtx
[0]);
1395 int* pOcas
= (nAlloc
< nTokens
? new int[nTokens
] : &aOpCodeAddressStack
[0]);
1396 int* pOcds
= (nAlloc
< nTokens
? new int[nTokens
] : &aOpCodeDcountStack
[0]);
1397 // Never go below 0, never use 0, mpFunc always NULL.
1403 FormulaTokenArray
*pNewArr
= new FormulaTokenArray
;
1404 // At least ScRecalcMode::ALWAYS needs to be set.
1405 pNewArr
->AddRecalcMode( GetRecalcMode());
1407 FormulaTokenArrayPlainIterator
aIter(*this);
1408 for ( FormulaToken
*pCur
= aIter
.First(); pCur
; pCur
= aIter
.Next() )
1411 // Don't write the expression of the new inserted ADDRESS() parameter.
1412 // Do NOT omit the new second parameter of INDIRECT() though. If that
1413 // was done for both, INDIRECT() actually could calculate different and
1414 // valid (but wrong) results with the then changed return value of
1415 // ADDRESS(). Better let it generate an error instead.
1416 for (int i
= nOcas
; i
-- > 0 && bAdd
; )
1418 if (pCtx
[ pOcas
[ i
] ].mnCurArg
== nOmitAddressArg
)
1420 // Omit everything except a trailing separator, the leading
1421 // separator is omitted below. The other way around would leave
1422 // an extraneous separator if no parameter followed.
1423 if (pOcas
[ i
] != nFn
|| pCur
->GetOpCode() != ocSep
)
1427 // Strip the 2nd argument (leaving empty) of DCOUNT() and DCOUNTA() if
1429 for (int i
= nOcds
; i
-- > 0 && bAdd
; )
1431 if (pCtx
[ pOcds
[ i
] ].mnCurArg
== nOmitDcountArg
)
1433 // Omit only a literal 0 value, nothing else.
1434 if (pOcds
[ i
] == nFn
&& pCur
->GetOpCode() == ocPush
&& pCur
->GetType() == svDouble
&&
1435 pCur
->GetDouble() == 0.0)
1437 // No other expression, between separators.
1438 FormulaToken
* p
= aIter
.PeekPrevNoSpaces();
1439 if (p
&& p
->GetOpCode() == ocSep
)
1441 p
= aIter
.PeekNextNoSpaces();
1442 if (p
&& p
->GetOpCode() == ocSep
)
1448 switch ( pCur
->GetOpCode() )
1452 ++nFn
; // all following operations on _that_ function
1453 pCtx
[ nFn
].mpFunc
= aIter
.PeekPrevNoSpaces();
1454 pCtx
[ nFn
].mnCurArg
= 0;
1455 if (rConv
.isPODF() && pCtx
[ nFn
].mpFunc
&& pCtx
[ nFn
].mpFunc
->GetOpCode() == ocAddress
)
1456 pOcas
[ nOcas
++ ] = nFn
; // entering ADDRESS() if PODF
1457 else if ((rConv
.isODFF() || rConv
.isOOXML()) && pCtx
[ nFn
].mpFunc
)
1459 OpCode eOp
= pCtx
[ nFn
].mpFunc
->GetOpCode();
1460 if (eOp
== ocDBCount
|| eOp
== ocDBCount2
)
1461 pOcds
[ nOcds
++ ] = nFn
; // entering DCOUNT() or DCOUNTA() if ODFF or OOXML
1466 pCtx
[ nFn
].AddMoreArgs( pNewArr
, rConv
);
1467 SAL_WARN_IF(nFn
<= 0, "formula.core", "FormulaTokenArray::RewriteMissing: underflow");
1468 if (nOcas
> 0 && pOcas
[ nOcas
-1 ] == nFn
)
1469 --nOcas
; // leaving ADDRESS()
1470 else if (nOcds
> 0 && pOcds
[ nOcds
-1 ] == nFn
)
1471 --nOcds
; // leaving DCOUNT() or DCOUNTA()
1476 pCtx
[ nFn
].mnCurArg
++;
1477 // Omit leading separator of ADDRESS() parameter.
1478 if (nOcas
&& pOcas
[ nOcas
-1 ] == nFn
&& pCtx
[ nFn
].mnCurArg
== nOmitAddressArg
)
1485 bAdd
= !pCtx
[ nFn
].AddMissing( pNewArr
, rConv
);
1492 OpCode eOp
= pCur
->GetOpCode();
1493 if ( ( eOp
== ocCeil
|| eOp
== ocFloor
||
1494 ( eOp
== ocLogNormDist
&& pCur
->GetByte() == 4 ) ) &&
1495 rConv
.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML
)
1505 case ocLogNormDist
:
1506 eOp
= ocLogNormDist_MS
;
1512 FormulaToken
*pToken
= new FormulaToken( svByte
, eOp
);
1513 pNewArr
->Add( pToken
);
1515 else if ( eOp
== ocHypGeomDist
&&
1516 rConv
.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML
)
1518 FormulaToken
*pToken
= new FormulaToken( svByte
, ocHypGeomDist_MS
);
1519 pNewArr
->Add( pToken
);
1522 pNewArr
->AddToken( *pCur
);
1526 if (pOcds
!= &aOpCodeDcountStack
[0])
1528 if (pOcas
!= &aOpCodeAddressStack
[0])
1530 if (pCtx
!= &aCtx
[0])
1537 inline bool isWhitespace( OpCode eOp
) { return eOp
== ocSpaces
|| eOp
== ocWhitespace
; }
1540 bool FormulaTokenArray::MayReferenceFollow()
1542 if ( !pCode
|| nLen
<= 0 )
1545 // ignore trailing spaces
1546 sal_uInt16 i
= nLen
- 1;
1547 while (i
> 0 && isWhitespace( pCode
[i
]->GetOpCode()))
1551 if (i
> 0 || !isWhitespace( pCode
[i
]->GetOpCode()))
1553 OpCode eOp
= pCode
[i
]->GetOpCode();
1554 if ( (SC_OPCODE_START_BIN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_BIN_OP
) ||
1555 (SC_OPCODE_START_UN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_UN_OP
) ||
1556 eOp
== SC_OPCODE_OPEN
|| eOp
== SC_OPCODE_SEP
)
1563 FormulaToken
* FormulaTokenArray::AddOpCode( OpCode eOp
)
1565 FormulaToken
* pRet
= nullptr;
1575 pRet
= new FormulaToken( svSep
,eOp
);
1582 short nJump
[FORMULA_MAXJUMPCOUNT
+ 1];
1585 else if ( eOp
== ocChoose
)
1586 nJump
[ 0 ] = FORMULA_MAXJUMPCOUNT
+ 1;
1589 pRet
= new FormulaJumpToken( eOp
, nJump
);
1593 pRet
= new FormulaByteToken( eOp
, 0, ParamClass::Unknown
);
1599 void FormulaTokenArray::ReinternStrings( svl::SharedStringPool
& rPool
)
1601 for (auto i
: Tokens())
1603 switch (i
->GetType())
1606 i
->SetString( rPool
.intern( i
->GetString().getString()));
1615 /*----------------------------------------------------------------------*/
1617 FormulaTokenIterator::Item::Item(const FormulaTokenArray
* pArray
, short pc
, short stop
) :
1618 pArr(pArray
), nPC(pc
), nStop(stop
)
1622 FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray
& rArr
)
1623 : maStack
{ FormulaTokenIterator::Item(&rArr
, -1, SHRT_MAX
) }
1627 FormulaTokenIterator::~FormulaTokenIterator()
1631 void FormulaTokenIterator::Push( const FormulaTokenArray
* pArr
)
1633 FormulaTokenIterator::Item
item(pArr
, -1, SHRT_MAX
);
1635 maStack
.push_back(item
);
1638 void FormulaTokenIterator::Pop()
1643 void FormulaTokenIterator::Reset()
1645 while( maStack
.size() > 1 )
1648 maStack
.back().nPC
= -1;
1651 FormulaToken
* FormulaTokenArrayPlainIterator::GetNextName()
1653 if( mpFTA
->GetArray() )
1655 while ( mnIndex
< mpFTA
->GetLen() )
1657 FormulaToken
* t
= mpFTA
->GetArray()[ mnIndex
++ ];
1658 if( t
->GetType() == svIndex
)
1665 const FormulaToken
* FormulaTokenIterator::Next()
1667 const FormulaToken
* t
= GetNonEndOfPathToken( ++maStack
.back().nPC
);
1668 if( !t
&& maStack
.size() > 1 )
1676 const FormulaToken
* FormulaTokenIterator::PeekNextOperator()
1678 const FormulaToken
* t
= nullptr;
1679 short nIdx
= maStack
.back().nPC
;
1682 t
= GetNonEndOfPathToken( ++nIdx
);
1683 if (t
== nullptr || t
->GetOpCode() != ocPush
)
1684 break; // ignore operands
1686 if (!t
&& maStack
.size() > 1)
1688 FormulaTokenIterator::Item aHere
= maStack
.back();
1690 t
= PeekNextOperator();
1691 maStack
.push_back(aHere
);
1696 //! The nPC counts after a Push() are -1
1698 void FormulaTokenIterator::Jump( short nStart
, short nNext
, short nStop
)
1700 maStack
.back().nPC
= nNext
;
1701 if( nStart
!= nNext
)
1703 Push( maStack
.back().pArr
);
1704 maStack
.back().nPC
= nStart
;
1705 maStack
.back().nStop
= nStop
;
1709 void FormulaTokenIterator::ReInit( const FormulaTokenArray
& rArr
)
1715 const FormulaToken
* FormulaTokenIterator::GetNonEndOfPathToken( short nIdx
) const
1717 FormulaTokenIterator::Item cur
= maStack
.back();
1719 if (nIdx
< cur
.pArr
->GetCodeLen() && nIdx
< cur
.nStop
)
1721 const FormulaToken
* t
= cur
.pArr
->GetCode()[ nIdx
];
1722 // such an OpCode ends an IF() or CHOOSE() path
1723 return (t
->GetOpCode() == ocSep
|| t
->GetOpCode() == ocClose
) ? nullptr : t
;
1728 bool FormulaTokenIterator::IsEndOfPath() const
1730 return GetNonEndOfPathToken( maStack
.back().nPC
+ 1) == nullptr;
1733 FormulaToken
* FormulaTokenArrayPlainIterator::GetNextReference()
1735 while( mnIndex
< mpFTA
->GetLen() )
1737 FormulaToken
* t
= mpFTA
->GetArray()[ mnIndex
++ ];
1738 switch( t
->GetType() )
1742 case svExternalSingleRef
:
1743 case svExternalDoubleRef
:
1747 // added to avoid warnings
1754 FormulaToken
* FormulaTokenArrayPlainIterator::GetNextColRowName()
1756 while( mnIndex
< mpFTA
->GetLen() )
1758 FormulaToken
* t
= mpFTA
->GetArray()[ mnIndex
++ ];
1759 if ( t
->GetOpCode() == ocColRowName
)
1765 FormulaToken
* FormulaTokenArrayPlainIterator::GetNextReferenceRPN()
1767 while( mnIndex
< mpFTA
->GetCodeLen() )
1769 FormulaToken
* t
= mpFTA
->GetCode()[ mnIndex
++ ];
1770 switch( t
->GetType() )
1774 case svExternalSingleRef
:
1775 case svExternalDoubleRef
:
1779 // added to avoid warnings
1786 FormulaToken
* FormulaTokenArrayPlainIterator::GetNextReferenceOrName()
1788 if( !mpFTA
->GetArray() )
1791 while ( mnIndex
< mpFTA
->GetLen() )
1793 FormulaToken
* t
= mpFTA
->GetArray()[ mnIndex
++ ];
1794 switch( t
->GetType() )
1799 case svExternalSingleRef
:
1800 case svExternalDoubleRef
:
1801 case svExternalName
:
1805 // added to avoid warnings
1812 FormulaToken
* FormulaTokenArrayPlainIterator::Next()
1814 if( mpFTA
->GetArray() && mnIndex
< mpFTA
->GetLen() )
1815 return mpFTA
->GetArray()[ mnIndex
++ ];
1820 FormulaToken
* FormulaTokenArrayPlainIterator::NextNoSpaces()
1822 if( mpFTA
->GetArray() )
1824 while ((mnIndex
< mpFTA
->GetLen()) && isWhitespace( mpFTA
->GetArray()[ mnIndex
]->GetOpCode()))
1826 if( mnIndex
< mpFTA
->GetLen() )
1827 return mpFTA
->GetArray()[ mnIndex
++ ];
1832 FormulaToken
* FormulaTokenArrayPlainIterator::NextRPN()
1834 if( mpFTA
->GetCode() && mnIndex
< mpFTA
->GetCodeLen() )
1835 return mpFTA
->GetCode()[ mnIndex
++ ];
1840 FormulaToken
* FormulaTokenArrayPlainIterator::PrevRPN()
1842 if( mpFTA
->GetCode() && mnIndex
)
1843 return mpFTA
->GetCode()[ --mnIndex
];
1848 FormulaToken
* FormulaTokenArrayPlainIterator::PeekNext()
1850 if( mpFTA
->GetArray() && mnIndex
< mpFTA
->GetLen() )
1851 return mpFTA
->GetArray()[ mnIndex
];
1856 FormulaToken
* FormulaTokenArrayPlainIterator::PeekNextNoSpaces() const
1858 if( mpFTA
->GetArray() && mnIndex
< mpFTA
->GetLen() )
1860 sal_uInt16 j
= mnIndex
;
1861 while (j
< mpFTA
->GetLen() && isWhitespace( mpFTA
->GetArray()[j
]->GetOpCode()))
1863 if ( j
< mpFTA
->GetLen() )
1864 return mpFTA
->GetArray()[ j
];
1872 FormulaToken
* FormulaTokenArrayPlainIterator::PeekPrevNoSpaces() const
1874 if( mpFTA
->GetArray() && mnIndex
> 1 )
1876 sal_uInt16 j
= mnIndex
- 2;
1877 while (isWhitespace( mpFTA
->GetArray()[j
]->GetOpCode()) && j
> 0 )
1879 if (j
> 0 || !isWhitespace( mpFTA
->GetArray()[j
]->GetOpCode()))
1880 return mpFTA
->GetArray()[ j
];
1888 void FormulaTokenArrayPlainIterator::AfterRemoveToken( sal_uInt16 nOffset
, sal_uInt16 nCount
)
1890 const sal_uInt16 nStop
= std::min( static_cast<sal_uInt16
>(nOffset
+ nCount
), mpFTA
->GetLen());
1892 if (mnIndex
>= nOffset
)
1894 if (mnIndex
< nStop
)
1895 mnIndex
= nOffset
+ 1;
1897 mnIndex
-= nStop
- nOffset
;
1901 // real implementations of virtual functions
1904 double FormulaDoubleToken::GetDouble() const { return fDouble
; }
1905 double & FormulaDoubleToken::GetDoubleAsReference() { return fDouble
; }
1907 sal_Int16
FormulaDoubleToken::GetDoubleType() const
1909 // This is a plain double value without type information, don't emit a
1910 // warning via FormulaToken::GetDoubleType().
1914 bool FormulaDoubleToken::operator==( const FormulaToken
& r
) const
1916 return FormulaToken::operator==( r
) && fDouble
== r
.GetDouble();
1919 sal_Int16
FormulaTypedDoubleToken::GetDoubleType() const
1924 void FormulaTypedDoubleToken::SetDoubleType( sal_Int16 nType
)
1929 bool FormulaTypedDoubleToken::operator==( const FormulaToken
& r
) const
1931 return FormulaDoubleToken::operator==( r
) && mnType
== r
.GetDoubleType();
1934 FormulaStringToken::FormulaStringToken( svl::SharedString r
) :
1935 FormulaToken( svString
), maString(std::move( r
))
1939 FormulaStringToken::FormulaStringToken( const FormulaStringToken
& r
) :
1940 FormulaToken( r
), maString( r
.maString
) {}
1942 FormulaToken
* FormulaStringToken::Clone() const
1944 return new FormulaStringToken(*this);
1947 const svl::SharedString
& FormulaStringToken::GetString() const
1952 void FormulaStringToken::SetString( const svl::SharedString
& rStr
)
1957 bool FormulaStringToken::operator==( const FormulaToken
& r
) const
1959 return FormulaToken::operator==( r
) && maString
== r
.GetString();
1962 FormulaStringOpToken::FormulaStringOpToken( OpCode e
, svl::SharedString r
) :
1963 FormulaByteToken( e
, 0, svString
, ParamClass::Unknown
), maString(std::move( r
)) {}
1965 FormulaStringOpToken::FormulaStringOpToken( const FormulaStringOpToken
& r
) :
1966 FormulaByteToken( r
), maString( r
.maString
) {}
1968 FormulaToken
* FormulaStringOpToken::Clone() const
1970 return new FormulaStringOpToken(*this);
1973 const svl::SharedString
& FormulaStringOpToken::GetString() const
1978 void FormulaStringOpToken::SetString( const svl::SharedString
& rStr
)
1983 bool FormulaStringOpToken::operator==( const FormulaToken
& r
) const
1985 return FormulaByteToken::operator==( r
) && maString
== r
.GetString();
1988 sal_uInt16
FormulaIndexToken::GetIndex() const { return nIndex
; }
1989 void FormulaIndexToken::SetIndex( sal_uInt16 n
) { nIndex
= n
; }
1990 sal_Int16
FormulaIndexToken::GetSheet() const { return mnSheet
; }
1991 void FormulaIndexToken::SetSheet( sal_Int16 n
) { mnSheet
= n
; }
1992 bool FormulaIndexToken::operator==( const FormulaToken
& r
) const
1994 return FormulaToken::operator==( r
) && nIndex
== r
.GetIndex() &&
1995 mnSheet
== r
.GetSheet();
1997 const OUString
& FormulaExternalToken::GetExternal() const { return aExternal
; }
1998 bool FormulaExternalToken::operator==( const FormulaToken
& r
) const
2000 return FormulaByteToken::operator==( r
) && aExternal
== r
.GetExternal();
2004 FormulaError
FormulaErrorToken::GetError() const { return nError
; }
2005 void FormulaErrorToken::SetError( FormulaError nErr
) { nError
= nErr
; }
2006 bool FormulaErrorToken::operator==( const FormulaToken
& r
) const
2008 return FormulaToken::operator==( r
) &&
2009 nError
== static_cast< const FormulaErrorToken
& >(r
).GetError();
2011 double FormulaMissingToken::GetDouble() const { return 0.0; }
2013 const svl::SharedString
& FormulaMissingToken::GetString() const
2015 return svl::SharedString::getEmptyString();
2018 bool FormulaMissingToken::operator==( const FormulaToken
& r
) const
2020 return FormulaToken::operator==( r
);
2024 bool FormulaUnknownToken::operator==( const FormulaToken
& r
) const
2026 return FormulaToken::operator==( r
);
2033 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */