bump product version to 7.2.5.1
[LibreOffice.git] / formula / source / core / api / token.cxx
blob6464f3d52b0f4c1e6a5a364c90287ae0a36d10a9
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>
37 namespace formula
39 using namespace com::sun::star;
42 // --- helpers --------------------------------------------------------------
44 static bool lcl_IsReference( OpCode eOp, StackVar eType )
46 return
47 (eOp == ocPush && (eType == svSingleRef || eType == svDoubleRef))
48 || (eOp == ocColRowNameAuto && eType == svDoubleRef)
49 || (eOp == ocColRowName && eType == svSingleRef)
50 || (eOp == ocMatRef && eType == svSingleRef)
54 // --- class FormulaToken --------------------------------------------------------
56 FormulaToken::FormulaToken( StackVar eTypeP, OpCode e ) :
57 eOp(e), eType( eTypeP ), mnRefCnt(0)
61 FormulaToken::FormulaToken( const FormulaToken& r ) :
62 eOp(r.eOp), eType( r.eType ), mnRefCnt(0)
66 FormulaToken::~FormulaToken()
70 bool FormulaToken::IsFunction() const
72 return (eOp != ocPush && eOp != ocBad && eOp != ocColRowName &&
73 eOp != ocColRowNameAuto && eOp != ocName && eOp != ocDBArea &&
74 eOp != ocTableRef &&
75 (GetByte() != 0 // x parameters
76 || (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR) // no parameter
77 || FormulaCompiler::IsOpCodeJumpCommand( eOp ) // @ jump commands
78 || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) // one parameter
79 || (SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR) // x parameters (cByte==0 in
80 // FuncAutoPilot)
81 || eOp == ocMacro || eOp == ocExternal // macros, AddIns
82 || eOp == ocAnd || eOp == ocOr // former binary, now x parameters
83 || (eOp >= ocInternalBegin && eOp <= ocInternalEnd) // internal
84 ));
88 sal_uInt8 FormulaToken::GetParamCount() const
90 if ( eOp < SC_OPCODE_STOP_DIV && eOp != ocExternal && eOp != ocMacro &&
91 !FormulaCompiler::IsOpCodeJumpCommand( eOp ) &&
92 eOp != ocPercentSign )
93 return 0; // parameters and specials
94 // ocIf... jump commands not for FAP, have cByte then
95 //2do: bool parameter whether FAP or not?
96 else if ( GetByte() )
97 return GetByte(); // all functions, also ocExternal and ocMacro
98 else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP)
99 return 2; // binary
100 else if ((SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)
101 || eOp == ocPercentSign)
102 return 1; // unary
103 else if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
104 return 0; // no parameter
105 else if (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR)
106 return 1; // one parameter
107 else if (FormulaCompiler::IsOpCodeJumpCommand( eOp ))
108 return 1; // only the condition counts as parameter
109 else
110 return 0; // all the rest, no Parameter, or
111 // if so then it should be in cByte
114 bool FormulaToken::IsExternalRef() const
116 bool bRet = false;
117 switch (eType)
119 case svExternalSingleRef:
120 case svExternalDoubleRef:
121 case svExternalName:
122 bRet = true;
123 break;
124 default:
125 bRet = false;
126 break;
128 return bRet;
131 bool FormulaToken::IsRef() const
133 switch (eType)
135 case svSingleRef:
136 case svDoubleRef:
137 case svExternalSingleRef:
138 case svExternalDoubleRef:
139 return true;
140 default:
141 if (eOp == ocTableRef)
142 return true;
145 return false;
148 bool FormulaToken::IsInForceArray() const
150 ParamClass eParam = GetInForceArray();
151 return eParam == ParamClass::ForceArray || eParam == ParamClass::ReferenceOrForceArray
152 || eParam == ParamClass::ReferenceOrRefArray || eParam == ParamClass::ForceArrayReturn;
155 bool FormulaToken::operator==( const FormulaToken& rToken ) const
157 // don't compare reference count!
158 return eType == rToken.eType && GetOpCode() == rToken.GetOpCode();
162 // --- virtual dummy methods -------------------------------------------------
164 sal_uInt8 FormulaToken::GetByte() const
166 // ok to be called for any derived class
167 return 0;
170 void FormulaToken::SetByte( sal_uInt8 )
172 assert( !"virtual dummy called" );
175 ParamClass FormulaToken::GetInForceArray() const
177 // ok to be called for any derived class
178 return ParamClass::Unknown;
181 void FormulaToken::SetInForceArray( ParamClass )
183 assert( !"virtual dummy called" );
186 double FormulaToken::GetDouble() const
188 // This Get is worth an assert.
189 assert( !"virtual dummy called" );
190 return 0.0;
193 double & FormulaToken::GetDoubleAsReference()
195 // This Get is worth an assert.
196 assert( !"virtual dummy called" );
197 static double fVal = 0.0;
198 return fVal;
201 sal_Int16 FormulaToken::GetDoubleType() const
203 SAL_WARN( "formula.core", "FormulaToken::GetDoubleType: virtual dummy called" );
204 return 0;
207 void FormulaToken::SetDoubleType( sal_Int16 )
209 assert( !"virtual dummy called" );
212 const svl::SharedString INVALID_STRING;
214 const svl::SharedString & FormulaToken::GetString() const
216 SAL_WARN( "formula.core", "FormulaToken::GetString: virtual dummy called" );
217 return INVALID_STRING; // invalid string
220 void FormulaToken::SetString( const svl::SharedString& )
222 assert( !"virtual dummy called" );
225 sal_uInt16 FormulaToken::GetIndex() const
227 SAL_WARN( "formula.core", "FormulaToken::GetIndex: virtual dummy called" );
228 return 0;
231 void FormulaToken::SetIndex( sal_uInt16 )
233 assert( !"virtual dummy called" );
236 sal_Int16 FormulaToken::GetSheet() const
238 SAL_WARN( "formula.core", "FormulaToken::GetSheet: virtual dummy called" );
239 return -1;
242 void FormulaToken::SetSheet( sal_Int16 )
244 assert( !"virtual dummy called" );
247 short* FormulaToken::GetJump() const
249 SAL_WARN( "formula.core", "FormulaToken::GetJump: virtual dummy called" );
250 return nullptr;
254 const OUString& FormulaToken::GetExternal() const
256 SAL_WARN( "formula.core", "FormulaToken::GetExternal: virtual dummy called" );
257 static OUString aDummyString;
258 return aDummyString;
261 FormulaToken* FormulaToken::GetFAPOrigToken() const
263 SAL_WARN( "formula.core", "FormulaToken::GetFAPOrigToken: virtual dummy called" );
264 return nullptr;
267 FormulaError FormulaToken::GetError() const
269 SAL_WARN( "formula.core", "FormulaToken::GetError: virtual dummy called" );
270 return FormulaError::NONE;
273 void FormulaToken::SetError( FormulaError )
275 assert( !"virtual dummy called" );
278 const ScSingleRefData* FormulaToken::GetSingleRef() const
280 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
281 return nullptr;
284 ScSingleRefData* FormulaToken::GetSingleRef()
286 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
287 return nullptr;
290 const ScComplexRefData* FormulaToken::GetDoubleRef() const
292 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
293 return nullptr;
296 ScComplexRefData* FormulaToken::GetDoubleRef()
298 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
299 return nullptr;
302 const ScSingleRefData* FormulaToken::GetSingleRef2() const
304 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
305 return nullptr;
308 ScSingleRefData* FormulaToken::GetSingleRef2()
310 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
311 return nullptr;
314 const ScMatrix* FormulaToken::GetMatrix() const
316 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
317 return nullptr;
320 ScMatrix* FormulaToken::GetMatrix()
322 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
323 return nullptr;
326 ScJumpMatrix* FormulaToken::GetJumpMatrix() const
328 OSL_FAIL( "FormulaToken::GetJumpMatrix: virtual dummy called" );
329 return nullptr;
331 const std::vector<ScComplexRefData>* FormulaToken::GetRefList() const
333 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
334 return nullptr;
337 std::vector<ScComplexRefData>* FormulaToken::GetRefList()
339 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
340 return nullptr;
343 bool FormulaToken::TextEqual( const FormulaToken& rToken ) const
345 return *this == rToken;
348 // real implementations of virtual functions
351 sal_uInt8 FormulaByteToken::GetByte() const { return nByte; }
352 void FormulaByteToken::SetByte( sal_uInt8 n ) { nByte = n; }
353 ParamClass FormulaByteToken::GetInForceArray() const { return eInForceArray; }
354 void FormulaByteToken::SetInForceArray( ParamClass c ) { eInForceArray = c; }
355 bool FormulaByteToken::operator==( const FormulaToken& r ) const
357 return FormulaToken::operator==( r ) && nByte == r.GetByte() &&
358 eInForceArray == r.GetInForceArray();
362 FormulaToken* FormulaFAPToken::GetFAPOrigToken() const { return pOrigToken.get(); }
363 bool FormulaFAPToken::operator==( const FormulaToken& r ) const
365 return FormulaByteToken::operator==( r ) && pOrigToken == r.GetFAPOrigToken();
369 short* FormulaJumpToken::GetJump() const { return pJump.get(); }
370 ParamClass FormulaJumpToken::GetInForceArray() const { return eInForceArray; }
371 void FormulaJumpToken::SetInForceArray( ParamClass c ) { eInForceArray = c; }
372 bool FormulaJumpToken::operator==( const FormulaToken& r ) const
374 return FormulaToken::operator==( r ) && pJump[0] == r.GetJump()[0] &&
375 memcmp( pJump.get()+1, r.GetJump()+1, pJump[0] * sizeof(short) ) == 0 &&
376 eInForceArray == r.GetInForceArray();
378 FormulaJumpToken::~FormulaJumpToken()
383 bool FormulaTokenArray::AddFormulaToken(
384 const sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool, ExternalReferenceHelper* /*pExtRef*/)
386 bool bError = false;
387 const OpCode eOpCode = static_cast<OpCode>(rToken.OpCode); //! assuming equal values for the moment
389 const uno::TypeClass eClass = rToken.Data.getValueTypeClass();
390 switch ( eClass )
392 case uno::TypeClass_VOID:
393 // empty data -> use AddOpCode (does some special cases)
394 AddOpCode( eOpCode );
395 break;
396 case uno::TypeClass_DOUBLE:
397 // double is only used for "push"
398 if ( eOpCode == ocPush )
399 AddDouble( rToken.Data.get<double>() );
400 else
401 bError = true;
402 break;
403 case uno::TypeClass_LONG:
405 // long is svIndex, used for name / database area, or "byte" for spaces
406 sal_Int32 nValue = rToken.Data.get<sal_Int32>();
407 if ( eOpCode == ocDBArea )
408 Add( new formula::FormulaIndexToken( eOpCode, static_cast<sal_uInt16>(nValue) ) );
409 else if ( eOpCode == ocTableRef )
410 bError = true; /* TODO: implementation */
411 else if ( eOpCode == ocSpaces )
412 Add( new formula::FormulaByteToken( ocSpaces, static_cast<sal_uInt8>(nValue) ) );
413 else
414 bError = true;
416 break;
417 case uno::TypeClass_STRING:
419 OUString aStrVal( rToken.Data.get<OUString>() );
420 if ( eOpCode == ocPush )
421 AddString(rSPool.intern(aStrVal));
422 else if ( eOpCode == ocBad )
423 AddBad( aStrVal );
424 else if ( eOpCode == ocStringXML )
425 AddStringXML( aStrVal );
426 else if ( eOpCode == ocExternal || eOpCode == ocMacro )
427 Add( new formula::FormulaExternalToken( eOpCode, aStrVal ) );
428 else
429 bError = true; // unexpected string: don't know what to do with it
431 break;
432 default:
433 bError = true;
434 } // switch ( eClass )
435 return bError;
438 bool FormulaTokenArray::Fill(
439 const uno::Sequence<sheet::FormulaToken>& rSequence,
440 svl::SharedStringPool& rSPool, ExternalReferenceHelper* pExtRef )
442 bool bError = false;
443 const sal_Int32 nCount = rSequence.getLength();
444 for (sal_Int32 nPos=0; nPos<nCount; nPos++)
446 bool bOneError = AddFormulaToken(rSequence[nPos], rSPool, pExtRef);
447 if (bOneError)
449 AddOpCode( ocErrName); // add something that indicates an error
450 bError = true;
453 return bError;
456 void FormulaTokenArray::DelRPN()
458 if( nRPN )
460 FormulaToken** p = pRPN;
461 for( sal_uInt16 i = 0; i < nRPN; i++ )
463 (*p++)->DecRef();
465 delete [] pRPN;
467 pRPN = nullptr;
468 nRPN = 0;
471 FormulaToken* FormulaTokenArray::FirstToken() const
473 if (!pCode || nLen == 0)
474 return nullptr;
475 return pCode[0];
478 FormulaToken* FormulaTokenArray::PeekPrev( sal_uInt16 & nIdx ) const
480 if (0 < nIdx && nIdx <= nLen)
481 return pCode[--nIdx];
482 return nullptr;
485 FormulaToken* FormulaTokenArray::FirstRPNToken() const
487 if (!pRPN || nRPN == 0)
488 return nullptr;
489 return pRPN[0];
492 bool FormulaTokenArray::HasReferences() const
494 for (auto i: Tokens())
496 if (i->IsRef())
497 return true;
500 for (auto i: RPNTokens())
502 if (i->IsRef())
503 return true;
506 return false;
509 bool FormulaTokenArray::HasExternalRef() const
511 for (auto i: Tokens())
513 if (i->IsExternalRef())
514 return true;
516 return false;
519 bool FormulaTokenArray::HasOpCode( OpCode eOp ) const
521 for (auto i: Tokens())
523 if (i->GetOpCode() == eOp)
524 return true;
526 return false;
529 bool FormulaTokenArray::HasOpCodeRPN( OpCode eOp ) const
531 for (auto i: RPNTokens())
533 if (i->GetOpCode() == eOp)
534 return true;
536 return false;
539 bool FormulaTokenArray::HasNameOrColRowName() const
541 for (auto i: Tokens())
543 if (i->GetType() == svIndex || i->GetOpCode() == ocColRowName )
544 return true;
546 return false;
549 bool FormulaTokenArray::HasOpCodes(const unordered_opcode_set& rOpCodes) const
551 for (auto i: Tokens())
553 if (rOpCodes.count(i->GetOpCode()) > 0)
554 return true;
557 return false;
560 FormulaTokenArray::FormulaTokenArray() :
561 pRPN(nullptr),
562 nLen(0),
563 nRPN(0),
564 nError(FormulaError::NONE),
565 nMode(ScRecalcMode::NORMAL),
566 bHyperLink(false),
567 mbFromRangeName(false),
568 mbShareable(true),
569 mbFinalized(false)
573 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray& rArr )
575 Assign( rArr );
578 FormulaTokenArray::~FormulaTokenArray()
580 FormulaTokenArray::Clear();
583 void FormulaTokenArray::Finalize()
585 if( nLen && !mbFinalized )
587 // Add() overallocates, so reallocate to the minimum needed size.
588 std::unique_ptr<FormulaToken*[]> newCode(new FormulaToken*[ nLen ]);
589 std::copy(&pCode[0], &pCode[nLen], newCode.get());
590 pCode = std::move( newCode );
591 mbFinalized = true;
595 void FormulaTokenArray::Assign( const FormulaTokenArray& r )
597 nLen = r.nLen;
598 nRPN = r.nRPN;
599 nError = r.nError;
600 nMode = r.nMode;
601 bHyperLink = r.bHyperLink;
602 mbFromRangeName = r.mbFromRangeName;
603 mbShareable = r.mbShareable;
604 mbFinalized = r.mbFinalized;
605 pCode = nullptr;
606 pRPN = nullptr;
607 FormulaToken** pp;
608 if( nLen )
610 pCode.reset(new FormulaToken*[ nLen ]);
611 pp = pCode.get();
612 memcpy( pp, r.pCode.get(), nLen * sizeof( FormulaToken* ) );
613 for( sal_uInt16 i = 0; i < nLen; i++ )
614 (*pp++)->IncRef();
615 mbFinalized = true;
617 if( nRPN )
619 pp = pRPN = new FormulaToken*[ nRPN ];
620 memcpy( pp, r.pRPN, nRPN * sizeof( FormulaToken* ) );
621 for( sal_uInt16 i = 0; i < nRPN; i++ )
622 (*pp++)->IncRef();
626 /// Optimisation for efficiently creating StringXML placeholders
627 void FormulaTokenArray::Assign( sal_uInt16 nCode, FormulaToken **pTokens )
629 assert( nLen == 0 );
630 assert( pCode == nullptr );
632 nLen = nCode;
633 pCode.reset(new FormulaToken*[ nLen ]);
634 mbFinalized = true;
636 for( sal_uInt16 i = 0; i < nLen; i++ )
638 FormulaToken *t = pTokens[ i ];
639 assert( t->GetOpCode() == ocStringXML );
640 pCode[ i ] = t;
641 t->IncRef();
645 FormulaTokenArray& FormulaTokenArray::operator=( const FormulaTokenArray& rArr )
647 if(this == &rArr)
648 return *this;
650 Clear();
651 Assign( rArr );
652 return *this;
655 void FormulaTokenArray::Clear()
657 if( nRPN ) DelRPN();
658 if( pCode )
660 FormulaToken** p = pCode.get();
661 for( sal_uInt16 i = 0; i < nLen; i++ )
663 (*p++)->DecRef();
665 pCode.reset();
667 pRPN = nullptr;
668 nError = FormulaError::NONE;
669 nLen = nRPN = 0;
670 bHyperLink = false;
671 mbFromRangeName = false;
672 mbShareable = true;
673 mbFinalized = false;
674 ClearRecalcMode();
677 void FormulaTokenArray::CheckToken( const FormulaToken& /*r*/ )
679 // Do nothing.
682 void FormulaTokenArray::CheckAllRPNTokens()
684 if( nRPN )
686 FormulaToken** p = pRPN;
687 for( sal_uInt16 i = 0; i < nRPN; i++ )
689 CheckToken( *p[ i ] );
694 FormulaToken* FormulaTokenArray::AddToken( const FormulaToken& r )
696 return Add( r.Clone() );
699 FormulaToken* FormulaTokenArray::MergeArray( )
701 return nullptr;
704 FormulaToken* FormulaTokenArray::ReplaceToken( sal_uInt16 nOffset, FormulaToken* t,
705 FormulaTokenArray::ReplaceMode eMode )
707 if (nOffset < nLen)
709 CheckToken(*t);
710 t->IncRef();
711 FormulaToken* p = pCode[nOffset];
712 pCode[nOffset] = t;
713 if (eMode == CODE_AND_RPN && p->GetRef() > 1)
715 for (sal_uInt16 i=0; i < nRPN; ++i)
717 if (pRPN[i] == p)
719 t->IncRef();
720 pRPN[i] = t;
721 p->DecRef();
722 if (p->GetRef() == 1)
723 break; // for
727 p->DecRef(); // may be dead now
728 return t;
730 else
732 t->DeleteIfZeroRef();
733 return nullptr;
737 sal_uInt16 FormulaTokenArray::RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount )
739 if (nOffset < nLen)
741 SAL_WARN_IF( nOffset + nCount > nLen, "formula.core",
742 "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen);
743 const sal_uInt16 nStop = ::std::min( static_cast<sal_uInt16>(nOffset + nCount), nLen);
744 nCount = nStop - nOffset;
745 for (sal_uInt16 j = nOffset; j < nStop; ++j)
747 FormulaToken* p = pCode[j];
748 if (p->GetRef() > 1)
750 for (sal_uInt16 i=0; i < nRPN; ++i)
752 if (pRPN[i] == p)
754 // Shift remaining tokens in pRPN down.
755 for (sal_uInt16 x=i+1; x < nRPN; ++x)
757 pRPN[x-1] = pRPN[x];
759 --nRPN;
761 p->DecRef();
762 if (p->GetRef() == 1)
763 break; // for
767 p->DecRef(); // may be dead now
770 // Shift remaining tokens in pCode down.
771 for (sal_uInt16 x = nStop; x < nLen; ++x)
773 pCode[x-nCount] = pCode[x];
775 nLen -= nCount;
777 return nCount;
779 else
781 SAL_WARN("formula.core","FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen);
782 return 0;
786 FormulaToken* FormulaTokenArray::Add( FormulaToken* t )
788 assert(!mbFinalized);
789 if (mbFinalized)
791 t->DeleteIfZeroRef();
792 return nullptr;
795 // Allocating an array of size FORMULA_MAXTOKENS is simple, but that results in relatively large
796 // allocations that malloc() implementations usually do not handle as efficiently as smaller
797 // sizes (not only in terms of memory usage but also speed). Since most token arrays are going
798 // to be small, start with a small array and resize only if needed. Eventually Finalize() will
799 // reallocate the memory to size exactly matching the requirements.
800 const size_t MAX_FAST_TOKENS = 32;
801 if( !pCode )
802 pCode.reset(new FormulaToken*[ MAX_FAST_TOKENS ]);
803 if( nLen == MAX_FAST_TOKENS )
805 FormulaToken** tmp = new FormulaToken*[ FORMULA_MAXTOKENS ];
806 std::copy(&pCode[0], &pCode[MAX_FAST_TOKENS], tmp);
807 pCode.reset(tmp);
809 if( nLen < FORMULA_MAXTOKENS - 1 )
811 CheckToken(*t);
812 pCode[ nLen++ ] = t;
813 t->IncRef();
814 if( t->GetOpCode() == ocArrayClose )
815 return MergeArray();
816 return t;
818 else
820 t->DeleteIfZeroRef();
821 if ( nLen == FORMULA_MAXTOKENS - 1 )
823 t = new FormulaByteToken( ocStop );
824 pCode[ nLen++ ] = t;
825 t->IncRef();
827 return nullptr;
831 FormulaToken* FormulaTokenArray::AddString( const svl::SharedString& rStr )
833 return Add( new FormulaStringToken( rStr ) );
836 FormulaToken* FormulaTokenArray::AddDouble( double fVal )
838 return Add( new FormulaDoubleToken( fVal ) );
841 void FormulaTokenArray::AddExternal( const sal_Unicode* pStr )
843 AddExternal( OUString( pStr ) );
846 FormulaToken* FormulaTokenArray::AddExternal( const OUString& rStr,
847 OpCode eOp /* = ocExternal */ )
849 return Add( new FormulaExternalToken( eOp, rStr ) );
852 FormulaToken* FormulaTokenArray::AddBad( const OUString& rStr )
854 return Add( new FormulaStringOpToken( ocBad, svl::SharedString( rStr ) ) ); // string not interned
857 FormulaToken* FormulaTokenArray::AddStringXML( const OUString& rStr )
859 return Add( new FormulaStringOpToken( ocStringXML, svl::SharedString( rStr ) ) ); // string not interned
863 void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits )
865 const unsigned nExclusive = static_cast<sal_uInt8>(nBits & ScRecalcMode::EMask);
866 if (nExclusive)
868 unsigned nExBit;
869 if (nExclusive & (nExclusive - 1))
871 // More than one bit set, use highest priority.
872 for (nExBit = 1; (nExBit & static_cast<sal_uInt8>(ScRecalcMode::EMask)) != 0; nExBit <<= 1)
874 if (nExclusive & nExBit)
875 break;
878 else
880 // Only one bit is set.
881 nExBit = nExclusive;
883 // Set exclusive bit if priority is higher than existing.
884 if (nExBit < static_cast<sal_uInt8>(nMode & ScRecalcMode::EMask))
885 SetMaskedRecalcMode( static_cast<ScRecalcMode>(nExBit));
887 SetCombinedBitsRecalcMode( nBits );
891 bool FormulaTokenArray::HasMatrixDoubleRefOps() const
893 if ( pRPN && nRPN )
895 // RPN-Interpreter simulation.
896 // Simply assumes a double as return value of each function.
897 std::unique_ptr<FormulaToken*[]> pStack(new FormulaToken* [nRPN]);
898 FormulaToken* pResult = new FormulaDoubleToken( 0.0 );
899 short sp = 0;
900 for ( auto t: RPNTokens() )
902 OpCode eOp = t->GetOpCode();
903 sal_uInt8 nParams = t->GetParamCount();
904 switch ( eOp )
906 case ocAdd :
907 case ocSub :
908 case ocMul :
909 case ocDiv :
910 case ocPow :
911 case ocPower :
912 case ocAmpersand :
913 case ocEqual :
914 case ocNotEqual :
915 case ocLess :
916 case ocGreater :
917 case ocLessEqual :
918 case ocGreaterEqual :
920 for ( sal_uInt8 k = nParams; k; k-- )
922 if ( sp >= k && pStack[sp-k]->GetType() == svDoubleRef )
924 pResult->Delete();
925 return true;
929 break;
930 default:
932 // added to avoid warnings
935 if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() ) )
936 pStack[sp++] = t;
937 else if (FormulaCompiler::IsOpCodeJumpCommand( eOp ))
938 { // ignore Jumps, pop previous Result (Condition)
939 if ( sp )
940 --sp;
942 else
943 { // pop parameters, push result
944 sp = sal::static_int_cast<short>( sp - nParams );
945 if ( sp < 0 )
947 SAL_WARN("formula.core", "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
948 sp = 0;
950 pStack[sp++] = pResult;
953 pResult->Delete();
956 return false;
959 // --- Formula rewrite of a token array
961 inline bool MissingConventionODF::isRewriteNeeded( OpCode eOp ) const
963 switch (eOp)
965 case ocGammaDist:
966 case ocPoissonDist:
967 case ocAddress:
968 case ocLogInv:
969 case ocLogNormDist:
970 case ocNormDist:
971 return true;
972 case ocMissing:
973 case ocLog:
974 return isPODF(); // rewrite only for PODF
975 case ocDBCount:
976 case ocDBCount2:
977 return isODFF(); // rewrite only for ODFF
978 default:
979 return false;
984 fdo 81596
985 To be implemented yet:
986 ocExternal: ?
987 ocMacro: ?
988 ocIndex: INDEX() ?
990 inline bool MissingConventionOOXML::isRewriteNeeded( OpCode eOp )
992 switch (eOp)
994 case ocIf:
996 case ocExternal:
997 case ocEuroConvert:
998 case ocMacro:
1000 case ocRound:
1001 case ocRoundUp:
1002 case ocRoundDown:
1004 case ocIndex:
1006 case ocCeil:
1007 case ocFloor:
1009 case ocGammaDist:
1010 case ocFDist_LT:
1011 case ocPoissonDist:
1012 case ocNormDist:
1013 case ocLogInv:
1014 case ocLogNormDist:
1015 case ocHypGeomDist:
1017 case ocDBCount:
1018 case ocDBCount2:
1019 return true;
1021 default:
1022 return false;
1026 namespace {
1028 class FormulaMissingContext
1030 public:
1031 const FormulaToken* mpFunc;
1032 int mnCurArg;
1034 void Clear() { mpFunc = nullptr; mnCurArg = 0; }
1035 inline bool AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const;
1036 bool AddMissingExternal( FormulaTokenArray* pNewArr ) const;
1037 bool AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
1038 void AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
1043 void FormulaMissingContext::AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
1045 if ( !mpFunc )
1046 return;
1048 switch (rConv.getConvention())
1050 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF:
1051 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF:
1053 switch (mpFunc->GetOpCode())
1055 case ocGammaDist:
1056 if (mnCurArg == 2)
1058 pNewArr->AddOpCode( ocSep );
1059 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1061 break;
1062 case ocPoissonDist:
1063 if (mnCurArg == 1)
1065 pNewArr->AddOpCode( ocSep );
1066 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1068 break;
1069 case ocNormDist:
1070 if ( mnCurArg == 2 )
1072 pNewArr->AddOpCode( ocSep );
1073 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1075 break;
1076 case ocLogInv:
1077 case ocLogNormDist:
1078 if ( mnCurArg == 0 )
1080 pNewArr->AddOpCode( ocSep );
1081 pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0
1083 if ( mnCurArg <= 1 )
1085 pNewArr->AddOpCode( ocSep );
1086 pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1088 break;
1089 case ocLog:
1090 if ( rConv.isPODF() && mnCurArg == 0 )
1092 pNewArr->AddOpCode( ocSep );
1093 pNewArr->AddDouble( 10.0 ); // 2nd, basis 10
1095 break;
1096 default:
1097 break;
1100 break;
1101 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML:
1103 switch (mpFunc->GetOpCode())
1105 case ocIf:
1106 if( mnCurArg == 0 )
1108 // Excel needs at least two parameters in IF function
1109 pNewArr->AddOpCode( ocSep );
1110 pNewArr->AddOpCode( ocTrue ); // 2nd, true() as function
1111 pNewArr->AddOpCode( ocOpen ); // so the result is of logical type
1112 pNewArr->AddOpCode( ocClose ); // and survives roundtrip
1114 break;
1116 case ocEuroConvert:
1117 if ( mnCurArg == 2 )
1119 pNewArr->AddOpCode( ocSep );
1120 pNewArr->AddDouble( 0.0 ); // 4th, FullPrecision = false()
1122 break;
1124 case ocPoissonDist:
1125 if (mnCurArg == 1)
1127 pNewArr->AddOpCode( ocSep );
1128 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1130 break;
1132 case ocGammaDist:
1133 case ocFDist_LT:
1134 case ocNormDist:
1135 if (mnCurArg == 2)
1137 pNewArr->AddOpCode( ocSep );
1138 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1140 break;
1142 case ocLogInv:
1143 case ocLogNormDist:
1144 if ( mnCurArg == 0 )
1146 pNewArr->AddOpCode( ocSep );
1147 pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0
1149 if ( mnCurArg <= 1 )
1151 pNewArr->AddOpCode( ocSep );
1152 pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1154 break;
1156 case ocHypGeomDist:
1157 if ( mnCurArg == 3 )
1159 pNewArr->AddOpCode( ocSep );
1160 pNewArr->AddDouble( 0.0 ); // 5th, Cumulative = false()
1162 break;
1164 case ocRound:
1165 case ocRoundUp:
1166 case ocRoundDown:
1167 if( mnCurArg == 0 )
1169 // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel
1170 pNewArr->AddOpCode( ocSep );
1171 pNewArr->AddDouble( 0.0 ); // 2nd, 0.0
1173 break;
1175 default:
1176 break;
1179 break;
1184 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const
1186 if (mnCurArg == nArg)
1188 pNewArr->AddDouble( f );
1189 return true;
1191 return false;
1194 bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray *pNewArr ) const
1196 // Only called for PODF, not ODFF. No need to distinguish.
1198 const OUString &rName = mpFunc->GetExternal();
1200 // initial (fast) check:
1201 sal_Unicode nLastChar = rName[ rName.getLength() - 1];
1202 if ( nLastChar != 't' && nLastChar != 'm' )
1203 return false;
1205 if (rName.equalsIgnoreAsciiCase(
1206 "com.sun.star.sheet.addin.Analysis.getAccrint" ))
1208 return AddDefaultArg( pNewArr, 4, 1000.0 );
1210 if (rName.equalsIgnoreAsciiCase(
1211 "com.sun.star.sheet.addin.Analysis.getAccrintm" ))
1213 return AddDefaultArg( pNewArr, 3, 1000.0 );
1215 return false;
1218 bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
1220 if ( !mpFunc )
1221 return false;
1223 bool bRet = false;
1224 const OpCode eOp = mpFunc->GetOpCode();
1226 switch (rConv.getConvention())
1228 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF:
1230 // Add for ODFF
1231 switch (eOp)
1233 case ocAddress:
1234 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1235 default:
1236 break;
1239 break;
1240 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF:
1242 // Add for PODF
1243 switch (eOp)
1245 case ocAddress:
1246 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1247 case ocFixed:
1248 return AddDefaultArg( pNewArr, 1, 2.0 );
1249 case ocBetaDist:
1250 case ocBetaInv:
1251 case ocPMT:
1252 return AddDefaultArg( pNewArr, 3, 0.0 );
1253 case ocIpmt:
1254 case ocPpmt:
1255 return AddDefaultArg( pNewArr, 4, 0.0 );
1256 case ocPV:
1257 case ocFV:
1258 bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt
1259 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v
1260 break;
1261 case ocRate:
1262 bRet |= AddDefaultArg( pNewArr, 1, 0.0 ); // pmt
1263 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // fv
1264 bRet |= AddDefaultArg( pNewArr, 4, 0.0 ); // type
1265 break;
1266 case ocExternal:
1267 return AddMissingExternal( pNewArr );
1269 // --- more complex cases ---
1271 case ocOffset:
1272 // FIXME: rather tough
1273 // if arg 3 (height) omitted, export arg1 (rows)
1274 break;
1275 default:
1276 break;
1279 break;
1280 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML:
1282 switch (eOp)
1284 case ocExternal:
1285 return AddMissingExternal( pNewArr );
1286 default:
1287 break;
1290 break;
1293 return bRet;
1296 bool FormulaTokenArray::NeedsPodfRewrite( const MissingConventionODF & rConv )
1298 for ( auto i: Tokens() )
1300 if ( rConv.isRewriteNeeded( i->GetOpCode()))
1301 return true;
1303 return false;
1306 bool FormulaTokenArray::NeedsOoxmlRewrite()
1308 for ( auto i: Tokens() )
1310 if ( MissingConventionOOXML::isRewriteNeeded( i->GetOpCode()))
1311 return true;
1313 return false;
1317 FormulaTokenArray * FormulaTokenArray::RewriteMissing( const MissingConvention & rConv )
1319 const size_t nAlloc = 256;
1320 FormulaMissingContext aCtx[ nAlloc ];
1322 /* TODO: with some effort we might be able to merge the two almost
1323 * identical function stacks into one and generalize things, otherwise
1324 * adding yet another "omit argument" would be copypasta. */
1326 int aOpCodeAddressStack[ nAlloc ]; // use of ADDRESS() function
1327 const int nOmitAddressArg = 3; // ADDRESS() 4th parameter A1/R1C1
1329 int aOpCodeDcountStack[ nAlloc ]; // use of DCOUNT()/DCOUNTA() function
1330 const int nOmitDcountArg = 1; // DCOUNT() and DCOUNTA() 2nd parameter DatabaseField if 0
1332 sal_uInt16 nTokens = GetLen() + 1;
1333 FormulaMissingContext* pCtx = (nAlloc < nTokens ? new FormulaMissingContext[nTokens] : &aCtx[0]);
1334 int* pOcas = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeAddressStack[0]);
1335 int* pOcds = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeDcountStack[0]);
1336 // Never go below 0, never use 0, mpFunc always NULL.
1337 pCtx[0].Clear();
1338 int nFn = 0;
1339 int nOcas = 0;
1340 int nOcds = 0;
1342 FormulaTokenArray *pNewArr = new FormulaTokenArray;
1343 // At least ScRecalcMode::ALWAYS needs to be set.
1344 pNewArr->AddRecalcMode( GetRecalcMode());
1346 FormulaTokenArrayPlainIterator aIter(*this);
1347 for ( FormulaToken *pCur = aIter.First(); pCur; pCur = aIter.Next() )
1349 bool bAdd = true;
1350 // Don't write the expression of the new inserted ADDRESS() parameter.
1351 // Do NOT omit the new second parameter of INDIRECT() though. If that
1352 // was done for both, INDIRECT() actually could calculate different and
1353 // valid (but wrong) results with the then changed return value of
1354 // ADDRESS(). Better let it generate an error instead.
1355 for (int i = nOcas; i-- > 0 && bAdd; )
1357 if (pCtx[ pOcas[ i ] ].mnCurArg == nOmitAddressArg)
1359 // Omit everything except a trailing separator, the leading
1360 // separator is omitted below. The other way around would leave
1361 // an extraneous separator if no parameter followed.
1362 if (pOcas[ i ] != nFn || pCur->GetOpCode() != ocSep)
1363 bAdd = false;
1366 // Strip the 2nd argument (leaving empty) of DCOUNT() and DCOUNTA() if
1367 // it is 0.
1368 for (int i = nOcds; i-- > 0 && bAdd; )
1370 if (pCtx[ pOcds[ i ] ].mnCurArg == nOmitDcountArg)
1372 // Omit only a literal 0 value, nothing else.
1373 if (pOcds[ i ] == nFn && pCur->GetOpCode() == ocPush && pCur->GetType() == svDouble &&
1374 pCur->GetDouble() == 0.0)
1376 // No other expression, between separators.
1377 FormulaToken* p = aIter.PeekPrevNoSpaces();
1378 if (p && p->GetOpCode() == ocSep)
1380 p = aIter.PeekNextNoSpaces();
1381 if (p && p->GetOpCode() == ocSep)
1382 bAdd = false;
1387 switch ( pCur->GetOpCode() )
1389 case ocOpen:
1391 ++nFn; // all following operations on _that_ function
1392 pCtx[ nFn ].mpFunc = aIter.PeekPrevNoSpaces();
1393 pCtx[ nFn ].mnCurArg = 0;
1394 if (rConv.isPODF() && pCtx[ nFn ].mpFunc && pCtx[ nFn ].mpFunc->GetOpCode() == ocAddress)
1395 pOcas[ nOcas++ ] = nFn; // entering ADDRESS() if PODF
1396 else if ((rConv.isODFF() || rConv.isOOXML()) && pCtx[ nFn ].mpFunc)
1398 OpCode eOp = pCtx[ nFn ].mpFunc->GetOpCode();
1399 if (eOp == ocDBCount || eOp == ocDBCount2)
1400 pOcds[ nOcds++ ] = nFn; // entering DCOUNT() or DCOUNTA() if ODFF or OOXML
1403 break;
1404 case ocClose:
1405 pCtx[ nFn ].AddMoreArgs( pNewArr, rConv );
1406 SAL_WARN_IF(nFn <= 0, "formula.core", "FormulaTokenArray::RewriteMissing: underflow");
1407 if (nOcas > 0 && pOcas[ nOcas-1 ] == nFn)
1408 --nOcas; // leaving ADDRESS()
1409 else if (nOcds > 0 && pOcds[ nOcds-1 ] == nFn)
1410 --nOcds; // leaving DCOUNT() or DCOUNTA()
1411 if (nFn > 0)
1412 --nFn;
1413 break;
1414 case ocSep:
1415 pCtx[ nFn ].mnCurArg++;
1416 // Omit leading separator of ADDRESS() parameter.
1417 if (nOcas && pOcas[ nOcas-1 ] == nFn && pCtx[ nFn ].mnCurArg == nOmitAddressArg)
1419 bAdd = false;
1421 break;
1422 case ocMissing:
1423 if ( bAdd )
1424 bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv );
1425 break;
1426 default:
1427 break;
1429 if (bAdd)
1431 OpCode eOp = pCur->GetOpCode();
1432 if ( ( eOp == ocCeil || eOp == ocFloor ||
1433 ( eOp == ocLogNormDist && pCur->GetByte() == 4 ) ) &&
1434 rConv.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML )
1436 switch ( eOp )
1438 case ocCeil :
1439 eOp = ocCeil_Math;
1440 break;
1441 case ocFloor :
1442 eOp = ocFloor_Math;
1443 break;
1444 case ocLogNormDist :
1445 eOp = ocLogNormDist_MS;
1446 break;
1447 default :
1448 eOp = ocNone;
1449 break;
1451 FormulaToken *pToken = new FormulaToken( svByte, eOp );
1452 pNewArr->Add( pToken );
1454 else if ( eOp == ocHypGeomDist &&
1455 rConv.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML )
1457 FormulaToken *pToken = new FormulaToken( svByte, ocHypGeomDist_MS );
1458 pNewArr->Add( pToken );
1460 else
1461 pNewArr->AddToken( *pCur );
1465 if (pOcds != &aOpCodeDcountStack[0])
1466 delete [] pOcds;
1467 if (pOcas != &aOpCodeAddressStack[0])
1468 delete [] pOcas;
1469 if (pCtx != &aCtx[0])
1470 delete [] pCtx;
1472 return pNewArr;
1475 bool FormulaTokenArray::MayReferenceFollow()
1477 if ( pCode && nLen > 0 )
1479 // ignore trailing spaces
1480 sal_uInt16 i = nLen - 1;
1481 while ( i > 0 && pCode[i]->GetOpCode() == SC_OPCODE_SPACES )
1483 --i;
1485 if ( i > 0 || pCode[i]->GetOpCode() != SC_OPCODE_SPACES )
1487 OpCode eOp = pCode[i]->GetOpCode();
1488 if ( (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP ) ||
1489 (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP ) ||
1490 eOp == SC_OPCODE_OPEN || eOp == SC_OPCODE_SEP )
1492 return true;
1496 return false;
1498 FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp )
1500 FormulaToken* pRet = nullptr;
1501 switch ( eOp )
1503 case ocOpen:
1504 case ocClose:
1505 case ocSep:
1506 case ocArrayOpen:
1507 case ocArrayClose:
1508 case ocArrayRowSep:
1509 case ocArrayColSep:
1510 pRet = new FormulaToken( svSep,eOp );
1511 break;
1512 case ocIf:
1513 case ocIfError:
1514 case ocIfNA:
1515 case ocChoose:
1517 short nJump[FORMULA_MAXJUMPCOUNT + 1];
1518 if ( eOp == ocIf )
1519 nJump[ 0 ] = 3;
1520 else if ( eOp == ocChoose )
1521 nJump[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
1522 else
1523 nJump[ 0 ] = 2;
1524 pRet = new FormulaJumpToken( eOp, nJump );
1526 break;
1527 default:
1528 pRet = new FormulaByteToken( eOp, 0, ParamClass::Unknown );
1529 break;
1531 return Add( pRet );
1534 void FormulaTokenArray::ReinternStrings( svl::SharedStringPool& rPool )
1536 for (auto i: Tokens())
1538 switch (i->GetType())
1540 case svString:
1541 i->SetString( rPool.intern( i->GetString().getString()));
1542 break;
1543 default:
1544 ; // nothing
1550 /*----------------------------------------------------------------------*/
1552 FormulaTokenIterator::Item::Item(const FormulaTokenArray* pArray, short pc, short stop) :
1553 pArr(pArray), nPC(pc), nStop(stop)
1557 FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray& rArr )
1559 Push( &rArr );
1562 FormulaTokenIterator::~FormulaTokenIterator()
1566 void FormulaTokenIterator::Push( const FormulaTokenArray* pArr )
1568 FormulaTokenIterator::Item item(pArr, -1, SHRT_MAX);
1570 maStack.push_back(item);
1573 void FormulaTokenIterator::Pop()
1575 maStack.pop_back();
1578 void FormulaTokenIterator::Reset()
1580 while( maStack.size() > 1 )
1581 maStack.pop_back();
1583 maStack.back().nPC = -1;
1586 FormulaToken* FormulaTokenArrayPlainIterator::GetNextName()
1588 if( mpFTA->GetArray() )
1590 while ( mnIndex < mpFTA->GetLen() )
1592 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1593 if( t->GetType() == svIndex )
1594 return t;
1597 return nullptr;
1600 const FormulaToken* FormulaTokenIterator::Next()
1602 const FormulaToken* t = GetNonEndOfPathToken( ++maStack.back().nPC );
1603 if( !t && maStack.size() > 1 )
1605 Pop();
1606 t = Next();
1608 return t;
1611 const FormulaToken* FormulaTokenIterator::PeekNextOperator()
1613 const FormulaToken* t = nullptr;
1614 short nIdx = maStack.back().nPC;
1615 for (;;)
1617 t = GetNonEndOfPathToken( ++nIdx);
1618 if (t == nullptr || t->GetOpCode() != ocPush)
1619 break; // ignore operands
1621 if (!t && maStack.size() > 1)
1623 FormulaTokenIterator::Item aHere = maStack.back();
1624 maStack.pop_back();
1625 t = PeekNextOperator();
1626 maStack.push_back(aHere);
1628 return t;
1631 //! The nPC counts after a Push() are -1
1633 void FormulaTokenIterator::Jump( short nStart, short nNext, short nStop )
1635 maStack.back().nPC = nNext;
1636 if( nStart != nNext )
1638 Push( maStack.back().pArr );
1639 maStack.back().nPC = nStart;
1640 maStack.back().nStop = nStop;
1644 void FormulaTokenIterator::ReInit( const FormulaTokenArray& rArr )
1646 maStack.clear();
1647 Push( &rArr );
1650 const FormulaToken* FormulaTokenIterator::GetNonEndOfPathToken( short nIdx ) const
1652 FormulaTokenIterator::Item cur = maStack.back();
1654 if (nIdx < cur.pArr->GetCodeLen() && nIdx < cur.nStop)
1656 const FormulaToken* t = cur.pArr->GetCode()[ nIdx ];
1657 // such an OpCode ends an IF() or CHOOSE() path
1658 return (t->GetOpCode() == ocSep || t->GetOpCode() == ocClose) ? nullptr : t;
1660 return nullptr;
1663 bool FormulaTokenIterator::IsEndOfPath() const
1665 return GetNonEndOfPathToken( maStack.back().nPC + 1) == nullptr;
1668 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReference()
1670 while( mnIndex < mpFTA->GetLen() )
1672 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1673 switch( t->GetType() )
1675 case svSingleRef:
1676 case svDoubleRef:
1677 case svExternalSingleRef:
1678 case svExternalDoubleRef:
1679 return t;
1680 default:
1682 // added to avoid warnings
1686 return nullptr;
1689 FormulaToken* FormulaTokenArrayPlainIterator::GetNextColRowName()
1691 while( mnIndex < mpFTA->GetLen() )
1693 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1694 if ( t->GetOpCode() == ocColRowName )
1695 return t;
1697 return nullptr;
1700 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceRPN()
1702 while( mnIndex < mpFTA->GetCodeLen() )
1704 FormulaToken* t = mpFTA->GetCode()[ mnIndex++ ];
1705 switch( t->GetType() )
1707 case svSingleRef:
1708 case svDoubleRef:
1709 case svExternalSingleRef:
1710 case svExternalDoubleRef:
1711 return t;
1712 default:
1714 // added to avoid warnings
1718 return nullptr;
1721 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceOrName()
1723 if( mpFTA->GetArray() )
1725 while ( mnIndex < mpFTA->GetLen() )
1727 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1728 switch( t->GetType() )
1730 case svSingleRef:
1731 case svDoubleRef:
1732 case svIndex:
1733 case svExternalSingleRef:
1734 case svExternalDoubleRef:
1735 case svExternalName:
1736 return t;
1737 default:
1739 // added to avoid warnings
1744 return nullptr;
1747 FormulaToken* FormulaTokenArrayPlainIterator::Next()
1749 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1750 return mpFTA->GetArray()[ mnIndex++ ];
1751 else
1752 return nullptr;
1755 FormulaToken* FormulaTokenArrayPlainIterator::NextNoSpaces()
1757 if( mpFTA->GetArray() )
1759 while( (mnIndex < mpFTA->GetLen()) && (mpFTA->GetArray()[ mnIndex ]->GetOpCode() == ocSpaces) )
1760 ++mnIndex;
1761 if( mnIndex < mpFTA->GetLen() )
1762 return mpFTA->GetArray()[ mnIndex++ ];
1764 return nullptr;
1767 FormulaToken* FormulaTokenArrayPlainIterator::NextRPN()
1769 if( mpFTA->GetCode() && mnIndex < mpFTA->GetCodeLen() )
1770 return mpFTA->GetCode()[ mnIndex++ ];
1771 else
1772 return nullptr;
1775 FormulaToken* FormulaTokenArrayPlainIterator::PrevRPN()
1777 if( mpFTA->GetCode() && mnIndex )
1778 return mpFTA->GetCode()[ --mnIndex ];
1779 else
1780 return nullptr;
1783 FormulaToken* FormulaTokenArrayPlainIterator::PeekNext()
1785 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1786 return mpFTA->GetArray()[ mnIndex ];
1787 else
1788 return nullptr;
1791 FormulaToken* FormulaTokenArrayPlainIterator::PeekNextNoSpaces() const
1793 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1795 sal_uInt16 j = mnIndex;
1796 while ( j < mpFTA->GetLen() && mpFTA->GetArray()[j]->GetOpCode() == ocSpaces )
1797 j++;
1798 if ( j < mpFTA->GetLen() )
1799 return mpFTA->GetArray()[ j ];
1800 else
1801 return nullptr;
1803 else
1804 return nullptr;
1807 FormulaToken* FormulaTokenArrayPlainIterator::PeekPrevNoSpaces() const
1809 if( mpFTA->GetArray() && mnIndex > 1 )
1811 sal_uInt16 j = mnIndex - 2;
1812 while ( mpFTA->GetArray()[j]->GetOpCode() == ocSpaces && j > 0 )
1813 j--;
1814 if ( j > 0 || mpFTA->GetArray()[j]->GetOpCode() != ocSpaces )
1815 return mpFTA->GetArray()[ j ];
1816 else
1817 return nullptr;
1819 else
1820 return nullptr;
1823 void FormulaTokenArrayPlainIterator::AfterRemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount )
1825 const sal_uInt16 nStop = std::min( static_cast<sal_uInt16>(nOffset + nCount), mpFTA->GetLen());
1827 if (mnIndex >= nOffset)
1829 if (mnIndex < nStop)
1830 mnIndex = nOffset + 1;
1831 else
1832 mnIndex -= nStop - nOffset;
1836 // real implementations of virtual functions
1839 double FormulaDoubleToken::GetDouble() const { return fDouble; }
1840 double & FormulaDoubleToken::GetDoubleAsReference() { return fDouble; }
1842 sal_Int16 FormulaDoubleToken::GetDoubleType() const
1844 // This is a plain double value without type information, don't emit a
1845 // warning via FormulaToken::GetDoubleType().
1846 return 0;
1849 bool FormulaDoubleToken::operator==( const FormulaToken& r ) const
1851 return FormulaToken::operator==( r ) && fDouble == r.GetDouble();
1854 sal_Int16 FormulaTypedDoubleToken::GetDoubleType() const
1856 return mnType;
1859 void FormulaTypedDoubleToken::SetDoubleType( sal_Int16 nType )
1861 mnType = nType;
1864 bool FormulaTypedDoubleToken::operator==( const FormulaToken& r ) const
1866 return FormulaDoubleToken::operator==( r ) && mnType == r.GetDoubleType();
1869 FormulaStringToken::FormulaStringToken( const svl::SharedString& r ) :
1870 FormulaToken( svString ), maString( r )
1874 FormulaStringToken::FormulaStringToken( const FormulaStringToken& r ) :
1875 FormulaToken( r ), maString( r.maString ) {}
1877 FormulaToken* FormulaStringToken::Clone() const
1879 return new FormulaStringToken(*this);
1882 const svl::SharedString & FormulaStringToken::GetString() const
1884 return maString;
1887 void FormulaStringToken::SetString( const svl::SharedString& rStr )
1889 maString = rStr;
1892 bool FormulaStringToken::operator==( const FormulaToken& r ) const
1894 return FormulaToken::operator==( r ) && maString == r.GetString();
1897 FormulaStringOpToken::FormulaStringOpToken( OpCode e, const svl::SharedString& r ) :
1898 FormulaByteToken( e, 0, svString, ParamClass::Unknown ), maString( r ) {}
1900 FormulaStringOpToken::FormulaStringOpToken( const FormulaStringOpToken& r ) :
1901 FormulaByteToken( r ), maString( r.maString ) {}
1903 FormulaToken* FormulaStringOpToken::Clone() const
1905 return new FormulaStringOpToken(*this);
1908 const svl::SharedString & FormulaStringOpToken::GetString() const
1910 return maString;
1913 void FormulaStringOpToken::SetString( const svl::SharedString& rStr )
1915 maString = rStr;
1918 bool FormulaStringOpToken::operator==( const FormulaToken& r ) const
1920 return FormulaByteToken::operator==( r ) && maString == r.GetString();
1923 sal_uInt16 FormulaIndexToken::GetIndex() const { return nIndex; }
1924 void FormulaIndexToken::SetIndex( sal_uInt16 n ) { nIndex = n; }
1925 sal_Int16 FormulaIndexToken::GetSheet() const { return mnSheet; }
1926 void FormulaIndexToken::SetSheet( sal_Int16 n ) { mnSheet = n; }
1927 bool FormulaIndexToken::operator==( const FormulaToken& r ) const
1929 return FormulaToken::operator==( r ) && nIndex == r.GetIndex() &&
1930 mnSheet == r.GetSheet();
1932 const OUString& FormulaExternalToken::GetExternal() const { return aExternal; }
1933 bool FormulaExternalToken::operator==( const FormulaToken& r ) const
1935 return FormulaByteToken::operator==( r ) && aExternal == r.GetExternal();
1939 FormulaError FormulaErrorToken::GetError() const { return nError; }
1940 void FormulaErrorToken::SetError( FormulaError nErr ) { nError = nErr; }
1941 bool FormulaErrorToken::operator==( const FormulaToken& r ) const
1943 return FormulaToken::operator==( r ) &&
1944 nError == static_cast< const FormulaErrorToken & >(r).GetError();
1946 double FormulaMissingToken::GetDouble() const { return 0.0; }
1948 const svl::SharedString & FormulaMissingToken::GetString() const
1950 return svl::SharedString::getEmptyString();
1953 bool FormulaMissingToken::operator==( const FormulaToken& r ) const
1955 return FormulaToken::operator==( r );
1959 bool FormulaUnknownToken::operator==( const FormulaToken& r ) const
1961 return FormulaToken::operator==( r );
1965 } // formula
1968 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */