tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / formula / source / core / api / token.cxx
blob1167b3ebcd0d72053eec2a07a03685af1587b3e7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include <algorithm>
23 #include <string.h>
24 #include <limits.h>
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>
35 #include <memory>
36 #include <utility>
38 namespace formula
40 using namespace com::sun::star;
43 // --- helpers --------------------------------------------------------------
45 static bool lcl_IsReference( OpCode eOp, StackVar eType )
47 return
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 &&
75 eOp != ocTableRef &&
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
81 // FuncAutoPilot)
82 || eOp == ocMacro || eOp == ocExternal // macros, AddIns
83 || eOp == ocAnd || eOp == ocOr // former binary, now x parameters
84 || (eOp >= ocInternalBegin && eOp <= ocInternalEnd) // internal
85 ));
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?
97 else if (GetByte())
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
107 else
108 return 0; // all the rest, no Parameter, or
109 // if so then it should be in cByte
112 bool FormulaToken::IsExternalRef() const
114 bool bRet = false;
115 switch (eType)
117 case svExternalSingleRef:
118 case svExternalDoubleRef:
119 case svExternalName:
120 bRet = true;
121 break;
122 default:
123 bRet = false;
124 break;
126 return bRet;
129 bool FormulaToken::IsRef() const
131 switch (eType)
133 case svSingleRef:
134 case svDoubleRef:
135 case svExternalSingleRef:
136 case svExternalDoubleRef:
137 return true;
138 default:
139 if (eOp == ocTableRef)
140 return true;
143 return false;
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
165 return 0;
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" );
188 return 0.0;
191 void FormulaToken::SetDouble(double)
193 // This Get is worth an assert.
194 assert( !"virtual dummy called" );
197 sal_Int16 FormulaToken::GetDoubleType() const
199 SAL_WARN( "formula.core", "FormulaToken::GetDoubleType: virtual dummy called" );
200 return 0;
203 void FormulaToken::SetDoubleType( sal_Int16 )
205 assert( !"virtual dummy called" );
208 const svl::SharedString INVALID_STRING;
210 const svl::SharedString & FormulaToken::GetString() const
212 SAL_WARN( "formula.core", "FormulaToken::GetString: virtual dummy called" );
213 return INVALID_STRING; // invalid string
216 void FormulaToken::SetString( const svl::SharedString& )
218 assert( !"virtual dummy called" );
221 sal_uInt16 FormulaToken::GetIndex() const
223 SAL_WARN( "formula.core", "FormulaToken::GetIndex: virtual dummy called" );
224 return 0;
227 void FormulaToken::SetIndex( sal_uInt16 )
229 assert( !"virtual dummy called" );
232 sal_Int16 FormulaToken::GetSheet() const
234 SAL_WARN( "formula.core", "FormulaToken::GetSheet: virtual dummy called" );
235 return -1;
238 void FormulaToken::SetSheet( sal_Int16 )
240 assert( !"virtual dummy called" );
243 sal_Unicode FormulaToken::GetChar() const
245 // This Get is worth an assert.
246 assert( !"virtual dummy called" );
247 return 0;
250 short* FormulaToken::GetJump() const
252 SAL_WARN( "formula.core", "FormulaToken::GetJump: virtual dummy called" );
253 return nullptr;
257 const OUString& FormulaToken::GetExternal() const
259 SAL_WARN( "formula.core", "FormulaToken::GetExternal: virtual dummy called" );
260 static OUString aDummyString;
261 return aDummyString;
264 FormulaToken* FormulaToken::GetFAPOrigToken() const
266 SAL_WARN( "formula.core", "FormulaToken::GetFAPOrigToken: virtual dummy called" );
267 return nullptr;
270 FormulaError FormulaToken::GetError() const
272 SAL_WARN( "formula.core", "FormulaToken::GetError: virtual dummy called" );
273 return FormulaError::NONE;
276 void FormulaToken::SetError( FormulaError )
278 assert( !"virtual dummy called" );
281 const ScSingleRefData* FormulaToken::GetSingleRef() const
283 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
284 return nullptr;
287 ScSingleRefData* FormulaToken::GetSingleRef()
289 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
290 return nullptr;
293 const ScComplexRefData* FormulaToken::GetDoubleRef() const
295 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
296 return nullptr;
299 ScComplexRefData* FormulaToken::GetDoubleRef()
301 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
302 return nullptr;
305 const ScSingleRefData* FormulaToken::GetSingleRef2() const
307 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
308 return nullptr;
311 ScSingleRefData* FormulaToken::GetSingleRef2()
313 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
314 return nullptr;
317 const ScMatrix* FormulaToken::GetMatrix() const
319 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
320 return nullptr;
323 ScMatrix* FormulaToken::GetMatrix()
325 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
326 return nullptr;
329 ScJumpMatrix* FormulaToken::GetJumpMatrix() const
331 OSL_FAIL( "FormulaToken::GetJumpMatrix: virtual dummy called" );
332 return nullptr;
334 const std::vector<ScComplexRefData>* FormulaToken::GetRefList() const
336 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
337 return nullptr;
340 std::vector<ScComplexRefData>* FormulaToken::GetRefList()
342 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
343 return nullptr;
346 bool FormulaToken::TextEqual( const FormulaToken& rToken ) const
348 return *this == rToken;
351 // real implementations of virtual functions
354 sal_uInt8 FormulaSpaceToken::GetByte() const { return nByte; }
355 sal_Unicode FormulaSpaceToken::GetChar() const { return cChar; }
356 bool FormulaSpaceToken::operator==( const FormulaToken& r ) const
358 return FormulaToken::operator==( r ) && nByte == r.GetByte() &&
359 cChar == r.GetChar();
363 sal_uInt8 FormulaByteToken::GetByte() const { return nByte; }
364 void FormulaByteToken::SetByte( sal_uInt8 n ) { nByte = n; }
365 ParamClass FormulaByteToken::GetInForceArray() const { return eInForceArray; }
366 void FormulaByteToken::SetInForceArray( ParamClass c ) { eInForceArray = c; }
367 bool FormulaByteToken::operator==( const FormulaToken& r ) const
369 return FormulaToken::operator==( r ) && nByte == r.GetByte() &&
370 eInForceArray == r.GetInForceArray();
374 FormulaToken* FormulaFAPToken::GetFAPOrigToken() const { return pOrigToken.get(); }
375 bool FormulaFAPToken::operator==( const FormulaToken& r ) const
377 return FormulaByteToken::operator==( r ) && pOrigToken == r.GetFAPOrigToken();
381 short* FormulaJumpToken::GetJump() const { return pJump.get(); }
382 ParamClass FormulaJumpToken::GetInForceArray() const { return eInForceArray; }
383 void FormulaJumpToken::SetInForceArray( ParamClass c ) { eInForceArray = c; }
384 bool FormulaJumpToken::operator==( const FormulaToken& r ) const
386 return FormulaToken::operator==( r ) && pJump[0] == r.GetJump()[0] &&
387 memcmp( pJump.get()+1, r.GetJump()+1, pJump[0] * sizeof(short) ) == 0 &&
388 eInForceArray == r.GetInForceArray();
390 FormulaJumpToken::~FormulaJumpToken()
395 bool FormulaTokenArray::AddFormulaToken(
396 const sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool, ExternalReferenceHelper* /*pExtRef*/)
398 bool bError = false;
399 const OpCode eOpCode = static_cast<OpCode>(rToken.OpCode); //! assuming equal values for the moment
401 const uno::TypeClass eClass = rToken.Data.getValueTypeClass();
402 switch ( eClass )
404 case uno::TypeClass_VOID:
405 // empty data -> use AddOpCode (does some special cases)
406 AddOpCode( eOpCode );
407 break;
408 case uno::TypeClass_DOUBLE:
409 // double is only used for "push"
410 if ( eOpCode == ocPush )
411 AddDouble( rToken.Data.get<double>() );
412 else
413 bError = true;
414 break;
415 case uno::TypeClass_LONG:
417 // long is svIndex, used for name / database area, or "byte" for spaces
418 sal_Int32 nValue = rToken.Data.get<sal_Int32>();
419 if ( eOpCode == ocDBArea )
420 Add( new formula::FormulaIndexToken( eOpCode, static_cast<sal_uInt16>(nValue) ) );
421 else if ( eOpCode == ocSpaces )
422 Add( new formula::FormulaByteToken( ocSpaces, static_cast<sal_uInt8>(nValue) ) );
423 else
424 bError = true;
426 break;
427 case uno::TypeClass_STRING:
429 OUString aStrVal( rToken.Data.get<OUString>() );
430 if ( eOpCode == ocPush )
431 AddString(rSPool.intern(aStrVal));
432 else if ( eOpCode == ocBad )
433 AddBad( aStrVal );
434 else if ( eOpCode == ocStringXML )
435 AddStringXML( aStrVal );
436 else if ( eOpCode == ocStringName )
437 AddStringName( aStrVal );
438 else if ( eOpCode == ocExternal || eOpCode == ocMacro )
439 Add( new formula::FormulaExternalToken( eOpCode, aStrVal ) );
440 else if ( eOpCode == ocWhitespace )
442 // Simply ignore empty string.
443 // Convention is one character repeated.
444 if (!aStrVal.isEmpty())
445 Add( new formula::FormulaSpaceToken( static_cast<sal_uInt8>(aStrVal.getLength()), aStrVal[0]));
447 else
448 bError = true; // unexpected string: don't know what to do with it
450 break;
451 default:
452 bError = true;
453 } // switch ( eClass )
454 return bError;
457 bool FormulaTokenArray::Fill(
458 const uno::Sequence<sheet::FormulaToken>& rSequence,
459 svl::SharedStringPool& rSPool, ExternalReferenceHelper* pExtRef )
461 bool bError = false;
462 const sal_Int32 nCount = rSequence.getLength();
463 for (sal_Int32 nPos=0; nPos<nCount; nPos++)
465 bool bOneError = AddFormulaToken(rSequence[nPos], rSPool, pExtRef);
466 if (bOneError)
468 AddOpCode( ocErrName); // add something that indicates an error
469 bError = true;
472 return bError;
475 void FormulaTokenArray::DelRPN()
477 if( nRPN )
479 FormulaToken** p = pRPN;
480 for( sal_uInt16 i = 0; i < nRPN; i++ )
482 (*p++)->DecRef();
484 delete [] pRPN;
486 pRPN = nullptr;
487 nRPN = 0;
490 FormulaToken* FormulaTokenArray::FirstToken() const
492 if (!pCode || nLen == 0)
493 return nullptr;
494 return pCode[0];
497 FormulaToken* FormulaTokenArray::PeekPrev( sal_uInt16 & nIdx ) const
499 if (0 < nIdx && nIdx <= nLen)
500 return pCode[--nIdx];
501 return nullptr;
504 FormulaToken* FormulaTokenArray::FirstRPNToken() const
506 if (!pRPN || nRPN == 0)
507 return nullptr;
508 return pRPN[0];
511 FormulaToken* FormulaTokenArray::LastRPNToken() const
513 if (!pRPN || nRPN == 0)
514 return nullptr;
515 return pRPN[nRPN - 1];
518 bool FormulaTokenArray::HasReferences() const
520 for (auto i: Tokens())
522 if (i->IsRef())
523 return true;
526 for (auto i: RPNTokens())
528 if (i->IsRef())
529 return true;
532 return false;
535 bool FormulaTokenArray::HasExternalRef() const
537 for (auto i: Tokens())
539 if (i->IsExternalRef())
540 return true;
542 return false;
545 bool FormulaTokenArray::HasOpCode( OpCode eOp ) const
547 for (auto i: Tokens())
549 if (i->GetOpCode() == eOp)
550 return true;
552 return false;
555 bool FormulaTokenArray::HasOpCodeRPN( OpCode eOp ) const
557 for (auto i: RPNTokens())
559 if (i->GetOpCode() == eOp)
560 return true;
562 return false;
565 bool FormulaTokenArray::HasNameOrColRowName() const
567 for (auto i: Tokens())
569 if (i->GetType() == svIndex || i->GetOpCode() == ocColRowName )
570 return true;
572 return false;
575 bool FormulaTokenArray::HasOpCodes(const unordered_opcode_set& rOpCodes) const
577 for (auto i: Tokens())
579 if (rOpCodes.count(i->GetOpCode()) > 0)
580 return true;
583 return false;
586 FormulaTokenArray::FormulaTokenArray() :
587 pRPN(nullptr),
588 nLen(0),
589 nRPN(0),
590 nError(FormulaError::NONE),
591 nMode(ScRecalcMode::NORMAL),
592 bHyperLink(false),
593 mbFromRangeName(false),
594 mbShareable(true),
595 mbFinalized(false)
599 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray& rArr )
601 Assign( rArr );
604 FormulaTokenArray::FormulaTokenArray( FormulaTokenArray&& rArr )
606 Move( std::move(rArr) );
609 FormulaTokenArray::~FormulaTokenArray()
611 FormulaTokenArray::Clear();
614 void FormulaTokenArray::Finalize()
616 if( nLen && !mbFinalized )
618 // Add() overallocates, so reallocate to the minimum needed size.
619 std::unique_ptr<FormulaToken*[]> newCode(new FormulaToken*[ nLen ]);
620 std::copy(&pCode[0], &pCode[nLen], newCode.get());
621 pCode = std::move( newCode );
622 mbFinalized = true;
626 void FormulaTokenArray::Assign( const FormulaTokenArray& r )
628 nLen = r.nLen;
629 nRPN = r.nRPN;
630 nError = r.nError;
631 nMode = r.nMode;
632 bHyperLink = r.bHyperLink;
633 mbFromRangeName = r.mbFromRangeName;
634 mbShareable = r.mbShareable;
635 mbFinalized = r.mbFinalized;
636 pCode = nullptr;
637 pRPN = nullptr;
638 FormulaToken** pp;
639 if( nLen )
641 pCode.reset(new FormulaToken*[ nLen ]);
642 pp = pCode.get();
643 memcpy( pp, r.pCode.get(), nLen * sizeof( FormulaToken* ) );
644 for( sal_uInt16 i = 0; i < nLen; i++ )
645 (*pp++)->IncRef();
646 mbFinalized = true;
648 if( nRPN )
650 pp = pRPN = new FormulaToken*[ nRPN ];
651 memcpy( pp, r.pRPN, nRPN * sizeof( FormulaToken* ) );
652 for( sal_uInt16 i = 0; i < nRPN; i++ )
653 (*pp++)->IncRef();
657 void FormulaTokenArray::Move( FormulaTokenArray&& r )
659 pCode = std::move(r.pCode);
660 pRPN = r.pRPN;
661 r.pRPN = nullptr;
662 nLen = r.nLen;
663 r.nLen = 0;
664 nRPN = r.nRPN;
665 r.nRPN = 0;
666 nError = r.nError;
667 nMode = r.nMode;
668 bHyperLink = r.bHyperLink;
669 mbFromRangeName = r.mbFromRangeName;
670 mbShareable = r.mbShareable;
671 mbFinalized = r.mbFinalized;
674 /// Optimisation for efficiently creating StringXML placeholders
675 void FormulaTokenArray::Assign( sal_uInt16 nCode, FormulaToken **pTokens )
677 assert( nLen == 0 );
678 assert( pCode == nullptr );
680 nLen = nCode;
681 pCode.reset(new FormulaToken*[ nLen ]);
682 mbFinalized = true;
684 for( sal_uInt16 i = 0; i < nLen; i++ )
686 FormulaToken *t = pTokens[ i ];
687 assert( t->GetOpCode() == ocStringXML );
688 pCode[ i ] = t;
689 t->IncRef();
693 FormulaTokenArray& FormulaTokenArray::operator=( const FormulaTokenArray& rArr )
695 if(this == &rArr)
696 return *this;
698 Clear();
699 Assign( rArr );
700 return *this;
703 FormulaTokenArray& FormulaTokenArray::operator=( FormulaTokenArray&& rArr )
705 Clear();
706 Move( std::move(rArr) );
707 return *this;
710 void FormulaTokenArray::Clear()
712 if( nRPN ) DelRPN();
713 if( pCode )
715 FormulaToken** p = pCode.get();
716 for( sal_uInt16 i = 0; i < nLen; i++ )
718 (*p++)->DecRef();
720 pCode.reset();
722 pRPN = nullptr;
723 nError = FormulaError::NONE;
724 nLen = nRPN = 0;
725 bHyperLink = false;
726 mbFromRangeName = false;
727 mbShareable = true;
728 mbFinalized = false;
729 ClearRecalcMode();
732 void FormulaTokenArray::CheckToken( const FormulaToken& /*r*/ )
734 // Do nothing.
737 void FormulaTokenArray::CheckAllRPNTokens()
739 if( nRPN )
741 FormulaToken** p = pRPN;
742 for( sal_uInt16 i = 0; i < nRPN; i++ )
744 CheckToken( *p[ i ] );
749 FormulaToken* FormulaTokenArray::AddToken( const FormulaToken& r )
751 return Add( r.Clone() );
754 FormulaToken* FormulaTokenArray::MergeArray( )
756 return nullptr;
759 FormulaToken* FormulaTokenArray::ReplaceToken( sal_uInt16 nOffset, FormulaToken* t,
760 FormulaTokenArray::ReplaceMode eMode )
762 if (nOffset < nLen)
764 CheckToken(*t);
765 t->IncRef();
766 FormulaToken* p = pCode[nOffset];
767 pCode[nOffset] = t;
768 if (eMode == CODE_AND_RPN && p->GetRef() > 1)
770 for (sal_uInt16 i=0; i < nRPN; ++i)
772 if (pRPN[i] == p)
774 t->IncRef();
775 pRPN[i] = t;
776 p->DecRef();
777 if (p->GetRef() == 1)
778 break; // for
782 p->DecRef(); // may be dead now
783 return t;
785 else
787 t->DeleteIfZeroRef();
788 return nullptr;
792 sal_uInt16 FormulaTokenArray::RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount )
794 if (nOffset < nLen)
796 SAL_WARN_IF( nOffset + nCount > nLen, "formula.core",
797 "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen);
798 const sal_uInt16 nStop = ::std::min( static_cast<sal_uInt16>(nOffset + nCount), nLen);
799 nCount = nStop - nOffset;
800 for (sal_uInt16 j = nOffset; j < nStop; ++j)
802 FormulaToken* p = pCode[j];
803 if (p->GetRef() > 1)
805 for (sal_uInt16 i=0; i < nRPN; ++i)
807 if (pRPN[i] == p)
809 // Shift remaining tokens in pRPN down.
810 for (sal_uInt16 x=i+1; x < nRPN; ++x)
812 pRPN[x-1] = pRPN[x];
814 --nRPN;
816 p->DecRef();
817 if (p->GetRef() == 1)
818 break; // for
822 p->DecRef(); // may be dead now
825 // Shift remaining tokens in pCode down.
826 for (sal_uInt16 x = nStop; x < nLen; ++x)
828 pCode[x-nCount] = pCode[x];
830 nLen -= nCount;
832 return nCount;
834 else
836 SAL_WARN("formula.core","FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen);
837 return 0;
841 FormulaToken* FormulaTokenArray::Add( FormulaToken* t )
843 assert(!mbFinalized);
844 if (mbFinalized)
846 t->DeleteIfZeroRef();
847 return nullptr;
850 // Allocating an array of size FORMULA_MAXTOKENS is simple, but that results in relatively large
851 // allocations that malloc() implementations usually do not handle as efficiently as smaller
852 // sizes (not only in terms of memory usage but also speed). Since most token arrays are going
853 // to be small, start with a small array and resize only if needed. Eventually Finalize() will
854 // reallocate the memory to size exactly matching the requirements.
855 const size_t MAX_FAST_TOKENS = 32;
856 if( !pCode )
857 pCode.reset(new FormulaToken*[ MAX_FAST_TOKENS ]);
858 if( nLen == MAX_FAST_TOKENS )
860 FormulaToken** tmp = new FormulaToken*[ FORMULA_MAXTOKENS ];
861 std::copy(&pCode[0], &pCode[MAX_FAST_TOKENS], tmp);
862 pCode.reset(tmp);
864 if( nLen < FORMULA_MAXTOKENS - 1 )
866 CheckToken(*t);
867 pCode[ nLen++ ] = t;
868 t->IncRef();
869 if( t->GetOpCode() == ocArrayClose )
870 return MergeArray();
871 return t;
873 else
875 t->DeleteIfZeroRef();
876 if ( nLen == FORMULA_MAXTOKENS - 1 )
878 t = new FormulaByteToken( ocStop );
879 pCode[ nLen++ ] = t;
880 t->IncRef();
882 return nullptr;
886 FormulaToken* FormulaTokenArray::AddString( const svl::SharedString& rStr )
888 return Add( new FormulaStringToken( rStr ) );
891 FormulaToken* FormulaTokenArray::AddDouble( double fVal )
893 return Add( new FormulaDoubleToken( fVal ) );
896 void FormulaTokenArray::AddExternal( const sal_Unicode* pStr )
898 AddExternal( OUString( pStr ) );
901 FormulaToken* FormulaTokenArray::AddExternal( const OUString& rStr,
902 OpCode eOp /* = ocExternal */ )
904 return Add( new FormulaExternalToken( eOp, rStr ) );
907 FormulaToken* FormulaTokenArray::AddBad( const OUString& rStr )
909 return Add( new FormulaStringOpToken( ocBad, svl::SharedString( rStr ) ) ); // string not interned
912 FormulaToken* FormulaTokenArray::AddStringXML( const OUString& rStr )
914 return Add( new FormulaStringOpToken( ocStringXML, svl::SharedString( rStr ) ) ); // string not interned
917 FormulaToken* FormulaTokenArray::AddStringName( const OUString& rStr )
919 return Add( new FormulaStringOpToken( ocStringName, svl::SharedString( rStr ) ) ); // string not interned
922 void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits )
924 const unsigned nExclusive = static_cast<sal_uInt8>(nBits & ScRecalcMode::EMask);
925 if (nExclusive)
927 unsigned nExBit;
928 if (nExclusive & (nExclusive - 1))
930 // More than one bit set, use highest priority.
931 for (nExBit = 1; (nExBit & static_cast<sal_uInt8>(ScRecalcMode::EMask)) != 0; nExBit <<= 1)
933 if (nExclusive & nExBit)
934 break;
937 else
939 // Only one bit is set.
940 nExBit = nExclusive;
942 // Set exclusive bit if priority is higher than existing.
943 if (nExBit < static_cast<sal_uInt8>(nMode & ScRecalcMode::EMask))
944 SetMaskedRecalcMode( static_cast<ScRecalcMode>(nExBit));
946 SetCombinedBitsRecalcMode( nBits );
950 bool FormulaTokenArray::HasMatrixDoubleRefOps() const
952 if ( !pRPN || !nRPN )
953 return false;
955 // RPN-Interpreter simulation.
956 // Simply assumes a double as return value of each function.
957 std::unique_ptr<FormulaToken*[]> pStack(new FormulaToken* [nRPN]);
958 FormulaToken* pResult = new FormulaDoubleToken( 0.0 );
959 short sp = 0;
960 for ( auto t: RPNTokens() )
962 OpCode eOp = t->GetOpCode();
963 sal_uInt8 nParams = t->GetParamCount();
964 switch ( eOp )
966 case ocAdd :
967 case ocSub :
968 case ocMul :
969 case ocDiv :
970 case ocPow :
971 case ocPower :
972 case ocAmpersand :
973 case ocEqual :
974 case ocNotEqual :
975 case ocLess :
976 case ocGreater :
977 case ocLessEqual :
978 case ocGreaterEqual :
980 for ( sal_uInt8 k = nParams; k; k-- )
982 if ( sp >= k && pStack[sp-k]->GetType() == svDoubleRef )
984 pResult->Delete();
985 return true;
989 break;
990 default:
992 // added to avoid warnings
995 if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() ) )
996 pStack[sp++] = t;
997 else if (FormulaCompiler::IsOpCodeJumpCommand( eOp ))
998 { // ignore Jumps, pop previous Result (Condition)
999 if ( sp )
1000 --sp;
1002 else
1003 { // pop parameters, push result
1004 sp = sal::static_int_cast<short>( sp - nParams );
1005 if ( sp < 0 )
1007 SAL_WARN("formula.core", "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
1008 sp = 0;
1010 pStack[sp++] = pResult;
1013 pResult->Delete();
1015 return false;
1018 // --- Formula rewrite of a token array
1020 inline bool MissingConventionODF::isRewriteNeeded( OpCode eOp ) const
1022 switch (eOp)
1024 case ocGammaDist:
1025 case ocPoissonDist:
1026 case ocAddress:
1027 case ocLogInv:
1028 case ocLogNormDist:
1029 case ocNormDist:
1030 return true;
1031 case ocMissing:
1032 case ocLog:
1033 return isPODF(); // rewrite only for PODF
1034 case ocDBCount:
1035 case ocDBCount2:
1036 return isODFF(); // rewrite only for ODFF
1037 default:
1038 return false;
1043 fdo 81596
1044 To be implemented yet:
1045 ocExternal: ?
1046 ocMacro: ?
1047 ocIndex: INDEX() ?
1049 inline bool MissingConventionOOXML::isRewriteNeeded( OpCode eOp )
1051 switch (eOp)
1053 case ocIf:
1055 case ocExternal:
1056 case ocEuroConvert:
1057 case ocMacro:
1059 case ocRound:
1060 case ocRoundUp:
1061 case ocRoundDown:
1063 case ocIndex:
1065 case ocCeil:
1066 case ocFloor:
1068 case ocGammaDist:
1069 case ocFDist_LT:
1070 case ocPoissonDist:
1071 case ocNormDist:
1072 case ocLogInv:
1073 case ocLogNormDist:
1074 case ocHypGeomDist:
1076 case ocDBCount:
1077 case ocDBCount2:
1078 return true;
1080 default:
1081 return false;
1085 namespace {
1087 class FormulaMissingContext
1089 public:
1090 const FormulaToken* mpFunc;
1091 int mnCurArg;
1093 void Clear() { mpFunc = nullptr; mnCurArg = 0; }
1094 inline bool AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const;
1095 bool AddMissingExternal( FormulaTokenArray* pNewArr ) const;
1096 bool AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
1097 void AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
1102 void FormulaMissingContext::AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
1104 if ( !mpFunc )
1105 return;
1107 switch (rConv.getConvention())
1109 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF:
1110 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF:
1112 switch (mpFunc->GetOpCode())
1114 case ocGammaDist:
1115 if (mnCurArg == 2)
1117 pNewArr->AddOpCode( ocSep );
1118 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1120 break;
1121 case ocPoissonDist:
1122 if (mnCurArg == 1)
1124 pNewArr->AddOpCode( ocSep );
1125 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1127 break;
1128 case ocNormDist:
1129 if ( mnCurArg == 2 )
1131 pNewArr->AddOpCode( ocSep );
1132 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1134 break;
1135 case ocLogInv:
1136 case ocLogNormDist:
1137 if ( mnCurArg == 0 )
1139 pNewArr->AddOpCode( ocSep );
1140 pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0
1142 if ( mnCurArg <= 1 )
1144 pNewArr->AddOpCode( ocSep );
1145 pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1147 break;
1148 case ocLog:
1149 if ( rConv.isPODF() && mnCurArg == 0 )
1151 pNewArr->AddOpCode( ocSep );
1152 pNewArr->AddDouble( 10.0 ); // 2nd, basis 10
1154 break;
1155 default:
1156 break;
1159 break;
1160 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML:
1162 switch (mpFunc->GetOpCode())
1164 case ocIf:
1165 if( mnCurArg == 0 )
1167 // Excel needs at least two parameters in IF function
1168 pNewArr->AddOpCode( ocSep );
1169 pNewArr->AddOpCode( ocTrue ); // 2nd, true() as function
1170 pNewArr->AddOpCode( ocOpen ); // so the result is of logical type
1171 pNewArr->AddOpCode( ocClose ); // and survives roundtrip
1173 break;
1175 case ocEuroConvert:
1176 if ( mnCurArg == 2 )
1178 pNewArr->AddOpCode( ocSep );
1179 pNewArr->AddDouble( 0.0 ); // 4th, FullPrecision = false()
1181 break;
1183 case ocPoissonDist:
1184 if (mnCurArg == 1)
1186 pNewArr->AddOpCode( ocSep );
1187 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1189 break;
1191 case ocGammaDist:
1192 case ocFDist_LT:
1193 case ocNormDist:
1194 if (mnCurArg == 2)
1196 pNewArr->AddOpCode( ocSep );
1197 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1199 break;
1201 case ocLogInv:
1202 case ocLogNormDist:
1203 if ( mnCurArg == 0 )
1205 pNewArr->AddOpCode( ocSep );
1206 pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0
1208 if ( mnCurArg <= 1 )
1210 pNewArr->AddOpCode( ocSep );
1211 pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1213 break;
1215 case ocHypGeomDist:
1216 if ( mnCurArg == 3 )
1218 pNewArr->AddOpCode( ocSep );
1219 pNewArr->AddDouble( 0.0 ); // 5th, Cumulative = false()
1221 break;
1223 case ocRound:
1224 case ocRoundUp:
1225 case ocRoundDown:
1226 if( mnCurArg == 0 )
1228 // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel
1229 pNewArr->AddOpCode( ocSep );
1230 pNewArr->AddDouble( 0.0 ); // 2nd, 0.0
1232 break;
1234 default:
1235 break;
1238 break;
1243 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const
1245 if (mnCurArg == nArg)
1247 pNewArr->AddDouble( f );
1248 return true;
1250 return false;
1253 bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray *pNewArr ) const
1255 // Only called for PODF, not ODFF. No need to distinguish.
1257 const OUString &rName = mpFunc->GetExternal();
1259 // initial (fast) checks:
1260 sal_Int32 nLength = rName.getLength();
1261 if (!nLength)
1262 return false;
1264 sal_Unicode nLastChar = rName[ nLength - 1];
1265 if ( nLastChar != 't' && nLastChar != 'm' )
1266 return false;
1268 if (rName.equalsIgnoreAsciiCase(
1269 "com.sun.star.sheet.addin.Analysis.getAccrint" ))
1271 return AddDefaultArg( pNewArr, 4, 1000.0 );
1273 if (rName.equalsIgnoreAsciiCase(
1274 "com.sun.star.sheet.addin.Analysis.getAccrintm" ))
1276 return AddDefaultArg( pNewArr, 3, 1000.0 );
1278 return false;
1281 bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
1283 if ( !mpFunc )
1284 return false;
1286 bool bRet = false;
1287 const OpCode eOp = mpFunc->GetOpCode();
1289 switch (rConv.getConvention())
1291 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF:
1293 // Add for ODFF
1294 switch (eOp)
1296 case ocAddress:
1297 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1298 default:
1299 break;
1302 break;
1303 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF:
1305 // Add for PODF
1306 switch (eOp)
1308 case ocAddress:
1309 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1310 case ocFixed:
1311 return AddDefaultArg( pNewArr, 1, 2.0 );
1312 case ocBetaDist:
1313 case ocBetaInv:
1314 case ocPMT:
1315 return AddDefaultArg( pNewArr, 3, 0.0 );
1316 case ocIpmt:
1317 case ocPpmt:
1318 return AddDefaultArg( pNewArr, 4, 0.0 );
1319 case ocPV:
1320 case ocFV:
1321 bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt
1322 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v
1323 break;
1324 case ocRate:
1325 bRet |= AddDefaultArg( pNewArr, 1, 0.0 ); // pmt
1326 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // fv
1327 bRet |= AddDefaultArg( pNewArr, 4, 0.0 ); // type
1328 break;
1329 case ocExternal:
1330 return AddMissingExternal( pNewArr );
1332 // --- more complex cases ---
1334 case ocOffset:
1335 // FIXME: rather tough
1336 // if arg 3 (height) omitted, export arg1 (rows)
1337 break;
1338 default:
1339 break;
1342 break;
1343 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML:
1345 switch (eOp)
1347 case ocExternal:
1348 return AddMissingExternal( pNewArr );
1349 default:
1350 break;
1353 break;
1356 return bRet;
1359 bool FormulaTokenArray::NeedsPodfRewrite( const MissingConventionODF & rConv )
1361 for ( auto i: Tokens() )
1363 if ( rConv.isRewriteNeeded( i->GetOpCode()))
1364 return true;
1366 return false;
1369 bool FormulaTokenArray::NeedsOoxmlRewrite()
1371 for ( auto i: Tokens() )
1373 if ( MissingConventionOOXML::isRewriteNeeded( i->GetOpCode()))
1374 return true;
1376 return false;
1380 FormulaTokenArray * FormulaTokenArray::RewriteMissing( const MissingConvention & rConv )
1382 const size_t nAlloc = 256;
1383 FormulaMissingContext aCtx[ nAlloc ];
1385 /* TODO: with some effort we might be able to merge the two almost
1386 * identical function stacks into one and generalize things, otherwise
1387 * adding yet another "omit argument" would be copypasta. */
1389 int aOpCodeAddressStack[ nAlloc ]; // use of ADDRESS() function
1390 const int nOmitAddressArg = 3; // ADDRESS() 4th parameter A1/R1C1
1392 int aOpCodeDcountStack[ nAlloc ]; // use of DCOUNT()/DCOUNTA() function
1393 const int nOmitDcountArg = 1; // DCOUNT() and DCOUNTA() 2nd parameter DatabaseField if 0
1395 sal_uInt16 nTokens = GetLen() + 1;
1396 FormulaMissingContext* pCtx = (nAlloc < nTokens ? new FormulaMissingContext[nTokens] : &aCtx[0]);
1397 int* pOcas = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeAddressStack[0]);
1398 int* pOcds = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeDcountStack[0]);
1399 // Never go below 0, never use 0, mpFunc always NULL.
1400 pCtx[0].Clear();
1401 int nFn = 0;
1402 int nOcas = 0;
1403 int nOcds = 0;
1405 FormulaTokenArray *pNewArr = new FormulaTokenArray;
1406 // At least ScRecalcMode::ALWAYS needs to be set.
1407 pNewArr->AddRecalcMode( GetRecalcMode());
1409 FormulaTokenArrayPlainIterator aIter(*this);
1410 for ( FormulaToken *pCur = aIter.First(); pCur; pCur = aIter.Next() )
1412 bool bAdd = true;
1413 // Don't write the expression of the new inserted ADDRESS() parameter.
1414 // Do NOT omit the new second parameter of INDIRECT() though. If that
1415 // was done for both, INDIRECT() actually could calculate different and
1416 // valid (but wrong) results with the then changed return value of
1417 // ADDRESS(). Better let it generate an error instead.
1418 for (int i = nOcas; i-- > 0 && bAdd; )
1420 if (pCtx[ pOcas[ i ] ].mnCurArg == nOmitAddressArg)
1422 // Omit everything except a trailing separator, the leading
1423 // separator is omitted below. The other way around would leave
1424 // an extraneous separator if no parameter followed.
1425 if (pOcas[ i ] != nFn || pCur->GetOpCode() != ocSep)
1426 bAdd = false;
1429 // Strip the 2nd argument (leaving empty) of DCOUNT() and DCOUNTA() if
1430 // it is 0.
1431 for (int i = nOcds; i-- > 0 && bAdd; )
1433 if (pCtx[ pOcds[ i ] ].mnCurArg == nOmitDcountArg)
1435 // Omit only a literal 0 value, nothing else.
1436 if (pOcds[ i ] == nFn && pCur->GetOpCode() == ocPush && pCur->GetType() == svDouble &&
1437 pCur->GetDouble() == 0.0)
1439 // No other expression, between separators.
1440 FormulaToken* p = aIter.PeekPrevNoSpaces();
1441 if (p && p->GetOpCode() == ocSep)
1443 p = aIter.PeekNextNoSpaces();
1444 if (p && p->GetOpCode() == ocSep)
1445 bAdd = false;
1450 switch ( pCur->GetOpCode() )
1452 case ocOpen:
1454 ++nFn; // all following operations on _that_ function
1455 pCtx[ nFn ].mpFunc = aIter.PeekPrevNoSpaces();
1456 pCtx[ nFn ].mnCurArg = 0;
1457 if (rConv.isPODF() && pCtx[ nFn ].mpFunc && pCtx[ nFn ].mpFunc->GetOpCode() == ocAddress)
1458 pOcas[ nOcas++ ] = nFn; // entering ADDRESS() if PODF
1459 else if ((rConv.isODFF() || rConv.isOOXML()) && pCtx[ nFn ].mpFunc)
1461 OpCode eOp = pCtx[ nFn ].mpFunc->GetOpCode();
1462 if (eOp == ocDBCount || eOp == ocDBCount2)
1463 pOcds[ nOcds++ ] = nFn; // entering DCOUNT() or DCOUNTA() if ODFF or OOXML
1466 break;
1467 case ocClose:
1468 pCtx[ nFn ].AddMoreArgs( pNewArr, rConv );
1469 SAL_WARN_IF(nFn <= 0, "formula.core", "FormulaTokenArray::RewriteMissing: underflow");
1470 if (nOcas > 0 && pOcas[ nOcas-1 ] == nFn)
1471 --nOcas; // leaving ADDRESS()
1472 else if (nOcds > 0 && pOcds[ nOcds-1 ] == nFn)
1473 --nOcds; // leaving DCOUNT() or DCOUNTA()
1474 if (nFn > 0)
1475 --nFn;
1476 break;
1477 case ocSep:
1478 pCtx[ nFn ].mnCurArg++;
1479 // Omit leading separator of ADDRESS() parameter.
1480 if (nOcas && pOcas[ nOcas-1 ] == nFn && pCtx[ nFn ].mnCurArg == nOmitAddressArg)
1482 bAdd = false;
1484 break;
1485 case ocMissing:
1486 if ( bAdd )
1487 bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv );
1488 break;
1489 default:
1490 break;
1492 if (bAdd)
1494 OpCode eOp = pCur->GetOpCode();
1495 if ( ( eOp == ocCeil || eOp == ocFloor ||
1496 ( eOp == ocLogNormDist && pCur->GetByte() == 4 ) ) &&
1497 rConv.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML )
1499 switch ( eOp )
1501 case ocCeil :
1502 eOp = ocCeil_Math;
1503 break;
1504 case ocFloor :
1505 eOp = ocFloor_Math;
1506 break;
1507 case ocLogNormDist :
1508 eOp = ocLogNormDist_MS;
1509 break;
1510 default :
1511 eOp = ocNone;
1512 break;
1514 FormulaToken *pToken = new FormulaToken( svByte, eOp );
1515 pNewArr->Add( pToken );
1517 else if ( eOp == ocHypGeomDist &&
1518 rConv.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML )
1520 FormulaToken *pToken = new FormulaToken( svByte, ocHypGeomDist_MS );
1521 pNewArr->Add( pToken );
1523 else
1524 pNewArr->AddToken( *pCur );
1528 if (pOcds != &aOpCodeDcountStack[0])
1529 delete [] pOcds;
1530 if (pOcas != &aOpCodeAddressStack[0])
1531 delete [] pOcas;
1532 if (pCtx != &aCtx[0])
1533 delete [] pCtx;
1535 return pNewArr;
1538 namespace {
1539 inline bool isWhitespace( OpCode eOp ) { return eOp == ocSpaces || eOp == ocWhitespace; }
1542 bool FormulaTokenArray::MayReferenceFollow()
1544 if ( !pCode || nLen <= 0 )
1545 return false;
1547 // ignore trailing spaces
1548 sal_uInt16 i = nLen - 1;
1549 while (i > 0 && isWhitespace( pCode[i]->GetOpCode()))
1551 --i;
1553 if (i > 0 || !isWhitespace( pCode[i]->GetOpCode()))
1555 OpCode eOp = pCode[i]->GetOpCode();
1556 if ( (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP ) ||
1557 (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP ) ||
1558 eOp == SC_OPCODE_OPEN || eOp == SC_OPCODE_SEP )
1560 return true;
1563 return false;
1565 FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp )
1567 FormulaToken* pRet = nullptr;
1568 switch ( eOp )
1570 case ocOpen:
1571 case ocClose:
1572 case ocSep:
1573 case ocArrayOpen:
1574 case ocArrayClose:
1575 case ocArrayRowSep:
1576 case ocArrayColSep:
1577 pRet = new FormulaToken( svSep,eOp );
1578 break;
1579 case ocIf:
1580 case ocIfError:
1581 case ocIfNA:
1582 case ocChoose:
1583 case ocLet:
1585 short nJump[FORMULA_MAXPARAMS + 1];
1586 if ( eOp == ocIf )
1587 nJump[ 0 ] = 3;
1588 else if ( eOp == ocChoose )
1589 nJump[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
1590 else if ( eOp == ocLet )
1591 nJump[ 0 ] = FORMULA_MAXPARAMS + 1;
1592 else
1593 nJump[ 0 ] = 2;
1594 pRet = new FormulaJumpToken( eOp, nJump );
1596 break;
1597 default:
1598 pRet = new FormulaByteToken( eOp, 0, ParamClass::Unknown );
1599 break;
1601 return Add( pRet );
1604 void FormulaTokenArray::ReinternStrings( svl::SharedStringPool& rPool )
1606 for (auto i: Tokens())
1608 switch (i->GetType())
1610 case svString:
1611 i->SetString( rPool.intern( i->GetString().getString()));
1612 break;
1613 default:
1614 ; // nothing
1620 /*----------------------------------------------------------------------*/
1622 FormulaTokenIterator::Item::Item(const FormulaTokenArray* pArray, short pc, short stop) :
1623 pArr(pArray), nPC(pc), nStop(stop)
1627 FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray& rArr )
1628 : maStack{ FormulaTokenIterator::Item(&rArr, -1, SHRT_MAX) }
1632 FormulaTokenIterator::~FormulaTokenIterator()
1636 void FormulaTokenIterator::Push( const FormulaTokenArray* pArr )
1638 FormulaTokenIterator::Item item(pArr, -1, SHRT_MAX);
1640 maStack.push_back(item);
1643 void FormulaTokenIterator::Pop()
1645 maStack.pop_back();
1648 void FormulaTokenIterator::Reset()
1650 while( maStack.size() > 1 )
1651 maStack.pop_back();
1653 maStack.back().nPC = -1;
1656 FormulaToken* FormulaTokenArrayPlainIterator::GetNextName()
1658 if( mpFTA->GetArray() )
1660 while ( mnIndex < mpFTA->GetLen() )
1662 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1663 if( t->GetType() == svIndex )
1664 return t;
1667 return nullptr;
1670 FormulaToken* FormulaTokenArrayPlainIterator::GetNextStringName()
1672 if (mpFTA->GetArray())
1674 while (mnIndex < mpFTA->GetLen())
1676 FormulaToken* t = mpFTA->GetArray()[mnIndex++];
1677 if (t->GetType() == svString && t->GetOpCode() == ocStringName)
1678 return t;
1681 return nullptr;
1684 const FormulaToken* FormulaTokenIterator::Next()
1686 const FormulaToken* t = GetNonEndOfPathToken( ++maStack.back().nPC );
1687 if( !t && maStack.size() > 1 )
1689 Pop();
1690 t = Next();
1692 return t;
1695 const FormulaToken* FormulaTokenIterator::PeekNextOperator()
1697 const FormulaToken* t = nullptr;
1698 short nIdx = maStack.back().nPC;
1699 for (;;)
1701 t = GetNonEndOfPathToken( ++nIdx);
1702 if (t == nullptr || t->GetOpCode() != ocPush)
1703 break; // ignore operands
1705 if (!t && maStack.size() > 1)
1707 FormulaTokenIterator::Item aHere = maStack.back();
1708 maStack.pop_back();
1709 t = PeekNextOperator();
1710 maStack.push_back(aHere);
1712 return t;
1715 //! The nPC counts after a Push() are -1
1717 void FormulaTokenIterator::Jump( short nStart, short nNext, short nStop )
1719 maStack.back().nPC = nNext;
1720 if( nStart != nNext )
1722 Push( maStack.back().pArr );
1723 maStack.back().nPC = nStart;
1724 maStack.back().nStop = nStop;
1728 void FormulaTokenIterator::ReInit( const FormulaTokenArray& rArr )
1730 maStack.clear();
1731 Push( &rArr );
1734 const FormulaToken* FormulaTokenIterator::GetNonEndOfPathToken( short nIdx ) const
1736 FormulaTokenIterator::Item cur = maStack.back();
1738 if (nIdx < cur.pArr->GetCodeLen() && nIdx < cur.nStop)
1740 const FormulaToken* t = cur.pArr->GetCode()[ nIdx ];
1741 // such an OpCode ends an IF() or CHOOSE() path
1742 return (t->GetOpCode() == ocSep || t->GetOpCode() == ocClose) ? nullptr : t;
1744 return nullptr;
1747 bool FormulaTokenIterator::IsEndOfPath() const
1749 return GetNonEndOfPathToken( maStack.back().nPC + 1) == nullptr;
1752 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReference()
1754 while( mnIndex < mpFTA->GetLen() )
1756 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1757 switch( t->GetType() )
1759 case svSingleRef:
1760 case svDoubleRef:
1761 case svExternalSingleRef:
1762 case svExternalDoubleRef:
1763 return t;
1764 default:
1766 // added to avoid warnings
1770 return nullptr;
1773 FormulaToken* FormulaTokenArrayPlainIterator::GetNextColRowName()
1775 while( mnIndex < mpFTA->GetLen() )
1777 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1778 if ( t->GetOpCode() == ocColRowName )
1779 return t;
1781 return nullptr;
1784 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceRPN()
1786 while( mnIndex < mpFTA->GetCodeLen() )
1788 FormulaToken* t = mpFTA->GetCode()[ mnIndex++ ];
1789 switch( t->GetType() )
1791 case svSingleRef:
1792 case svDoubleRef:
1793 case svExternalSingleRef:
1794 case svExternalDoubleRef:
1795 return t;
1796 default:
1798 // added to avoid warnings
1802 return nullptr;
1805 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceOrName()
1807 if( !mpFTA->GetArray() )
1808 return nullptr;
1810 while ( mnIndex < mpFTA->GetLen() )
1812 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1813 switch( t->GetType() )
1815 case svSingleRef:
1816 case svDoubleRef:
1817 case svIndex:
1818 case svExternalSingleRef:
1819 case svExternalDoubleRef:
1820 case svExternalName:
1821 return t;
1822 default:
1824 // added to avoid warnings
1828 return nullptr;
1831 FormulaToken* FormulaTokenArrayPlainIterator::Next()
1833 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1834 return mpFTA->GetArray()[ mnIndex++ ];
1835 else
1836 return nullptr;
1839 FormulaToken* FormulaTokenArrayPlainIterator::NextNoSpaces()
1841 if( mpFTA->GetArray() )
1843 while ((mnIndex < mpFTA->GetLen()) && isWhitespace( mpFTA->GetArray()[ mnIndex ]->GetOpCode()))
1844 ++mnIndex;
1845 if( mnIndex < mpFTA->GetLen() )
1846 return mpFTA->GetArray()[ mnIndex++ ];
1848 return nullptr;
1851 FormulaToken* FormulaTokenArrayPlainIterator::NextRPN()
1853 if( mpFTA->GetCode() && mnIndex < mpFTA->GetCodeLen() )
1854 return mpFTA->GetCode()[ mnIndex++ ];
1855 else
1856 return nullptr;
1859 FormulaToken* FormulaTokenArrayPlainIterator::PrevRPN()
1861 if( mpFTA->GetCode() && mnIndex )
1862 return mpFTA->GetCode()[ --mnIndex ];
1863 else
1864 return nullptr;
1867 FormulaToken* FormulaTokenArrayPlainIterator::PeekNext()
1869 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1870 return mpFTA->GetArray()[ mnIndex ];
1871 else
1872 return nullptr;
1875 FormulaToken* FormulaTokenArrayPlainIterator::PeekNextNoSpaces() const
1877 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1879 sal_uInt16 j = mnIndex;
1880 while (j < mpFTA->GetLen() && isWhitespace( mpFTA->GetArray()[j]->GetOpCode()))
1881 j++;
1882 if ( j < mpFTA->GetLen() )
1883 return mpFTA->GetArray()[ j ];
1884 else
1885 return nullptr;
1887 else
1888 return nullptr;
1891 FormulaToken* FormulaTokenArrayPlainIterator::PeekPrevNoSpaces() const
1893 if( mpFTA->GetArray() && mnIndex > 1 )
1895 sal_uInt16 j = mnIndex - 2;
1896 while (isWhitespace( mpFTA->GetArray()[j]->GetOpCode()) && j > 0 )
1897 j--;
1898 if (j > 0 || !isWhitespace( mpFTA->GetArray()[j]->GetOpCode()))
1899 return mpFTA->GetArray()[ j ];
1900 else
1901 return nullptr;
1903 else
1904 return nullptr;
1907 void FormulaTokenArrayPlainIterator::AfterRemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount )
1909 const sal_uInt16 nStop = std::min( static_cast<sal_uInt16>(nOffset + nCount), mpFTA->GetLen());
1911 if (mnIndex >= nOffset)
1913 if (mnIndex < nStop)
1914 mnIndex = nOffset + 1;
1915 else
1916 mnIndex -= nStop - nOffset;
1920 // real implementations of virtual functions
1922 sal_Int16 FormulaDoubleToken::GetDoubleType() const
1924 // This is a plain double value without type information, don't emit a
1925 // warning via FormulaToken::GetDoubleType().
1926 return 0;
1929 bool FormulaDoubleToken::operator==( const FormulaToken& r ) const
1931 return FormulaToken::operator==( r ) && fDouble == r.GetDouble();
1934 sal_Int16 FormulaTypedDoubleToken::GetDoubleType() const
1936 return mnType;
1939 void FormulaTypedDoubleToken::SetDoubleType( sal_Int16 nType )
1941 mnType = nType;
1944 bool FormulaTypedDoubleToken::operator==( const FormulaToken& r ) const
1946 return FormulaDoubleToken::operator==( r ) && mnType == r.GetDoubleType();
1949 FormulaStringToken::FormulaStringToken( svl::SharedString r ) :
1950 FormulaToken( svString ), maString(std::move( r ))
1954 FormulaStringToken::FormulaStringToken( const FormulaStringToken& r ) :
1955 FormulaToken( r ), maString( r.maString ) {}
1957 FormulaToken* FormulaStringToken::Clone() const
1959 return new FormulaStringToken(*this);
1962 const svl::SharedString & FormulaStringToken::GetString() const
1964 return maString;
1967 void FormulaStringToken::SetString( const svl::SharedString& rStr )
1969 maString = rStr;
1972 bool FormulaStringToken::operator==( const FormulaToken& r ) const
1974 return FormulaToken::operator==( r ) && maString == r.GetString();
1977 FormulaStringOpToken::FormulaStringOpToken( OpCode e, svl::SharedString r ) :
1978 FormulaByteToken( e, 0, svString, ParamClass::Unknown ), maString(std::move( r )) {}
1980 FormulaStringOpToken::FormulaStringOpToken( const FormulaStringOpToken& r ) :
1981 FormulaByteToken( r ), maString( r.maString ) {}
1983 FormulaToken* FormulaStringOpToken::Clone() const
1985 return new FormulaStringOpToken(*this);
1988 const svl::SharedString & FormulaStringOpToken::GetString() const
1990 return maString;
1993 void FormulaStringOpToken::SetString( const svl::SharedString& rStr )
1995 maString = rStr;
1998 bool FormulaStringOpToken::operator==( const FormulaToken& r ) const
2000 return FormulaByteToken::operator==( r ) && maString == r.GetString();
2003 sal_uInt16 FormulaIndexToken::GetIndex() const { return nIndex; }
2004 void FormulaIndexToken::SetIndex( sal_uInt16 n ) { nIndex = n; }
2005 sal_Int16 FormulaIndexToken::GetSheet() const { return mnSheet; }
2006 void FormulaIndexToken::SetSheet( sal_Int16 n ) { mnSheet = n; }
2007 bool FormulaIndexToken::operator==( const FormulaToken& r ) const
2009 return FormulaToken::operator==( r ) && nIndex == r.GetIndex() &&
2010 mnSheet == r.GetSheet();
2012 const OUString& FormulaExternalToken::GetExternal() const { return aExternal; }
2013 bool FormulaExternalToken::operator==( const FormulaToken& r ) const
2015 return FormulaByteToken::operator==( r ) && aExternal == r.GetExternal();
2019 FormulaError FormulaErrorToken::GetError() const { return nError; }
2020 void FormulaErrorToken::SetError( FormulaError nErr ) { nError = nErr; }
2021 bool FormulaErrorToken::operator==( const FormulaToken& r ) const
2023 return FormulaToken::operator==( r ) &&
2024 nError == static_cast< const FormulaErrorToken & >(r).GetError();
2026 double FormulaMissingToken::GetDouble() const { return 0.0; }
2028 const svl::SharedString & FormulaMissingToken::GetString() const
2030 return svl::SharedString::getEmptyString();
2033 bool FormulaMissingToken::operator==( const FormulaToken& r ) const
2035 return FormulaToken::operator==( r );
2039 bool FormulaUnknownToken::operator==( const FormulaToken& r ) const
2041 return FormulaToken::operator==( r );
2045 } // formula
2048 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */