Avoid potential negative array index access to cached text.
[LibreOffice.git] / formula / source / core / api / token.cxx
blobb384f091db6797f38dc99d47abad46b83ce54dcc
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 double & FormulaToken::GetDoubleAsReference()
193 // This Get is worth an assert.
194 assert( !"virtual dummy called" );
195 static double fVal = 0.0;
196 return fVal;
199 sal_Int16 FormulaToken::GetDoubleType() const
201 SAL_WARN( "formula.core", "FormulaToken::GetDoubleType: virtual dummy called" );
202 return 0;
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" );
226 return 0;
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" );
237 return -1;
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" );
249 return 0;
252 short* FormulaToken::GetJump() const
254 SAL_WARN( "formula.core", "FormulaToken::GetJump: virtual dummy called" );
255 return nullptr;
259 const OUString& FormulaToken::GetExternal() const
261 SAL_WARN( "formula.core", "FormulaToken::GetExternal: virtual dummy called" );
262 static OUString aDummyString;
263 return aDummyString;
266 FormulaToken* FormulaToken::GetFAPOrigToken() const
268 SAL_WARN( "formula.core", "FormulaToken::GetFAPOrigToken: virtual dummy called" );
269 return nullptr;
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" );
286 return nullptr;
289 ScSingleRefData* FormulaToken::GetSingleRef()
291 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
292 return nullptr;
295 const ScComplexRefData* FormulaToken::GetDoubleRef() const
297 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
298 return nullptr;
301 ScComplexRefData* FormulaToken::GetDoubleRef()
303 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
304 return nullptr;
307 const ScSingleRefData* FormulaToken::GetSingleRef2() const
309 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
310 return nullptr;
313 ScSingleRefData* FormulaToken::GetSingleRef2()
315 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
316 return nullptr;
319 const ScMatrix* FormulaToken::GetMatrix() const
321 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
322 return nullptr;
325 ScMatrix* FormulaToken::GetMatrix()
327 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
328 return nullptr;
331 ScJumpMatrix* FormulaToken::GetJumpMatrix() const
333 OSL_FAIL( "FormulaToken::GetJumpMatrix: virtual dummy called" );
334 return nullptr;
336 const std::vector<ScComplexRefData>* FormulaToken::GetRefList() const
338 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
339 return nullptr;
342 std::vector<ScComplexRefData>* FormulaToken::GetRefList()
344 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
345 return nullptr;
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*/)
400 bool bError = false;
401 const OpCode eOpCode = static_cast<OpCode>(rToken.OpCode); //! assuming equal values for the moment
403 const uno::TypeClass eClass = rToken.Data.getValueTypeClass();
404 switch ( eClass )
406 case uno::TypeClass_VOID:
407 // empty data -> use AddOpCode (does some special cases)
408 AddOpCode( eOpCode );
409 break;
410 case uno::TypeClass_DOUBLE:
411 // double is only used for "push"
412 if ( eOpCode == ocPush )
413 AddDouble( rToken.Data.get<double>() );
414 else
415 bError = true;
416 break;
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) ) );
427 else
428 bError = true;
430 break;
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 )
437 AddBad( aStrVal );
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]));
449 else
450 bError = true; // unexpected string: don't know what to do with it
452 break;
453 default:
454 bError = true;
455 } // switch ( eClass )
456 return bError;
459 bool FormulaTokenArray::Fill(
460 const uno::Sequence<sheet::FormulaToken>& rSequence,
461 svl::SharedStringPool& rSPool, ExternalReferenceHelper* pExtRef )
463 bool bError = false;
464 const sal_Int32 nCount = rSequence.getLength();
465 for (sal_Int32 nPos=0; nPos<nCount; nPos++)
467 bool bOneError = AddFormulaToken(rSequence[nPos], rSPool, pExtRef);
468 if (bOneError)
470 AddOpCode( ocErrName); // add something that indicates an error
471 bError = true;
474 return bError;
477 void FormulaTokenArray::DelRPN()
479 if( nRPN )
481 FormulaToken** p = pRPN;
482 for( sal_uInt16 i = 0; i < nRPN; i++ )
484 (*p++)->DecRef();
486 delete [] pRPN;
488 pRPN = nullptr;
489 nRPN = 0;
492 FormulaToken* FormulaTokenArray::FirstToken() const
494 if (!pCode || nLen == 0)
495 return nullptr;
496 return pCode[0];
499 FormulaToken* FormulaTokenArray::PeekPrev( sal_uInt16 & nIdx ) const
501 if (0 < nIdx && nIdx <= nLen)
502 return pCode[--nIdx];
503 return nullptr;
506 FormulaToken* FormulaTokenArray::FirstRPNToken() const
508 if (!pRPN || nRPN == 0)
509 return nullptr;
510 return pRPN[0];
513 FormulaToken* FormulaTokenArray::LastRPNToken() const
515 if (!pRPN || nRPN == 0)
516 return nullptr;
517 return pRPN[nRPN - 1];
520 bool FormulaTokenArray::HasReferences() const
522 for (auto i: Tokens())
524 if (i->IsRef())
525 return true;
528 for (auto i: RPNTokens())
530 if (i->IsRef())
531 return true;
534 return false;
537 bool FormulaTokenArray::HasExternalRef() const
539 for (auto i: Tokens())
541 if (i->IsExternalRef())
542 return true;
544 return false;
547 bool FormulaTokenArray::HasOpCode( OpCode eOp ) const
549 for (auto i: Tokens())
551 if (i->GetOpCode() == eOp)
552 return true;
554 return false;
557 bool FormulaTokenArray::HasOpCodeRPN( OpCode eOp ) const
559 for (auto i: RPNTokens())
561 if (i->GetOpCode() == eOp)
562 return true;
564 return false;
567 bool FormulaTokenArray::HasNameOrColRowName() const
569 for (auto i: Tokens())
571 if (i->GetType() == svIndex || i->GetOpCode() == ocColRowName )
572 return true;
574 return false;
577 bool FormulaTokenArray::HasOpCodes(const unordered_opcode_set& rOpCodes) const
579 for (auto i: Tokens())
581 if (rOpCodes.count(i->GetOpCode()) > 0)
582 return true;
585 return false;
588 FormulaTokenArray::FormulaTokenArray() :
589 pRPN(nullptr),
590 nLen(0),
591 nRPN(0),
592 nError(FormulaError::NONE),
593 nMode(ScRecalcMode::NORMAL),
594 bHyperLink(false),
595 mbFromRangeName(false),
596 mbShareable(true),
597 mbFinalized(false)
601 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray& rArr )
603 Assign( 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 );
624 mbFinalized = true;
628 void FormulaTokenArray::Assign( const FormulaTokenArray& r )
630 nLen = r.nLen;
631 nRPN = r.nRPN;
632 nError = r.nError;
633 nMode = r.nMode;
634 bHyperLink = r.bHyperLink;
635 mbFromRangeName = r.mbFromRangeName;
636 mbShareable = r.mbShareable;
637 mbFinalized = r.mbFinalized;
638 pCode = nullptr;
639 pRPN = nullptr;
640 FormulaToken** pp;
641 if( nLen )
643 pCode.reset(new FormulaToken*[ nLen ]);
644 pp = pCode.get();
645 memcpy( pp, r.pCode.get(), nLen * sizeof( FormulaToken* ) );
646 for( sal_uInt16 i = 0; i < nLen; i++ )
647 (*pp++)->IncRef();
648 mbFinalized = true;
650 if( nRPN )
652 pp = pRPN = new FormulaToken*[ nRPN ];
653 memcpy( pp, r.pRPN, nRPN * sizeof( FormulaToken* ) );
654 for( sal_uInt16 i = 0; i < nRPN; i++ )
655 (*pp++)->IncRef();
659 void FormulaTokenArray::Move( FormulaTokenArray&& r )
661 pCode = std::move(r.pCode);
662 pRPN = r.pRPN;
663 r.pRPN = nullptr;
664 nLen = r.nLen;
665 r.nLen = 0;
666 nRPN = r.nRPN;
667 r.nRPN = 0;
668 nError = r.nError;
669 nMode = r.nMode;
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 )
679 assert( nLen == 0 );
680 assert( pCode == nullptr );
682 nLen = nCode;
683 pCode.reset(new FormulaToken*[ nLen ]);
684 mbFinalized = true;
686 for( sal_uInt16 i = 0; i < nLen; i++ )
688 FormulaToken *t = pTokens[ i ];
689 assert( t->GetOpCode() == ocStringXML );
690 pCode[ i ] = t;
691 t->IncRef();
695 FormulaTokenArray& FormulaTokenArray::operator=( const FormulaTokenArray& rArr )
697 if(this == &rArr)
698 return *this;
700 Clear();
701 Assign( rArr );
702 return *this;
705 FormulaTokenArray& FormulaTokenArray::operator=( FormulaTokenArray&& rArr )
707 Clear();
708 Move( std::move(rArr) );
709 return *this;
712 void FormulaTokenArray::Clear()
714 if( nRPN ) DelRPN();
715 if( pCode )
717 FormulaToken** p = pCode.get();
718 for( sal_uInt16 i = 0; i < nLen; i++ )
720 (*p++)->DecRef();
722 pCode.reset();
724 pRPN = nullptr;
725 nError = FormulaError::NONE;
726 nLen = nRPN = 0;
727 bHyperLink = false;
728 mbFromRangeName = false;
729 mbShareable = true;
730 mbFinalized = false;
731 ClearRecalcMode();
734 void FormulaTokenArray::CheckToken( const FormulaToken& /*r*/ )
736 // Do nothing.
739 void FormulaTokenArray::CheckAllRPNTokens()
741 if( nRPN )
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( )
758 return nullptr;
761 FormulaToken* FormulaTokenArray::ReplaceToken( sal_uInt16 nOffset, FormulaToken* t,
762 FormulaTokenArray::ReplaceMode eMode )
764 if (nOffset < nLen)
766 CheckToken(*t);
767 t->IncRef();
768 FormulaToken* p = pCode[nOffset];
769 pCode[nOffset] = t;
770 if (eMode == CODE_AND_RPN && p->GetRef() > 1)
772 for (sal_uInt16 i=0; i < nRPN; ++i)
774 if (pRPN[i] == p)
776 t->IncRef();
777 pRPN[i] = t;
778 p->DecRef();
779 if (p->GetRef() == 1)
780 break; // for
784 p->DecRef(); // may be dead now
785 return t;
787 else
789 t->DeleteIfZeroRef();
790 return nullptr;
794 sal_uInt16 FormulaTokenArray::RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount )
796 if (nOffset < nLen)
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];
805 if (p->GetRef() > 1)
807 for (sal_uInt16 i=0; i < nRPN; ++i)
809 if (pRPN[i] == p)
811 // Shift remaining tokens in pRPN down.
812 for (sal_uInt16 x=i+1; x < nRPN; ++x)
814 pRPN[x-1] = pRPN[x];
816 --nRPN;
818 p->DecRef();
819 if (p->GetRef() == 1)
820 break; // for
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];
832 nLen -= nCount;
834 return nCount;
836 else
838 SAL_WARN("formula.core","FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen);
839 return 0;
843 FormulaToken* FormulaTokenArray::Add( FormulaToken* t )
845 assert(!mbFinalized);
846 if (mbFinalized)
848 t->DeleteIfZeroRef();
849 return nullptr;
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;
858 if( !pCode )
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);
864 pCode.reset(tmp);
866 if( nLen < FORMULA_MAXTOKENS - 1 )
868 CheckToken(*t);
869 pCode[ nLen++ ] = t;
870 t->IncRef();
871 if( t->GetOpCode() == ocArrayClose )
872 return MergeArray();
873 return t;
875 else
877 t->DeleteIfZeroRef();
878 if ( nLen == FORMULA_MAXTOKENS - 1 )
880 t = new FormulaByteToken( ocStop );
881 pCode[ nLen++ ] = t;
882 t->IncRef();
884 return nullptr;
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);
923 if (nExclusive)
925 unsigned nExBit;
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)
932 break;
935 else
937 // Only one bit is set.
938 nExBit = nExclusive;
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 )
951 return false;
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 );
957 short sp = 0;
958 for ( auto t: RPNTokens() )
960 OpCode eOp = t->GetOpCode();
961 sal_uInt8 nParams = t->GetParamCount();
962 switch ( eOp )
964 case ocAdd :
965 case ocSub :
966 case ocMul :
967 case ocDiv :
968 case ocPow :
969 case ocPower :
970 case ocAmpersand :
971 case ocEqual :
972 case ocNotEqual :
973 case ocLess :
974 case ocGreater :
975 case ocLessEqual :
976 case ocGreaterEqual :
978 for ( sal_uInt8 k = nParams; k; k-- )
980 if ( sp >= k && pStack[sp-k]->GetType() == svDoubleRef )
982 pResult->Delete();
983 return true;
987 break;
988 default:
990 // added to avoid warnings
993 if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() ) )
994 pStack[sp++] = t;
995 else if (FormulaCompiler::IsOpCodeJumpCommand( eOp ))
996 { // ignore Jumps, pop previous Result (Condition)
997 if ( sp )
998 --sp;
1000 else
1001 { // pop parameters, push result
1002 sp = sal::static_int_cast<short>( sp - nParams );
1003 if ( sp < 0 )
1005 SAL_WARN("formula.core", "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
1006 sp = 0;
1008 pStack[sp++] = pResult;
1011 pResult->Delete();
1013 return false;
1016 // --- Formula rewrite of a token array
1018 inline bool MissingConventionODF::isRewriteNeeded( OpCode eOp ) const
1020 switch (eOp)
1022 case ocGammaDist:
1023 case ocPoissonDist:
1024 case ocAddress:
1025 case ocLogInv:
1026 case ocLogNormDist:
1027 case ocNormDist:
1028 return true;
1029 case ocMissing:
1030 case ocLog:
1031 return isPODF(); // rewrite only for PODF
1032 case ocDBCount:
1033 case ocDBCount2:
1034 return isODFF(); // rewrite only for ODFF
1035 default:
1036 return false;
1041 fdo 81596
1042 To be implemented yet:
1043 ocExternal: ?
1044 ocMacro: ?
1045 ocIndex: INDEX() ?
1047 inline bool MissingConventionOOXML::isRewriteNeeded( OpCode eOp )
1049 switch (eOp)
1051 case ocIf:
1053 case ocExternal:
1054 case ocEuroConvert:
1055 case ocMacro:
1057 case ocRound:
1058 case ocRoundUp:
1059 case ocRoundDown:
1061 case ocIndex:
1063 case ocCeil:
1064 case ocFloor:
1066 case ocGammaDist:
1067 case ocFDist_LT:
1068 case ocPoissonDist:
1069 case ocNormDist:
1070 case ocLogInv:
1071 case ocLogNormDist:
1072 case ocHypGeomDist:
1074 case ocDBCount:
1075 case ocDBCount2:
1076 return true;
1078 default:
1079 return false;
1083 namespace {
1085 class FormulaMissingContext
1087 public:
1088 const FormulaToken* mpFunc;
1089 int mnCurArg;
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
1102 if ( !mpFunc )
1103 return;
1105 switch (rConv.getConvention())
1107 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF:
1108 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF:
1110 switch (mpFunc->GetOpCode())
1112 case ocGammaDist:
1113 if (mnCurArg == 2)
1115 pNewArr->AddOpCode( ocSep );
1116 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1118 break;
1119 case ocPoissonDist:
1120 if (mnCurArg == 1)
1122 pNewArr->AddOpCode( ocSep );
1123 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1125 break;
1126 case ocNormDist:
1127 if ( mnCurArg == 2 )
1129 pNewArr->AddOpCode( ocSep );
1130 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1132 break;
1133 case ocLogInv:
1134 case ocLogNormDist:
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
1145 break;
1146 case ocLog:
1147 if ( rConv.isPODF() && mnCurArg == 0 )
1149 pNewArr->AddOpCode( ocSep );
1150 pNewArr->AddDouble( 10.0 ); // 2nd, basis 10
1152 break;
1153 default:
1154 break;
1157 break;
1158 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML:
1160 switch (mpFunc->GetOpCode())
1162 case ocIf:
1163 if( mnCurArg == 0 )
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
1171 break;
1173 case ocEuroConvert:
1174 if ( mnCurArg == 2 )
1176 pNewArr->AddOpCode( ocSep );
1177 pNewArr->AddDouble( 0.0 ); // 4th, FullPrecision = false()
1179 break;
1181 case ocPoissonDist:
1182 if (mnCurArg == 1)
1184 pNewArr->AddOpCode( ocSep );
1185 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1187 break;
1189 case ocGammaDist:
1190 case ocFDist_LT:
1191 case ocNormDist:
1192 if (mnCurArg == 2)
1194 pNewArr->AddOpCode( ocSep );
1195 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1197 break;
1199 case ocLogInv:
1200 case ocLogNormDist:
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
1211 break;
1213 case ocHypGeomDist:
1214 if ( mnCurArg == 3 )
1216 pNewArr->AddOpCode( ocSep );
1217 pNewArr->AddDouble( 0.0 ); // 5th, Cumulative = false()
1219 break;
1221 case ocRound:
1222 case ocRoundUp:
1223 case ocRoundDown:
1224 if( mnCurArg == 0 )
1226 // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel
1227 pNewArr->AddOpCode( ocSep );
1228 pNewArr->AddDouble( 0.0 ); // 2nd, 0.0
1230 break;
1232 default:
1233 break;
1236 break;
1241 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const
1243 if (mnCurArg == nArg)
1245 pNewArr->AddDouble( f );
1246 return true;
1248 return false;
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();
1259 if (!nLength)
1260 return false;
1262 sal_Unicode nLastChar = rName[ nLength - 1];
1263 if ( nLastChar != 't' && nLastChar != 'm' )
1264 return false;
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 );
1276 return false;
1279 bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
1281 if ( !mpFunc )
1282 return false;
1284 bool bRet = false;
1285 const OpCode eOp = mpFunc->GetOpCode();
1287 switch (rConv.getConvention())
1289 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF:
1291 // Add for ODFF
1292 switch (eOp)
1294 case ocAddress:
1295 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1296 default:
1297 break;
1300 break;
1301 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF:
1303 // Add for PODF
1304 switch (eOp)
1306 case ocAddress:
1307 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1308 case ocFixed:
1309 return AddDefaultArg( pNewArr, 1, 2.0 );
1310 case ocBetaDist:
1311 case ocBetaInv:
1312 case ocPMT:
1313 return AddDefaultArg( pNewArr, 3, 0.0 );
1314 case ocIpmt:
1315 case ocPpmt:
1316 return AddDefaultArg( pNewArr, 4, 0.0 );
1317 case ocPV:
1318 case ocFV:
1319 bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt
1320 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v
1321 break;
1322 case ocRate:
1323 bRet |= AddDefaultArg( pNewArr, 1, 0.0 ); // pmt
1324 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // fv
1325 bRet |= AddDefaultArg( pNewArr, 4, 0.0 ); // type
1326 break;
1327 case ocExternal:
1328 return AddMissingExternal( pNewArr );
1330 // --- more complex cases ---
1332 case ocOffset:
1333 // FIXME: rather tough
1334 // if arg 3 (height) omitted, export arg1 (rows)
1335 break;
1336 default:
1337 break;
1340 break;
1341 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML:
1343 switch (eOp)
1345 case ocExternal:
1346 return AddMissingExternal( pNewArr );
1347 default:
1348 break;
1351 break;
1354 return bRet;
1357 bool FormulaTokenArray::NeedsPodfRewrite( const MissingConventionODF & rConv )
1359 for ( auto i: Tokens() )
1361 if ( rConv.isRewriteNeeded( i->GetOpCode()))
1362 return true;
1364 return false;
1367 bool FormulaTokenArray::NeedsOoxmlRewrite()
1369 for ( auto i: Tokens() )
1371 if ( MissingConventionOOXML::isRewriteNeeded( i->GetOpCode()))
1372 return true;
1374 return false;
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.
1398 pCtx[0].Clear();
1399 int nFn = 0;
1400 int nOcas = 0;
1401 int nOcds = 0;
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() )
1410 bool bAdd = true;
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)
1424 bAdd = false;
1427 // Strip the 2nd argument (leaving empty) of DCOUNT() and DCOUNTA() if
1428 // it is 0.
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)
1443 bAdd = false;
1448 switch ( pCur->GetOpCode() )
1450 case ocOpen:
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
1464 break;
1465 case ocClose:
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()
1472 if (nFn > 0)
1473 --nFn;
1474 break;
1475 case ocSep:
1476 pCtx[ nFn ].mnCurArg++;
1477 // Omit leading separator of ADDRESS() parameter.
1478 if (nOcas && pOcas[ nOcas-1 ] == nFn && pCtx[ nFn ].mnCurArg == nOmitAddressArg)
1480 bAdd = false;
1482 break;
1483 case ocMissing:
1484 if ( bAdd )
1485 bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv );
1486 break;
1487 default:
1488 break;
1490 if (bAdd)
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 )
1497 switch ( eOp )
1499 case ocCeil :
1500 eOp = ocCeil_Math;
1501 break;
1502 case ocFloor :
1503 eOp = ocFloor_Math;
1504 break;
1505 case ocLogNormDist :
1506 eOp = ocLogNormDist_MS;
1507 break;
1508 default :
1509 eOp = ocNone;
1510 break;
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 );
1521 else
1522 pNewArr->AddToken( *pCur );
1526 if (pOcds != &aOpCodeDcountStack[0])
1527 delete [] pOcds;
1528 if (pOcas != &aOpCodeAddressStack[0])
1529 delete [] pOcas;
1530 if (pCtx != &aCtx[0])
1531 delete [] pCtx;
1533 return pNewArr;
1536 namespace {
1537 inline bool isWhitespace( OpCode eOp ) { return eOp == ocSpaces || eOp == ocWhitespace; }
1540 bool FormulaTokenArray::MayReferenceFollow()
1542 if ( !pCode || nLen <= 0 )
1543 return false;
1545 // ignore trailing spaces
1546 sal_uInt16 i = nLen - 1;
1547 while (i > 0 && isWhitespace( pCode[i]->GetOpCode()))
1549 --i;
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 )
1558 return true;
1561 return false;
1563 FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp )
1565 FormulaToken* pRet = nullptr;
1566 switch ( eOp )
1568 case ocOpen:
1569 case ocClose:
1570 case ocSep:
1571 case ocArrayOpen:
1572 case ocArrayClose:
1573 case ocArrayRowSep:
1574 case ocArrayColSep:
1575 pRet = new FormulaToken( svSep,eOp );
1576 break;
1577 case ocIf:
1578 case ocIfError:
1579 case ocIfNA:
1580 case ocChoose:
1582 short nJump[FORMULA_MAXJUMPCOUNT + 1];
1583 if ( eOp == ocIf )
1584 nJump[ 0 ] = 3;
1585 else if ( eOp == ocChoose )
1586 nJump[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
1587 else
1588 nJump[ 0 ] = 2;
1589 pRet = new FormulaJumpToken( eOp, nJump );
1591 break;
1592 default:
1593 pRet = new FormulaByteToken( eOp, 0, ParamClass::Unknown );
1594 break;
1596 return Add( pRet );
1599 void FormulaTokenArray::ReinternStrings( svl::SharedStringPool& rPool )
1601 for (auto i: Tokens())
1603 switch (i->GetType())
1605 case svString:
1606 i->SetString( rPool.intern( i->GetString().getString()));
1607 break;
1608 default:
1609 ; // nothing
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()
1640 maStack.pop_back();
1643 void FormulaTokenIterator::Reset()
1645 while( maStack.size() > 1 )
1646 maStack.pop_back();
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 )
1659 return t;
1662 return nullptr;
1665 const FormulaToken* FormulaTokenIterator::Next()
1667 const FormulaToken* t = GetNonEndOfPathToken( ++maStack.back().nPC );
1668 if( !t && maStack.size() > 1 )
1670 Pop();
1671 t = Next();
1673 return t;
1676 const FormulaToken* FormulaTokenIterator::PeekNextOperator()
1678 const FormulaToken* t = nullptr;
1679 short nIdx = maStack.back().nPC;
1680 for (;;)
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();
1689 maStack.pop_back();
1690 t = PeekNextOperator();
1691 maStack.push_back(aHere);
1693 return t;
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 )
1711 maStack.clear();
1712 Push( &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;
1725 return nullptr;
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() )
1740 case svSingleRef:
1741 case svDoubleRef:
1742 case svExternalSingleRef:
1743 case svExternalDoubleRef:
1744 return t;
1745 default:
1747 // added to avoid warnings
1751 return nullptr;
1754 FormulaToken* FormulaTokenArrayPlainIterator::GetNextColRowName()
1756 while( mnIndex < mpFTA->GetLen() )
1758 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1759 if ( t->GetOpCode() == ocColRowName )
1760 return t;
1762 return nullptr;
1765 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceRPN()
1767 while( mnIndex < mpFTA->GetCodeLen() )
1769 FormulaToken* t = mpFTA->GetCode()[ mnIndex++ ];
1770 switch( t->GetType() )
1772 case svSingleRef:
1773 case svDoubleRef:
1774 case svExternalSingleRef:
1775 case svExternalDoubleRef:
1776 return t;
1777 default:
1779 // added to avoid warnings
1783 return nullptr;
1786 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceOrName()
1788 if( !mpFTA->GetArray() )
1789 return nullptr;
1791 while ( mnIndex < mpFTA->GetLen() )
1793 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1794 switch( t->GetType() )
1796 case svSingleRef:
1797 case svDoubleRef:
1798 case svIndex:
1799 case svExternalSingleRef:
1800 case svExternalDoubleRef:
1801 case svExternalName:
1802 return t;
1803 default:
1805 // added to avoid warnings
1809 return nullptr;
1812 FormulaToken* FormulaTokenArrayPlainIterator::Next()
1814 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1815 return mpFTA->GetArray()[ mnIndex++ ];
1816 else
1817 return nullptr;
1820 FormulaToken* FormulaTokenArrayPlainIterator::NextNoSpaces()
1822 if( mpFTA->GetArray() )
1824 while ((mnIndex < mpFTA->GetLen()) && isWhitespace( mpFTA->GetArray()[ mnIndex ]->GetOpCode()))
1825 ++mnIndex;
1826 if( mnIndex < mpFTA->GetLen() )
1827 return mpFTA->GetArray()[ mnIndex++ ];
1829 return nullptr;
1832 FormulaToken* FormulaTokenArrayPlainIterator::NextRPN()
1834 if( mpFTA->GetCode() && mnIndex < mpFTA->GetCodeLen() )
1835 return mpFTA->GetCode()[ mnIndex++ ];
1836 else
1837 return nullptr;
1840 FormulaToken* FormulaTokenArrayPlainIterator::PrevRPN()
1842 if( mpFTA->GetCode() && mnIndex )
1843 return mpFTA->GetCode()[ --mnIndex ];
1844 else
1845 return nullptr;
1848 FormulaToken* FormulaTokenArrayPlainIterator::PeekNext()
1850 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1851 return mpFTA->GetArray()[ mnIndex ];
1852 else
1853 return nullptr;
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()))
1862 j++;
1863 if ( j < mpFTA->GetLen() )
1864 return mpFTA->GetArray()[ j ];
1865 else
1866 return nullptr;
1868 else
1869 return nullptr;
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 )
1878 j--;
1879 if (j > 0 || !isWhitespace( mpFTA->GetArray()[j]->GetOpCode()))
1880 return mpFTA->GetArray()[ j ];
1881 else
1882 return nullptr;
1884 else
1885 return nullptr;
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;
1896 else
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().
1911 return 0;
1914 bool FormulaDoubleToken::operator==( const FormulaToken& r ) const
1916 return FormulaToken::operator==( r ) && fDouble == r.GetDouble();
1919 sal_Int16 FormulaTypedDoubleToken::GetDoubleType() const
1921 return mnType;
1924 void FormulaTypedDoubleToken::SetDoubleType( sal_Int16 nType )
1926 mnType = 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
1949 return maString;
1952 void FormulaStringToken::SetString( const svl::SharedString& rStr )
1954 maString = 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
1975 return maString;
1978 void FormulaStringOpToken::SetString( const svl::SharedString& rStr )
1980 maString = 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 );
2030 } // formula
2033 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */