1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
26 #include <tools/debug.hxx>
27 #include <osl/diagnose.h>
29 #include "formula/token.hxx"
30 #include "formula/tokenarray.hxx"
31 #include "formula/FormulaCompiler.hxx"
32 #include <formula/compiler.hrc>
33 #include <svl/sharedstringpool.hxx>
34 #include <boost/scoped_array.hpp>
38 using namespace com::sun::star
;
40 // Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2)
42 // Need a lot of FormulaDoubleToken
43 IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaDoubleToken
)
44 // Need a lot of FormulaByteToken
45 IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaByteToken
)
46 // Need several FormulaStringToken
47 IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaStringToken
)
50 // --- helpers --------------------------------------------------------------
52 inline bool lcl_IsReference( OpCode eOp
, StackVar eType
)
55 (eOp
== ocPush
&& (eType
== svSingleRef
|| eType
== svDoubleRef
))
56 || (eOp
== ocColRowNameAuto
&& eType
== svDoubleRef
)
57 || (eOp
== ocColRowName
&& eType
== svSingleRef
)
58 || (eOp
== ocMatRef
&& eType
== svSingleRef
)
62 // --- class FormulaToken --------------------------------------------------------
64 FormulaToken::FormulaToken( StackVar eTypeP
, OpCode e
) :
65 eOp(e
), eType( eTypeP
), mnRefCnt(0)
69 FormulaToken::FormulaToken( const FormulaToken
& r
) :
70 IFormulaToken(), eOp(r
.eOp
), eType( r
.eType
), mnRefCnt(0)
74 FormulaToken::~FormulaToken()
78 bool FormulaToken::IsFunction() const
80 return (eOp
!= ocPush
&& eOp
!= ocBad
&& eOp
!= ocColRowName
&&
81 eOp
!= ocColRowNameAuto
&& eOp
!= ocName
&& eOp
!= ocDBArea
&&
83 (GetByte() != 0 // x parameters
84 || (SC_OPCODE_START_NO_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_NO_PAR
) // no parameter
85 || (ocIf
== eOp
|| ocIfError
== eOp
|| ocIfNA
== eOp
|| ocChoose
== eOp
) // @ jump commands
86 || (SC_OPCODE_START_1_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_1_PAR
) // one parameter
87 || (SC_OPCODE_START_2_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_2_PAR
) // x parameters (cByte==0 in
89 || eOp
== ocMacro
|| eOp
== ocExternal
// macros, AddIns
90 || eOp
== ocAnd
|| eOp
== ocOr
// former binary, now x parameters
91 || eOp
== ocNot
|| eOp
== ocNeg
// unary but function
92 || (eOp
>= ocInternalBegin
&& eOp
<= ocInternalEnd
) // internal
97 sal_uInt8
FormulaToken::GetParamCount() const
99 if ( eOp
< SC_OPCODE_STOP_DIV
&& eOp
!= ocExternal
&& eOp
!= ocMacro
&&
100 eOp
!= ocIf
&& eOp
!= ocIfError
&& eOp
!= ocIfNA
&& eOp
!= ocChoose
&&
101 eOp
!= ocPercentSign
)
102 return 0; // parameters and specials
103 // ocIf, ocIfError, ocIfNA and ocChoose not for FAP, have cByte then
104 //2do: bool parameter whether FAP or not?
105 else if ( GetByte() )
106 return GetByte(); // all functions, also ocExternal and ocMacro
107 else if (SC_OPCODE_START_BIN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_BIN_OP
)
109 else if ((SC_OPCODE_START_UN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_UN_OP
)
110 || eOp
== ocPercentSign
)
112 else if (SC_OPCODE_START_NO_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_NO_PAR
)
113 return 0; // no parameter
114 else if (SC_OPCODE_START_1_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_1_PAR
)
115 return 1; // one parameter
116 else if ( eOp
== ocIf
|| eOp
== ocIfError
|| eOp
== ocIfNA
|| eOp
== ocChoose
)
117 return 1; // only the condition counts as parameter
119 return 0; // all the rest, no Parameter, or
120 // if so then it should be in cByte
123 bool FormulaToken::IsExternalRef() const
128 case svExternalSingleRef
:
129 case svExternalDoubleRef
:
140 bool FormulaToken::IsRef() const
146 case svExternalSingleRef
:
147 case svExternalDoubleRef
:
150 if (eOp
== ocTableRef
)
157 bool FormulaToken::operator==( const FormulaToken
& rToken
) const
159 // don't compare reference count!
160 return eType
== rToken
.eType
&& GetOpCode() == rToken
.GetOpCode();
164 // --- virtual dummy methods -------------------------------------------------
166 sal_uInt8
FormulaToken::GetByte() const
168 // ok to be called for any derived class
172 void FormulaToken::SetByte( sal_uInt8
)
174 SAL_WARN( "formula.core", "FormulaToken::SetByte: virtual dummy called" );
177 bool FormulaToken::HasForceArray() const
179 // ok to be called for any derived class
183 void FormulaToken::SetForceArray( bool )
185 SAL_WARN( "formula.core", "FormulaToken::SetForceArray: virtual dummy called" );
188 double FormulaToken::GetDouble() const
190 SAL_WARN( "formula.core", "FormulaToken::GetDouble: virtual dummy called" );
194 double & FormulaToken::GetDoubleAsReference()
196 SAL_WARN( "formula.core", "FormulaToken::GetDouble: virtual dummy called" );
197 static double fVal
= 0.0;
201 svl::SharedString
FormulaToken::GetString() const
203 SAL_WARN( "formula.core", "FormulaToken::GetString: virtual dummy called" );
204 return svl::SharedString(); // invalid string
207 sal_uInt16
FormulaToken::GetIndex() const
209 SAL_WARN( "formula.core", "FormulaToken::GetIndex: virtual dummy called" );
213 void FormulaToken::SetIndex( sal_uInt16
)
215 SAL_WARN( "formula.core", "FormulaToken::SetIndex: virtual dummy called" );
218 bool FormulaToken::IsGlobal() const
220 SAL_WARN( "formula.core", "FormulaToken::IsGlobal: virtual dummy called" );
224 void FormulaToken::SetGlobal( bool )
226 SAL_WARN( "formula.core", "FormulaToken::SetGlobal: virtual dummy called" );
229 short* FormulaToken::GetJump() const
231 SAL_WARN( "formula.core", "FormulaToken::GetJump: virtual dummy called" );
236 const OUString
& FormulaToken::GetExternal() const
238 SAL_WARN( "formula.core", "FormulaToken::GetExternal: virtual dummy called" );
239 static OUString aDummyString
;
243 FormulaToken
* FormulaToken::GetFAPOrigToken() const
245 SAL_WARN( "formula.core", "FormulaToken::GetFAPOrigToken: virtual dummy called" );
249 sal_uInt16
FormulaToken::GetError() const
251 SAL_WARN( "formula.core", "FormulaToken::GetError: virtual dummy called" );
255 void FormulaToken::SetError( sal_uInt16
)
257 SAL_WARN( "formula.core", "FormulaToken::SetError: virtual dummy called" );
260 const ScSingleRefData
* FormulaToken::GetSingleRef() const
262 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
266 ScSingleRefData
* FormulaToken::GetSingleRef()
268 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
272 const ScComplexRefData
* FormulaToken::GetDoubleRef() const
274 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
278 ScComplexRefData
* FormulaToken::GetDoubleRef()
280 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
284 const ScSingleRefData
* FormulaToken::GetSingleRef2() const
286 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
290 ScSingleRefData
* FormulaToken::GetSingleRef2()
292 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
296 const ScMatrix
* FormulaToken::GetMatrix() const
298 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
302 ScMatrix
* FormulaToken::GetMatrix()
304 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
308 ScJumpMatrix
* FormulaToken::GetJumpMatrix() const
310 OSL_FAIL( "FormulaToken::GetJumpMatrix: virtual dummy called" );
313 const std::vector
<ScComplexRefData
>* FormulaToken::GetRefList() const
315 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
319 std::vector
<ScComplexRefData
>* FormulaToken::GetRefList()
321 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
325 bool FormulaToken::TextEqual( const FormulaToken
& rToken
) const
327 return *this == rToken
;
330 // real implementations of virtual functions
334 sal_uInt8
FormulaByteToken::GetByte() const { return nByte
; }
335 void FormulaByteToken::SetByte( sal_uInt8 n
) { nByte
= n
; }
336 bool FormulaByteToken::HasForceArray() const { return bHasForceArray
; }
337 void FormulaByteToken::SetForceArray( bool b
) { bHasForceArray
= b
; }
338 bool FormulaByteToken::operator==( const FormulaToken
& r
) const
340 return FormulaToken::operator==( r
) && nByte
== r
.GetByte() &&
341 bHasForceArray
== r
.HasForceArray();
345 FormulaToken
* FormulaFAPToken::GetFAPOrigToken() const { return pOrigToken
.get(); }
346 bool FormulaFAPToken::operator==( const FormulaToken
& r
) const
348 return FormulaByteToken::operator==( r
) && pOrigToken
== r
.GetFAPOrigToken();
352 short* FormulaJumpToken::GetJump() const { return pJump
; }
353 bool FormulaJumpToken::HasForceArray() const { return bHasForceArray
; }
354 void FormulaJumpToken::SetForceArray( bool b
) { bHasForceArray
= b
; }
355 bool FormulaJumpToken::operator==( const FormulaToken
& r
) const
357 return FormulaToken::operator==( r
) && pJump
[0] == r
.GetJump()[0] &&
358 memcmp( pJump
+1, r
.GetJump()+1, pJump
[0] * sizeof(short) ) == 0 &&
359 bHasForceArray
== r
.HasForceArray();
361 FormulaJumpToken::~FormulaJumpToken()
367 bool FormulaTokenArray::AddFormulaToken(
368 const sheet::FormulaToken
& rToken
, svl::SharedStringPool
& rSPool
, ExternalReferenceHelper
* /*pExtRef*/)
371 const OpCode eOpCode
= static_cast<OpCode
>(rToken
.OpCode
); //! assuming equal values for the moment
373 const uno::TypeClass eClass
= rToken
.Data
.getValueTypeClass();
376 case uno::TypeClass_VOID
:
377 // empty data -> use AddOpCode (does some special cases)
378 AddOpCode( eOpCode
);
380 case uno::TypeClass_DOUBLE
:
381 // double is only used for "push"
382 if ( eOpCode
== ocPush
)
383 AddDouble( rToken
.Data
.get
<double>() );
387 case uno::TypeClass_LONG
:
389 // long is svIndex, used for name / database area, or "byte" for spaces
390 sal_Int32 nValue
= rToken
.Data
.get
<sal_Int32
>();
391 if ( eOpCode
== ocDBArea
)
392 AddToken( formula::FormulaIndexToken( eOpCode
, static_cast<sal_uInt16
>(nValue
) ) );
393 else if ( eOpCode
== ocTableRef
)
394 bError
= true; /* TODO: implementation */
395 else if ( eOpCode
== ocSpaces
)
396 AddToken( formula::FormulaByteToken( ocSpaces
, static_cast<sal_uInt8
>(nValue
) ) );
401 case uno::TypeClass_STRING
:
403 OUString
aStrVal( rToken
.Data
.get
<OUString
>() );
404 if ( eOpCode
== ocPush
)
405 AddString(rSPool
.intern(aStrVal
));
406 else if ( eOpCode
== ocBad
)
408 else if ( eOpCode
== ocStringXML
)
409 AddStringXML( aStrVal
);
410 else if ( eOpCode
== ocExternal
|| eOpCode
== ocMacro
)
411 AddToken( formula::FormulaExternalToken( eOpCode
, aStrVal
) );
413 bError
= true; // unexpected string: don't know what to do with it
418 } // switch ( eClass )
422 bool FormulaTokenArray::Fill(
423 const uno::Sequence
<sheet::FormulaToken
>& rSequence
,
424 svl::SharedStringPool
& rSPool
, ExternalReferenceHelper
* pExtRef
)
427 const sal_Int32 nCount
= rSequence
.getLength();
428 for (sal_Int32 nPos
=0; nPos
<nCount
; nPos
++)
430 bool bOneError
= AddFormulaToken(rSequence
[nPos
], rSPool
, pExtRef
);
433 AddOpCode( ocErrName
); // add something that indicates an error
439 FormulaToken
* FormulaTokenArray::GetNextReference()
441 while( nIndex
< nLen
)
443 FormulaToken
* t
= pCode
[ nIndex
++ ];
444 switch( t
->GetType() )
448 case svExternalSingleRef
:
449 case svExternalDoubleRef
:
453 // added to avoid warnings
460 FormulaToken
* FormulaTokenArray::GetNextColRowName()
462 while( nIndex
< nLen
)
464 FormulaToken
* t
= pCode
[ nIndex
++ ];
465 if ( t
->GetOpCode() == ocColRowName
)
471 FormulaToken
* FormulaTokenArray::GetNextReferenceRPN()
473 while( nIndex
< nRPN
)
475 FormulaToken
* t
= pRPN
[ nIndex
++ ];
476 switch( t
->GetType() )
480 case svExternalSingleRef
:
481 case svExternalDoubleRef
:
485 // added to avoid warnings
492 FormulaToken
* FormulaTokenArray::GetNextReferenceOrName()
496 while ( nIndex
< nLen
)
498 FormulaToken
* t
= pCode
[ nIndex
++ ];
499 switch( t
->GetType() )
504 case svExternalSingleRef
:
505 case svExternalDoubleRef
:
510 // added to avoid warnings
518 FormulaToken
* FormulaTokenArray::GetNextName()
522 while ( nIndex
< nLen
)
524 FormulaToken
* t
= pCode
[ nIndex
++ ];
525 if( t
->GetType() == svIndex
)
532 FormulaToken
* FormulaTokenArray::Next()
534 if( pCode
&& nIndex
< nLen
)
535 return pCode
[ nIndex
++ ];
540 FormulaToken
* FormulaTokenArray::NextNoSpaces()
544 while( (nIndex
< nLen
) && (pCode
[ nIndex
]->GetOpCode() == ocSpaces
) )
547 return pCode
[ nIndex
++ ];
552 FormulaToken
* FormulaTokenArray::NextRPN()
554 if( pRPN
&& nIndex
< nRPN
)
555 return pRPN
[ nIndex
++ ];
560 FormulaToken
* FormulaTokenArray::PrevRPN()
563 return pRPN
[ --nIndex
];
568 void FormulaTokenArray::DelRPN()
572 FormulaToken
** p
= pRPN
;
573 for( sal_uInt16 i
= 0; i
< nRPN
; i
++ )
583 FormulaToken
* FormulaTokenArray::PeekPrev( sal_uInt16
& nIdx
)
585 if (0 < nIdx
&& nIdx
<= nLen
)
586 return pCode
[--nIdx
];
590 FormulaToken
* FormulaTokenArray::PeekNext()
592 if( pCode
&& nIndex
< nLen
)
593 return pCode
[ nIndex
];
598 FormulaToken
* FormulaTokenArray::PeekNextNoSpaces()
600 if( pCode
&& nIndex
< nLen
)
602 sal_uInt16 j
= nIndex
;
603 while ( pCode
[j
]->GetOpCode() == ocSpaces
&& j
< nLen
)
614 FormulaToken
* FormulaTokenArray::PeekPrevNoSpaces()
616 if( pCode
&& nIndex
> 1 )
618 sal_uInt16 j
= nIndex
- 2;
619 while ( pCode
[j
]->GetOpCode() == ocSpaces
&& j
> 0 )
621 if ( j
> 0 || pCode
[j
]->GetOpCode() != ocSpaces
)
630 bool FormulaTokenArray::HasReferences() const
632 for (sal_uInt16 i
= 0; i
< nLen
; ++i
)
634 if (pCode
[i
]->IsRef())
638 for (sal_uInt16 i
= 0; i
< nRPN
; ++i
)
640 if (pRPN
[i
]->IsRef())
647 bool FormulaTokenArray::HasExternalRef() const
649 for ( sal_uInt16 j
=0; j
< nLen
; j
++ )
651 if (pCode
[j
]->IsExternalRef())
657 bool FormulaTokenArray::HasOpCode( OpCode eOp
) const
659 for ( sal_uInt16 j
=0; j
< nLen
; j
++ )
661 if ( pCode
[j
]->GetOpCode() == eOp
)
667 bool FormulaTokenArray::HasOpCodeRPN( OpCode eOp
) const
669 for ( sal_uInt16 j
=0; j
< nRPN
; j
++ )
671 if ( pRPN
[j
]->GetOpCode() == eOp
)
677 bool FormulaTokenArray::HasNameOrColRowName() const
679 for ( sal_uInt16 j
=0; j
< nLen
; j
++ )
681 if( pCode
[j
]->GetType() == svIndex
|| pCode
[j
]->GetOpCode() == ocColRowName
)
687 bool FormulaTokenArray::HasOpCodes(const unordered_opcode_set
& rOpCodes
) const
689 FormulaToken
** p
= pCode
;
690 FormulaToken
** pEnd
= p
+ static_cast<size_t>(nLen
);
691 for (; p
!= pEnd
; ++p
)
693 OpCode eOp
= (*p
)->GetOpCode();
694 if (rOpCodes
.count(eOp
) > 0)
701 FormulaTokenArray::FormulaTokenArray() :
708 nMode(ScRecalcMode::NORMAL
),
710 mbFromRangeName(false)
714 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray
& rArr
)
719 FormulaTokenArray::~FormulaTokenArray()
724 void FormulaTokenArray::Assign( const FormulaTokenArray
& r
)
731 bHyperLink
= r
.bHyperLink
;
732 mbFromRangeName
= r
.mbFromRangeName
;
738 pp
= pCode
= new FormulaToken
*[ nLen
];
739 memcpy( pp
, r
.pCode
, nLen
* sizeof( FormulaToken
* ) );
740 for( sal_uInt16 i
= 0; i
< nLen
; i
++ )
745 pp
= pRPN
= new FormulaToken
*[ nRPN
];
746 memcpy( pp
, r
.pRPN
, nRPN
* sizeof( FormulaToken
* ) );
747 for( sal_uInt16 i
= 0; i
< nRPN
; i
++ )
752 /// Optimisation for efficiently creating StringXML placeholders
753 void FormulaTokenArray::Assign( sal_uInt16 nCode
, FormulaToken
**pTokens
)
756 assert( pCode
== NULL
);
759 pCode
= new FormulaToken
*[ nLen
];
761 for( sal_uInt16 i
= 0; i
< nLen
; i
++ )
763 FormulaToken
*t
= pTokens
[ i
];
764 assert( t
->GetOpCode() == ocStringXML
);
770 FormulaTokenArray
& FormulaTokenArray::operator=( const FormulaTokenArray
& rArr
)
777 FormulaTokenArray
* FormulaTokenArray::Clone() const
779 FormulaTokenArray
* p
= new FormulaTokenArray
;
784 p
->bHyperLink
= bHyperLink
;
785 p
->mbFromRangeName
= mbFromRangeName
;
789 pp
= p
->pCode
= new FormulaToken
*[ nLen
];
790 memcpy( pp
, pCode
, nLen
* sizeof( FormulaToken
* ) );
791 for( sal_uInt16 i
= 0; i
< nLen
; i
++, pp
++ )
793 *pp
= (*pp
)->Clone();
799 pp
= p
->pRPN
= new FormulaToken
*[ nRPN
];
800 memcpy( pp
, pRPN
, nRPN
* sizeof( FormulaToken
* ) );
801 for( sal_uInt16 i
= 0; i
< nRPN
; i
++, pp
++ )
803 FormulaToken
* t
= *pp
;
804 if( t
->GetRef() > 1 )
806 FormulaToken
** p2
= pCode
;
807 sal_uInt16 nIdx
= 0xFFFF;
808 for( sal_uInt16 j
= 0; j
< nLen
; j
++, p2
++ )
818 *pp
= p
->pCode
[ nIdx
];
828 void FormulaTokenArray::Clear()
833 FormulaToken
** p
= pCode
;
834 for( sal_uInt16 i
= 0; i
< nLen
; i
++ )
840 pCode
= NULL
; pRPN
= NULL
;
841 nError
= nLen
= nIndex
= nRPN
= 0;
843 mbFromRangeName
= false;
847 void FormulaTokenArray::CheckToken( const FormulaToken
& /*r*/ )
852 FormulaToken
* FormulaTokenArray::AddToken( const FormulaToken
& r
)
854 return Add( r
.Clone() );
857 FormulaToken
* FormulaTokenArray::MergeArray( )
862 FormulaToken
* FormulaTokenArray::ReplaceToken( sal_uInt16 nOffset
, FormulaToken
* t
,
863 FormulaTokenArray::ReplaceMode eMode
)
865 if (eMode
== BACKWARD_CODE_ONLY
)
866 nOffset
= nLen
- nOffset
- 1;
872 FormulaToken
* p
= pCode
[nOffset
];
874 if (eMode
== FORWARD_CODE_AND_RPN
&& p
->GetRef() > 1)
876 for (sal_uInt16 i
=0; i
< nRPN
; ++i
)
883 if (p
->GetRef() == 1)
888 p
->DecRef(); // may be dead now
898 FormulaToken
* FormulaTokenArray::Add( FormulaToken
* t
)
901 pCode
= new FormulaToken
*[ FORMULA_MAXTOKENS
];
902 if( nLen
< FORMULA_MAXTOKENS
- 1 )
907 if( t
->GetOpCode() == ocArrayClose
)
914 if ( nLen
== FORMULA_MAXTOKENS
- 1 )
916 t
= new FormulaByteToken( ocStop
);
924 FormulaToken
* FormulaTokenArray::AddString( const svl::SharedString
& rStr
)
926 return Add( new FormulaStringToken( rStr
) );
929 FormulaToken
* FormulaTokenArray::AddDouble( double fVal
)
931 return Add( new FormulaDoubleToken( fVal
) );
934 FormulaToken
* FormulaTokenArray::AddExternal( const sal_Unicode
* pStr
)
936 return AddExternal( OUString( pStr
) );
939 FormulaToken
* FormulaTokenArray::AddExternal( const OUString
& rStr
,
940 OpCode eOp
/* = ocExternal */ )
942 return Add( new FormulaExternalToken( eOp
, rStr
) );
945 FormulaToken
* FormulaTokenArray::AddBad( const OUString
& rStr
)
947 return Add( new FormulaStringOpToken( ocBad
, rStr
) );
950 FormulaToken
* FormulaTokenArray::AddStringXML( const OUString
& rStr
)
952 return Add( new FormulaStringOpToken( ocStringXML
, rStr
) );
957 void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits
)
959 //! Order is important.
960 if ( nBits
& ScRecalcMode::ALWAYS
)
961 SetExclusiveRecalcModeAlways();
962 else if ( !IsRecalcModeAlways() )
964 if ( nBits
& ScRecalcMode::ONLOAD
)
965 SetExclusiveRecalcModeOnLoad();
966 else if ( nBits
& ScRecalcMode::ONLOAD_ONCE
&& !IsRecalcModeOnLoad() )
967 SetExclusiveRecalcModeOnLoadOnce();
969 SetCombinedBitsRecalcMode( nBits
);
973 bool FormulaTokenArray::HasMatrixDoubleRefOps()
977 // RPN-Interpreter simulation.
978 // Simply assumes a double as return value of each function.
979 boost::scoped_array
<FormulaToken
*> pStack(new FormulaToken
* [nRPN
]);
980 FormulaToken
* pResult
= new FormulaDoubleToken( 0.0 );
982 for ( sal_uInt16 j
= 0; j
< nRPN
; j
++ )
984 FormulaToken
* t
= pRPN
[j
];
985 OpCode eOp
= t
->GetOpCode();
986 sal_uInt8 nParams
= t
->GetParamCount();
1001 case ocGreaterEqual
:
1003 for ( sal_uInt8 k
= nParams
; k
; k
-- )
1005 if ( sp
>= k
&& pStack
[sp
-k
]->GetType() == svDoubleRef
)
1015 // added to avoid warnings
1018 if ( eOp
== ocPush
|| lcl_IsReference( eOp
, t
->GetType() ) )
1020 else if ( eOp
== ocIf
|| eOp
== ocIfError
|| eOp
== ocIfNA
|| eOp
== ocChoose
)
1021 { // ignore Jumps, pop previous Result (Condition)
1026 { // pop parameters, push result
1027 sp
= sal::static_int_cast
<short>( sp
- nParams
);
1030 SAL_WARN("formula.core", "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
1033 pStack
[sp
++] = pResult
;
1042 // --- Formula rewrite of a token array
1044 inline bool MissingConventionODF::isRewriteNeeded( OpCode eOp
) const
1056 return isPODF(); // rewrite only for PODF
1064 To be implemented yet:
1069 inline bool MissingConventionOOXML::isRewriteNeeded( OpCode eOp
)
1099 class FormulaMissingContext
1102 const FormulaToken
* mpFunc
;
1105 void Clear() { mpFunc
= NULL
; mnCurArg
= 0; }
1106 inline bool AddDefaultArg( FormulaTokenArray
* pNewArr
, int nArg
, double f
) const;
1107 bool AddMissingExternal( FormulaTokenArray
* pNewArr
) const;
1108 bool AddMissing( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const;
1109 void AddMoreArgs( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const;
1112 void FormulaMissingContext::AddMoreArgs( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const
1117 switch (rConv
.getConvention())
1119 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF
:
1120 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF
:
1122 switch (mpFunc
->GetOpCode())
1127 pNewArr
->AddOpCode( ocSep
);
1128 pNewArr
->AddDouble( 1.0 ); // 4th, Cumulative=true()
1134 pNewArr
->AddOpCode( ocSep
);
1135 pNewArr
->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1139 if ( mnCurArg
== 2 )
1141 pNewArr
->AddOpCode( ocSep
);
1142 pNewArr
->AddDouble( 1.0 ); // 4th, Cumulative=true()
1146 if ( mnCurArg
== 0 )
1148 pNewArr
->AddOpCode( ocSep
);
1149 pNewArr
->AddDouble( 0.0 ); // 2nd, mean = 0.0
1151 if ( mnCurArg
<= 1 )
1153 pNewArr
->AddOpCode( ocSep
);
1154 pNewArr
->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1158 if ( rConv
.isPODF() && mnCurArg
== 0 )
1160 pNewArr
->AddOpCode( ocSep
);
1161 pNewArr
->AddDouble( 10.0 ); // 2nd, basis 10
1169 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML
:
1171 switch (mpFunc
->GetOpCode())
1176 // Excel needs at least two parameters in IF function
1177 pNewArr
->AddOpCode( ocSep
);
1178 pNewArr
->AddOpCode( ocTrue
); // 2nd, true() as function
1179 pNewArr
->AddOpCode( ocOpen
); // so the result is of logical type
1180 pNewArr
->AddOpCode( ocClose
); // and survives roundtrip
1185 if ( mnCurArg
== 2 )
1187 pNewArr
->AddOpCode( ocSep
);
1188 pNewArr
->AddDouble( 0.0 ); // 4th, FullPrecision = false()
1195 pNewArr
->AddOpCode( ocSep
);
1196 pNewArr
->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1205 pNewArr
->AddOpCode( ocSep
);
1206 pNewArr
->AddDouble( 1.0 ); // 4th, Cumulative=true()
1211 if ( mnCurArg
== 0 )
1213 pNewArr
->AddOpCode( ocSep
);
1214 pNewArr
->AddDouble( 0.0 ); // 2nd, mean = 0.0
1216 if ( mnCurArg
<= 1 )
1218 pNewArr
->AddOpCode( ocSep
);
1219 pNewArr
->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1228 // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel
1229 pNewArr
->AddOpCode( ocSep
);
1230 pNewArr
->AddDouble( 0.0 ); // 2nd, 0.0
1243 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray
* pNewArr
, int nArg
, double f
) const
1245 if (mnCurArg
== nArg
)
1247 pNewArr
->AddDouble( f
);
1253 bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray
*pNewArr
) const
1255 // Only called for PODF, not ODFF. No need to distinguish.
1257 const OUString
&rName
= mpFunc
->GetExternal();
1259 // initial (fast) check:
1260 sal_Unicode nLastChar
= rName
[ rName
.getLength() - 1];
1261 if ( nLastChar
!= 't' && nLastChar
!= 'm' )
1264 if (rName
.equalsIgnoreAsciiCase(
1265 "com.sun.star.sheet.addin.Analysis.getAccrint" ))
1267 return AddDefaultArg( pNewArr
, 4, 1000.0 );
1269 if (rName
.equalsIgnoreAsciiCase(
1270 "com.sun.star.sheet.addin.Analysis.getAccrintm" ))
1272 return AddDefaultArg( pNewArr
, 3, 1000.0 );
1277 bool FormulaMissingContext::AddMissing( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const
1283 const OpCode eOp
= mpFunc
->GetOpCode();
1285 switch (rConv
.getConvention())
1287 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF
:
1293 return AddDefaultArg( pNewArr
, 2, 1.0 ); // abs
1299 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF
:
1305 return AddDefaultArg( pNewArr
, 2, 1.0 ); // abs
1307 return AddDefaultArg( pNewArr
, 1, 2.0 );
1311 return AddDefaultArg( pNewArr
, 3, 0.0 );
1314 return AddDefaultArg( pNewArr
, 4, 0.0 );
1317 bRet
|= AddDefaultArg( pNewArr
, 2, 0.0 ); // pmt
1318 bRet
|= AddDefaultArg( pNewArr
, 3, 0.0 ); // [fp]v
1321 bRet
|= AddDefaultArg( pNewArr
, 1, 0.0 ); // pmt
1322 bRet
|= AddDefaultArg( pNewArr
, 3, 0.0 ); // fv
1323 bRet
|= AddDefaultArg( pNewArr
, 4, 0.0 ); // type
1326 return AddMissingExternal( pNewArr
);
1328 // --- more complex cases ---
1331 // FIXME: rather tough.
1332 // if arg 3 (height) omitted, export arg1 (rows)
1339 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML
:
1344 return AddMissingExternal( pNewArr
);
1355 bool FormulaTokenArray::NeedsPodfRewrite( const MissingConventionODF
& rConv
)
1357 for ( FormulaToken
*pCur
= First(); pCur
; pCur
= Next() )
1359 if ( rConv
.isRewriteNeeded( pCur
->GetOpCode()))
1365 bool FormulaTokenArray::NeedsOoxmlRewrite()
1367 for ( FormulaToken
*pCur
= First(); pCur
; pCur
= Next() )
1369 if ( MissingConventionOOXML::isRewriteNeeded( pCur
->GetOpCode()))
1376 FormulaTokenArray
* FormulaTokenArray::RewriteMissing( const MissingConvention
& rConv
)
1378 const size_t nAlloc
= 256;
1379 FormulaMissingContext aCtx
[ nAlloc
];
1380 int aOpCodeAddressStack
[ nAlloc
]; // use of ADDRESS() function
1381 const int nOmitAddressArg
= 3; // ADDRESS() 4th parameter A1/R1C1
1382 sal_uInt16 nTokens
= GetLen() + 1;
1383 FormulaMissingContext
* pCtx
= (nAlloc
< nTokens
? new FormulaMissingContext
[nTokens
] : &aCtx
[0]);
1384 int* pOcas
= (nAlloc
< nTokens
? new int[nTokens
] : &aOpCodeAddressStack
[0]);
1385 // Never go below 0, never use 0, mpFunc always NULL.
1390 FormulaTokenArray
*pNewArr
= new FormulaTokenArray
;
1391 // At least ScRecalcMode::ALWAYS needs to be set.
1392 pNewArr
->AddRecalcMode( GetRecalcMode());
1394 for ( FormulaToken
*pCur
= First(); pCur
; pCur
= Next() )
1397 // Don't write the expression of the new inserted ADDRESS() parameter.
1398 // Do NOT omit the new second parameter of INDIRECT() though. If that
1399 // was done for both, INDIRECT() actually could calculate different and
1400 // valid (but wrong) results with the then changed return value of
1401 // ADDRESS(). Better let it generate an error instead.
1402 for (int i
= nOcas
; i
-- > 0 && bAdd
; )
1404 if (pCtx
[ pOcas
[ i
] ].mnCurArg
== nOmitAddressArg
)
1406 // Omit erverything except a trailing separator, the leading
1407 // separator is omitted below. The other way around would leave
1408 // an extraneous separator if no parameter followed.
1409 if (!(pOcas
[ i
] == nFn
&& pCur
->GetOpCode() == ocSep
))
1413 switch ( pCur
->GetOpCode() )
1416 ++nFn
; // all following operations on _that_ function
1417 pCtx
[ nFn
].mpFunc
= PeekPrevNoSpaces();
1418 pCtx
[ nFn
].mnCurArg
= 0;
1419 if (rConv
.isPODF() && pCtx
[ nFn
].mpFunc
&& pCtx
[ nFn
].mpFunc
->GetOpCode() == ocAddress
)
1420 pOcas
[ nOcas
++ ] = nFn
; // entering ADDRESS() if PODF
1423 pCtx
[ nFn
].AddMoreArgs( pNewArr
, rConv
);
1424 DBG_ASSERT( nFn
> 0, "FormulaTokenArray::RewriteMissing: underflow");
1425 if (nOcas
> 0 && pOcas
[ nOcas
-1 ] == nFn
)
1426 --nOcas
; // leaving ADDRESS()
1431 pCtx
[ nFn
].mnCurArg
++;
1432 // Omit leading separator of ADDRESS() parameter.
1433 if (nOcas
&& pOcas
[ nOcas
-1 ] == nFn
&& pCtx
[ nFn
].mnCurArg
== nOmitAddressArg
)
1440 bAdd
= !pCtx
[ nFn
].AddMissing( pNewArr
, rConv
);
1447 if ( ( pCur
->GetOpCode() == ocCeil
|| pCur
->GetOpCode() == ocFloor
) &&
1448 rConv
.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML
)
1450 FormulaToken
*pToken
= new FormulaToken( svByte
,
1451 ( pCur
->GetOpCode() == ocCeil
? ocCeil_Math
: ocFloor_Math
) );
1452 pNewArr
->AddToken( *pToken
);
1455 pNewArr
->AddToken( *pCur
);
1459 if (pOcas
!= &aOpCodeAddressStack
[0])
1461 if (pCtx
!= &aCtx
[0])
1467 bool FormulaTokenArray::MayReferenceFollow()
1469 if ( pCode
&& nLen
> 0 )
1471 // ignore trailing spaces
1472 sal_uInt16 i
= nLen
- 1;
1473 while ( i
> 0 && pCode
[i
]->GetOpCode() == SC_OPCODE_SPACES
)
1477 if ( i
> 0 || pCode
[i
]->GetOpCode() != SC_OPCODE_SPACES
)
1479 OpCode eOp
= pCode
[i
]->GetOpCode();
1480 if ( (SC_OPCODE_START_BIN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_BIN_OP
) ||
1481 (SC_OPCODE_START_UN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_UN_OP
) ||
1482 eOp
== SC_OPCODE_OPEN
|| eOp
== SC_OPCODE_SEP
)
1490 FormulaToken
* FormulaTokenArray::AddOpCode( OpCode eOp
)
1492 FormulaToken
* pRet
= NULL
;
1502 pRet
= new FormulaToken( svSep
,eOp
);
1509 short nJump
[FORMULA_MAXJUMPCOUNT
+ 1];
1512 else if ( eOp
== ocChoose
)
1513 nJump
[ 0 ] = FORMULA_MAXJUMPCOUNT
+ 1;
1516 pRet
= new FormulaJumpToken( eOp
, (short*)nJump
);
1520 pRet
= new FormulaByteToken( eOp
, 0, false );
1523 return AddToken( *pRet
);
1527 /*----------------------------------------------------------------------*/
1529 FormulaTokenIterator::Item::Item(const FormulaTokenArray
* pArray
, short pc
, short stop
) :
1530 pArr(pArray
), nPC(pc
), nStop(stop
)
1534 FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray
& rArr
)
1536 maStack
= new std::vector
<FormulaTokenIterator::Item
> ();
1540 FormulaTokenIterator::~FormulaTokenIterator()
1545 void FormulaTokenIterator::Push( const FormulaTokenArray
* pArr
)
1547 FormulaTokenIterator::Item
item(pArr
, -1, SHRT_MAX
);
1549 maStack
->push_back(item
);
1552 void FormulaTokenIterator::Pop()
1554 maStack
->pop_back();
1557 void FormulaTokenIterator::Reset()
1559 while( maStack
->size() > 1 )
1560 maStack
->pop_back();
1562 maStack
->back().nPC
= -1;
1565 const FormulaToken
* FormulaTokenIterator::Next()
1567 const FormulaToken
* t
= GetNonEndOfPathToken( ++maStack
->back().nPC
);
1568 if( !t
&& maStack
->size() > 1 )
1576 const FormulaToken
* FormulaTokenIterator::PeekNextOperator()
1578 const FormulaToken
* t
= NULL
;
1579 short nIdx
= maStack
->back().nPC
;
1580 while (!t
&& ((t
= GetNonEndOfPathToken( ++nIdx
)) != NULL
))
1582 if (t
->GetOpCode() == ocPush
)
1583 t
= NULL
; // ignore operands
1585 if (!t
&& maStack
->size() > 1)
1587 FormulaTokenIterator::Item pHere
= maStack
->back();
1588 maStack
->pop_back();
1589 t
= PeekNextOperator();
1590 maStack
->push_back(pHere
);
1595 //! The nPC counts after a Push() are -1
1597 void FormulaTokenIterator::Jump( short nStart
, short nNext
, short nStop
)
1599 maStack
->back().nPC
= nNext
;
1600 if( nStart
!= nNext
)
1602 Push( maStack
->back().pArr
);
1603 maStack
->back().nPC
= nStart
;
1604 maStack
->back().nStop
= nStop
;
1608 const FormulaToken
* FormulaTokenIterator::GetNonEndOfPathToken( short nIdx
) const
1610 FormulaTokenIterator::Item cur
= maStack
->back();
1612 if (nIdx
< cur
.pArr
->nRPN
&& nIdx
< cur
.nStop
)
1614 const FormulaToken
* t
= cur
.pArr
->pRPN
[ nIdx
];
1615 // such an OpCode ends an IF() or CHOOSE() path
1616 return (t
->GetOpCode() == ocSep
|| t
->GetOpCode() == ocClose
) ? NULL
: t
;
1621 bool FormulaTokenIterator::IsEndOfPath() const
1623 return GetNonEndOfPathToken( maStack
->back().nPC
+ 1) == NULL
;
1628 // real implementations of virtual functions
1631 double FormulaDoubleToken::GetDouble() const { return fDouble
; }
1632 double & FormulaDoubleToken::GetDoubleAsReference() { return fDouble
; }
1633 bool FormulaDoubleToken::operator==( const FormulaToken
& r
) const
1635 return FormulaToken::operator==( r
) && fDouble
== r
.GetDouble();
1638 FormulaStringToken::FormulaStringToken( const svl::SharedString
& r
) :
1639 FormulaToken( svString
), maString( r
)
1643 FormulaStringToken::FormulaStringToken( const FormulaStringToken
& r
) :
1644 FormulaToken( r
), maString( r
.maString
) {}
1646 FormulaToken
* FormulaStringToken::Clone() const
1648 return new FormulaStringToken(*this);
1651 svl::SharedString
FormulaStringToken::GetString() const
1656 bool FormulaStringToken::operator==( const FormulaToken
& r
) const
1658 return FormulaToken::operator==( r
) && maString
== r
.GetString();
1661 FormulaStringOpToken::FormulaStringOpToken( OpCode e
, const svl::SharedString
& r
) :
1662 FormulaByteToken( e
, 0, svString
, false ), maString( r
) {}
1664 FormulaStringOpToken::FormulaStringOpToken( const FormulaStringOpToken
& r
) :
1665 FormulaByteToken( r
), maString( r
.maString
) {}
1667 FormulaToken
* FormulaStringOpToken::Clone() const
1669 return new FormulaStringOpToken(*this);
1672 svl::SharedString
FormulaStringOpToken::GetString() const
1677 bool FormulaStringOpToken::operator==( const FormulaToken
& r
) const
1679 return FormulaByteToken::operator==( r
) && maString
== r
.GetString();
1682 sal_uInt16
FormulaIndexToken::GetIndex() const { return nIndex
; }
1683 void FormulaIndexToken::SetIndex( sal_uInt16 n
) { nIndex
= n
; }
1684 bool FormulaIndexToken::IsGlobal() const { return mbGlobal
; }
1685 void FormulaIndexToken::SetGlobal( bool b
) { mbGlobal
= b
; }
1686 bool FormulaIndexToken::operator==( const FormulaToken
& r
) const
1688 return FormulaToken::operator==( r
) && nIndex
== r
.GetIndex() &&
1689 mbGlobal
== r
.IsGlobal();
1691 const OUString
& FormulaExternalToken::GetExternal() const { return aExternal
; }
1692 sal_uInt8
FormulaExternalToken::GetByte() const { return nByte
; }
1693 void FormulaExternalToken::SetByte( sal_uInt8 n
) { nByte
= n
; }
1694 bool FormulaExternalToken::operator==( const FormulaToken
& r
) const
1696 return FormulaToken::operator==( r
) && nByte
== r
.GetByte() &&
1697 aExternal
== r
.GetExternal();
1701 sal_uInt16
FormulaErrorToken::GetError() const { return nError
; }
1702 void FormulaErrorToken::SetError( sal_uInt16 nErr
) { nError
= nErr
; }
1703 bool FormulaErrorToken::operator==( const FormulaToken
& r
) const
1705 return FormulaToken::operator==( r
) &&
1706 nError
== static_cast< const FormulaErrorToken
& >(r
).GetError();
1708 double FormulaMissingToken::GetDouble() const { return 0.0; }
1710 svl::SharedString
FormulaMissingToken::GetString() const
1712 return svl::SharedString::getEmptyString();
1715 bool FormulaMissingToken::operator==( const FormulaToken
& r
) const
1717 return FormulaToken::operator==( r
);
1721 FormulaSubroutineToken::FormulaSubroutineToken( const FormulaSubroutineToken
& r
) :
1723 mpArray( r
.mpArray
->Clone())
1726 FormulaSubroutineToken::~FormulaSubroutineToken()
1730 bool FormulaSubroutineToken::operator==( const FormulaToken
& r
) const
1732 // Arrays don't equal..
1733 return FormulaToken::operator==( r
) &&
1734 (mpArray
== static_cast<const FormulaSubroutineToken
&>(r
).mpArray
);
1738 bool FormulaUnknownToken::operator==( const FormulaToken
& r
) const
1740 return FormulaToken::operator==( r
);
1747 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */