1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: token.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_formula.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #if STLPORT_VERSION<321
47 #include <tools/debug.hxx>
49 #include "formula/token.hxx"
50 #include "formula/tokenarray.hxx"
51 #include "formula/FormulaCompiler.hxx"
52 #include <formula/compiler.hrc>
53 //#include "rechead.hxx"
54 //#include "parclass.hxx"
55 //#include "jumpmatrix.hxx"
56 #define MAXJUMPCOUNT 32 /* maximum number of jumps (ocChose) */
60 using namespace com::sun::star
;
61 // ImpTokenIterator wird je Interpreter angelegt, mehrfache auch durch
62 // SubCode via FormulaTokenIterator Push/Pop moeglich
63 IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator
, 32, 16 )
65 // Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2)
67 // Need a lot of FormulaDoubleToken
68 const USHORT nMemPoolDoubleToken
= (0x3000 - 64) / sizeof(FormulaDoubleToken
);
69 IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaDoubleToken
, nMemPoolDoubleToken
, nMemPoolDoubleToken
)
70 // Need a lot of FormulaByteToken
71 const USHORT nMemPoolByteToken
= (0x3000 - 64) / sizeof(FormulaByteToken
);
72 IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaByteToken
, nMemPoolByteToken
, nMemPoolByteToken
)
73 // Need several FormulaStringToken
74 const USHORT nMemPoolStringToken
= (0x1000 - 64) / sizeof(FormulaStringToken
);
75 IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaStringToken
, nMemPoolStringToken
, nMemPoolStringToken
)
78 // --- helpers --------------------------------------------------------------
80 inline BOOL
lcl_IsReference( OpCode eOp
, StackVar eType
)
83 (eOp
== ocPush
&& (eType
== svSingleRef
|| eType
== svDoubleRef
))
84 || (eOp
== ocColRowNameAuto
&& eType
== svDoubleRef
)
85 || (eOp
== ocColRowName
&& eType
== svSingleRef
)
86 || (eOp
== ocMatRef
&& eType
== svSingleRef
)
90 // --- class FormulaToken --------------------------------------------------------
91 FormulaToken::~FormulaToken()
95 BOOL
FormulaToken::Is3DRef() const
100 BOOL
FormulaToken::IsFunction() const
102 // OpCode eOp = GetOpCode();
103 return (eOp
!= ocPush
&& eOp
!= ocBad
&& eOp
!= ocColRowName
&&
104 eOp
!= ocColRowNameAuto
&& eOp
!= ocName
&& eOp
!= ocDBArea
&&
105 (GetByte() != 0 // x parameters
106 || (SC_OPCODE_START_NO_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_NO_PAR
) // no parameter
107 || (ocIf
== eOp
|| ocChose
== eOp
) // @ jump commands
108 || (SC_OPCODE_START_1_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_1_PAR
) // one parameter
109 || (SC_OPCODE_START_2_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_2_PAR
) // x parameters (cByte==0 in
111 || eOp
== ocMacro
|| eOp
== ocExternal
// macros, AddIns
112 || eOp
== ocAnd
|| eOp
== ocOr
// former binary, now x parameters
113 || eOp
== ocNot
|| eOp
== ocNeg
// unary but function
114 || (eOp
>= ocInternalBegin
&& eOp
<= ocInternalEnd
) // internal
119 BYTE
FormulaToken::GetParamCount() const
121 // OpCode eOp = GetOpCode();
122 if ( eOp
< SC_OPCODE_STOP_DIV
&& eOp
!= ocExternal
&& eOp
!= ocMacro
&&
123 eOp
!= ocIf
&& eOp
!= ocChose
&& eOp
!= ocPercentSign
)
124 return 0; // parameters and specials
125 // ocIf and ocChose not for FAP, have cByte then
126 //2do: BOOL parameter whether FAP or not?
127 else if ( GetByte() )
128 return GetByte(); // all functions, also ocExternal and ocMacro
129 else if (SC_OPCODE_START_BIN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_BIN_OP
)
131 else if ((SC_OPCODE_START_UN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_UN_OP
)
132 || eOp
== ocPercentSign
)
134 else if (SC_OPCODE_START_NO_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_NO_PAR
)
135 return 0; // no parameter
136 else if (SC_OPCODE_START_1_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_1_PAR
)
137 return 1; // one parameter
138 else if ( eOp
== ocIf
|| eOp
== ocChose
)
139 return 1; // only the condition counts as parameter
141 return 0; // all the rest, no Parameter, or
142 // if so then it should be in cByte
146 BOOL
FormulaToken::IsMatrixFunction() const
148 return formula::FormulaCompiler::IsMatrixFunction(GetOpCode());
151 BOOL
FormulaToken::operator==( const FormulaToken
& rToken
) const
153 // don't compare reference count!
154 return eType
== rToken
.eType
&& GetOpCode() == rToken
.GetOpCode();
158 // --- virtual dummy methods -------------------------------------------------
160 BYTE
FormulaToken::GetByte() const
162 // ok to be called for any derived class
166 void FormulaToken::SetByte( BYTE
)
168 DBG_ERRORFILE( "FormulaToken::SetByte: virtual dummy called" );
171 bool FormulaToken::HasForceArray() const
173 // ok to be called for any derived class
177 void FormulaToken::SetForceArray( bool )
179 DBG_ERRORFILE( "FormulaToken::SetForceArray: virtual dummy called" );
182 double FormulaToken::GetDouble() const
184 DBG_ERRORFILE( "FormulaToken::GetDouble: virtual dummy called" );
188 double & FormulaToken::GetDoubleAsReference()
190 DBG_ERRORFILE( "FormulaToken::GetDouble: virtual dummy called" );
191 static double fVal
= 0.0;
195 const String
& FormulaToken::GetString() const
197 DBG_ERRORFILE( "FormulaToken::GetString: virtual dummy called" );
198 static String aDummyString
;
202 USHORT
FormulaToken::GetIndex() const
204 DBG_ERRORFILE( "FormulaToken::GetIndex: virtual dummy called" );
208 void FormulaToken::SetIndex( USHORT
)
210 DBG_ERRORFILE( "FormulaToken::SetIndex: virtual dummy called" );
213 short* FormulaToken::GetJump() const
215 DBG_ERRORFILE( "FormulaToken::GetJump: virtual dummy called" );
220 const String
& FormulaToken::GetExternal() const
222 DBG_ERRORFILE( "FormulaToken::GetExternal: virtual dummy called" );
223 static String aDummyString
;
227 FormulaToken
* FormulaToken::GetFAPOrigToken() const
229 DBG_ERRORFILE( "FormulaToken::GetFAPOrigToken: virtual dummy called" );
233 USHORT
FormulaToken::GetError() const
235 DBG_ERRORFILE( "FormulaToken::GetError: virtual dummy called" );
239 void FormulaToken::SetError( USHORT
)
241 DBG_ERRORFILE( "FormulaToken::SetError: virtual dummy called" );
243 BOOL
FormulaToken::TextEqual( const FormulaToken
& rToken
) const
245 return *this == rToken
;
247 // ==========================================================================
248 // real implementations of virtual functions
249 // --------------------------------------------------------------------------
252 BYTE
FormulaByteToken::GetByte() const { return nByte
; }
253 void FormulaByteToken::SetByte( BYTE n
) { nByte
= n
; }
254 bool FormulaByteToken::HasForceArray() const { return bHasForceArray
; }
255 void FormulaByteToken::SetForceArray( bool b
) { bHasForceArray
= b
; }
256 BOOL
FormulaByteToken::operator==( const FormulaToken
& r
) const
258 return FormulaToken::operator==( r
) && nByte
== r
.GetByte() &&
259 bHasForceArray
== r
.HasForceArray();
263 FormulaToken
* FormulaFAPToken::GetFAPOrigToken() const { return pOrigToken
; }
264 BOOL
FormulaFAPToken::operator==( const FormulaToken
& r
) const
266 return FormulaByteToken::operator==( r
) && pOrigToken
== r
.GetFAPOrigToken();
268 short* FormulaJumpToken::GetJump() const { return pJump
; }
269 BOOL
FormulaJumpToken::operator==( const FormulaToken
& r
) const
271 return FormulaToken::operator==( r
) && pJump
[0] == r
.GetJump()[0] &&
272 memcmp( pJump
+1, r
.GetJump()+1, pJump
[0] * sizeof(short) ) == 0;
274 FormulaJumpToken::~FormulaJumpToken()
280 bool FormulaTokenArray::AddFormulaToken(const sheet::FormulaToken
& _aToken
,ExternalReferenceHelper
* /*_pRef*/)
283 const OpCode eOpCode
= static_cast<OpCode
>(_aToken
.OpCode
); //! assuming equal values for the moment
285 const uno::TypeClass eClass
= _aToken
.Data
.getValueTypeClass();
288 case uno::TypeClass_VOID
:
289 // empty data -> use AddOpCode (does some special cases)
290 AddOpCode( eOpCode
);
292 case uno::TypeClass_DOUBLE
:
293 // double is only used for "push"
294 if ( eOpCode
== ocPush
)
295 AddDouble( _aToken
.Data
.get
<double>() );
299 case uno::TypeClass_LONG
:
301 // long is svIndex, used for name / database area, or "byte" for spaces
302 sal_Int32 nValue
= _aToken
.Data
.get
<sal_Int32
>();
303 if ( eOpCode
== ocName
|| eOpCode
== ocDBArea
)
304 AddToken( formula::FormulaIndexToken( eOpCode
, static_cast<USHORT
>(nValue
) ) );
305 else if ( eOpCode
== ocSpaces
)
306 AddToken( formula::FormulaByteToken( ocSpaces
, static_cast<BYTE
>(nValue
) ) );
311 case uno::TypeClass_STRING
:
313 String
aStrVal( _aToken
.Data
.get
<rtl::OUString
>() );
314 if ( eOpCode
== ocPush
)
315 AddString( aStrVal
);
316 else if ( eOpCode
== ocBad
)
318 else if ( eOpCode
== ocExternal
|| eOpCode
== ocMacro
)
319 AddToken( formula::FormulaExternalToken( eOpCode
, aStrVal
) );
321 bError
= true; // unexpected string: don't know what to do with it
326 } // switch ( eClass )
329 bool FormulaTokenArray::Fill(const uno::Sequence
< sheet::FormulaToken
>& _aSequence
,ExternalReferenceHelper
* _pRef
)
332 const sal_Int32 nCount
= _aSequence
.getLength();
333 for (sal_Int32 nPos
=0; nPos
<nCount
; nPos
++)
335 bError
|= AddFormulaToken( _aSequence
[nPos
] ,_pRef
);
339 //////////////////////////////////////////////////////////////////////////
340 FormulaToken
* FormulaTokenArray::GetNextReference()
342 while( nIndex
< nLen
)
344 FormulaToken
* t
= pCode
[ nIndex
++ ];
345 switch( t
->GetType() )
349 case svExternalSingleRef
:
350 case svExternalDoubleRef
:
354 // added to avoid warnings
361 FormulaToken
* FormulaTokenArray::GetNextColRowName()
363 while( nIndex
< nLen
)
365 FormulaToken
* t
= pCode
[ nIndex
++ ];
366 if ( t
->GetOpCode() == ocColRowName
)
372 FormulaToken
* FormulaTokenArray::GetNextReferenceRPN()
374 while( nIndex
< nRPN
)
376 FormulaToken
* t
= pRPN
[ nIndex
++ ];
377 switch( t
->GetType() )
381 case svExternalSingleRef
:
382 case svExternalDoubleRef
:
386 // added to avoid warnings
393 FormulaToken
* FormulaTokenArray::GetNextReferenceOrName()
397 while ( nIndex
< nLen
)
399 FormulaToken
* t
= pCode
[ nIndex
++ ];
400 switch( t
->GetType() )
405 case svExternalSingleRef
:
406 case svExternalDoubleRef
:
411 // added to avoid warnings
419 FormulaToken
* FormulaTokenArray::GetNextName()
423 while ( nIndex
< nLen
)
425 FormulaToken
* t
= pCode
[ nIndex
++ ];
426 if( t
->GetType() == svIndex
)
433 FormulaToken
* FormulaTokenArray::GetNextDBArea()
437 while ( nIndex
< nLen
)
439 FormulaToken
* t
= pCode
[ nIndex
++ ];
440 if( t
->GetOpCode() == ocDBArea
)
442 } // while ( nIndex < nLen )+
447 FormulaToken
* FormulaTokenArray::GetNextOpCodeRPN( OpCode eOp
)
449 while( nIndex
< nRPN
)
451 FormulaToken
* t
= pRPN
[ nIndex
++ ];
452 if ( t
->GetOpCode() == eOp
)
458 FormulaToken
* FormulaTokenArray::Next()
460 if( pCode
&& nIndex
< nLen
)
461 return pCode
[ nIndex
++ ];
466 FormulaToken
* FormulaTokenArray::NextNoSpaces()
470 while( (nIndex
< nLen
) && (pCode
[ nIndex
]->GetOpCode() == ocSpaces
) )
473 return pCode
[ nIndex
++ ];
478 FormulaToken
* FormulaTokenArray::NextRPN()
480 if( pRPN
&& nIndex
< nRPN
)
481 return pRPN
[ nIndex
++ ];
486 FormulaToken
* FormulaTokenArray::PrevRPN()
489 return pRPN
[ --nIndex
];
494 void FormulaTokenArray::DelRPN()
498 FormulaToken
** p
= pRPN
;
499 for( USHORT i
= 0; i
< nRPN
; i
++ )
509 FormulaToken
* FormulaTokenArray::PeekPrev( USHORT
& nIdx
)
511 if (0 < nIdx
&& nIdx
<= nLen
)
512 return pCode
[--nIdx
];
516 FormulaToken
* FormulaTokenArray::PeekNext()
518 if( pCode
&& nIndex
< nLen
)
519 return pCode
[ nIndex
];
524 FormulaToken
* FormulaTokenArray::PeekNextNoSpaces()
526 if( pCode
&& nIndex
< nLen
)
529 while ( pCode
[j
]->GetOpCode() == ocSpaces
&& j
< nLen
)
540 FormulaToken
* FormulaTokenArray::PeekPrevNoSpaces()
542 if( pCode
&& nIndex
> 1 )
544 USHORT j
= nIndex
- 2;
545 while ( pCode
[j
]->GetOpCode() == ocSpaces
&& j
> 0 )
547 if ( j
> 0 || pCode
[j
]->GetOpCode() != ocSpaces
)
556 BOOL
FormulaTokenArray::HasOpCode( OpCode eOp
) const
558 for ( USHORT j
=0; j
< nLen
; j
++ )
560 if ( pCode
[j
]->GetOpCode() == eOp
)
566 BOOL
FormulaTokenArray::HasOpCodeRPN( OpCode eOp
) const
568 for ( USHORT j
=0; j
< nRPN
; j
++ )
570 if ( pRPN
[j
]->GetOpCode() == eOp
)
576 BOOL
FormulaTokenArray::HasNameOrColRowName() const
578 for ( USHORT j
=0; j
< nLen
; j
++ )
580 if( pCode
[j
]->GetType() == svIndex
|| pCode
[j
]->GetOpCode() == ocColRowName
)
586 ////////////////////////////////////////////////////////////////////////////
588 FormulaTokenArray::FormulaTokenArray()
590 pCode
= NULL
; pRPN
= NULL
;
591 nError
= nLen
= nIndex
= nRPN
= nRefs
= 0;
596 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray
& rArr
)
601 FormulaTokenArray::~FormulaTokenArray()
606 void FormulaTokenArray::Assign( const FormulaTokenArray
& r
)
614 bHyperLink
= r
.bHyperLink
;
620 pp
= pCode
= new FormulaToken
*[ nLen
];
621 memcpy( pp
, r
.pCode
, nLen
* sizeof( FormulaToken
* ) );
622 for( USHORT i
= 0; i
< nLen
; i
++ )
627 pp
= pRPN
= new FormulaToken
*[ nRPN
];
628 memcpy( pp
, r
.pRPN
, nRPN
* sizeof( FormulaToken
* ) );
629 for( USHORT i
= 0; i
< nRPN
; i
++ )
634 FormulaTokenArray
& FormulaTokenArray::operator=( const FormulaTokenArray
& rArr
)
641 FormulaTokenArray
* FormulaTokenArray::Clone() const
643 FormulaTokenArray
* p
= new FormulaTokenArray
;
649 p
->bHyperLink
= bHyperLink
;
653 pp
= p
->pCode
= new FormulaToken
*[ nLen
];
654 memcpy( pp
, pCode
, nLen
* sizeof( FormulaToken
* ) );
655 for( USHORT i
= 0; i
< nLen
; i
++, pp
++ )
657 *pp
= (*pp
)->Clone();
663 pp
= p
->pRPN
= new FormulaToken
*[ nRPN
];
664 memcpy( pp
, pRPN
, nRPN
* sizeof( FormulaToken
* ) );
665 for( USHORT i
= 0; i
< nRPN
; i
++, pp
++ )
667 FormulaToken
* t
= *pp
;
668 if( t
->GetRef() > 1 )
670 FormulaToken
** p2
= pCode
;
671 USHORT nIdx
= 0xFFFF;
672 for( USHORT j
= 0; j
< nLen
; j
++, p2
++ )
682 *pp
= p
->pCode
[ nIdx
];
692 void FormulaTokenArray::Clear()
697 FormulaToken
** p
= pCode
;
698 for( USHORT i
= 0; i
< nLen
; i
++ )
704 pCode
= NULL
; pRPN
= NULL
;
705 nError
= nLen
= nIndex
= nRPN
= nRefs
= 0;
710 FormulaToken
* FormulaTokenArray::AddToken( const FormulaToken
& r
)
712 return Add( r
.Clone() );
715 FormulaToken
* FormulaTokenArray::MergeArray( )
720 FormulaToken
* FormulaTokenArray::Add( FormulaToken
* t
)
723 pCode
= new FormulaToken
*[ MAXCODE
];
724 if( nLen
< MAXCODE
-1 )
726 // fprintf (stderr, "Add : %d\n", t->GetOpCode());
728 if( t
->GetOpCode() == ocPush
729 && ( t
->GetType() == svSingleRef
|| t
->GetType() == svDoubleRef
) )
732 if( t
->GetOpCode() == ocArrayClose
)
739 if ( nLen
== MAXCODE
-1 )
741 t
= new FormulaByteToken( ocStop
);
749 FormulaToken
* FormulaTokenArray::AddString( const sal_Unicode
* pStr
)
751 return AddString( String( pStr
) );
754 FormulaToken
* FormulaTokenArray::AddString( const String
& rStr
)
756 return Add( new FormulaStringToken( rStr
) );
759 FormulaToken
* FormulaTokenArray::AddDouble( double fVal
)
761 return Add( new FormulaDoubleToken( fVal
) );
764 FormulaToken
* FormulaTokenArray::AddName( USHORT n
)
766 return Add( new FormulaIndexToken( ocName
, n
) );
769 FormulaToken
* FormulaTokenArray::AddExternal( const sal_Unicode
* pStr
)
771 return AddExternal( String( pStr
) );
774 FormulaToken
* FormulaTokenArray::AddExternal( const String
& rStr
,
775 OpCode eOp
/* = ocExternal */ )
777 return Add( new FormulaExternalToken( eOp
, rStr
) );
780 FormulaToken
* FormulaTokenArray::AddBad( const sal_Unicode
* pStr
)
782 return AddBad( String( pStr
) );
785 FormulaToken
* FormulaTokenArray::AddBad( const String
& rStr
)
787 return Add( new FormulaStringOpToken( ocBad
, rStr
) );
792 void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits
)
794 //! Reihenfolge ist wichtig
795 if ( nBits
& RECALCMODE_ALWAYS
)
796 SetRecalcModeAlways();
797 else if ( !IsRecalcModeAlways() )
799 if ( nBits
& RECALCMODE_ONLOAD
)
800 SetRecalcModeOnLoad();
801 else if ( nBits
& RECALCMODE_ONLOAD_ONCE
&& !IsRecalcModeOnLoad() )
802 SetRecalcModeOnLoadOnce();
804 SetCombinedBitsRecalcMode( nBits
);
808 BOOL
FormulaTokenArray::HasMatrixDoubleRefOps()
812 // RPN-Interpreter Simulation
813 // als Ergebnis jeder Funktion wird einfach ein Double angenommen
814 FormulaToken
** pStack
= new FormulaToken
* [nRPN
];
815 FormulaToken
* pResult
= new FormulaDoubleToken( 0.0 );
817 for ( USHORT j
= 0; j
< nRPN
; j
++ )
819 FormulaToken
* t
= pRPN
[j
];
820 OpCode eOp
= t
->GetOpCode();
821 BYTE nParams
= t
->GetParamCount();
836 case ocGreaterEqual
:
838 for ( BYTE k
= nParams
; k
; k
-- )
840 if ( sp
>= k
&& pStack
[sp
-k
]->GetType() == svDoubleRef
)
851 // added to avoid warnings
854 if ( eOp
== ocPush
|| lcl_IsReference( eOp
, t
->GetType() ) )
856 else if ( eOp
== ocIf
|| eOp
== ocChose
)
857 { // Jumps ignorieren, vorheriges Result (Condition) poppen
862 { // pop parameters, push result
863 sp
= sal::static_int_cast
<short>( sp
- nParams
);
866 DBG_ERROR( "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
869 pStack
[sp
++] = pResult
;
881 // --- POF (plain old formula) rewrite of a token array ---------------------
884 // static function can't be compiled if not used (warning)
885 //#if OSL_DEBUG_LEVEL > 0
886 static void DumpTokArr( FormulaTokenArray
*pCode
)
888 fprintf (stderr
, "TokenArr: ");
889 for ( FormulaToken
*pCur
= pCode
->First(); pCur
; pCur
= pCode
->Next() )
890 fprintf( stderr
, "t%d,o%d ",
891 pCur
->GetType(), pCur
->GetOpCode() );
892 fprintf (stderr
, "\n");
896 inline bool MissingConvention::isRewriteNeeded( OpCode eOp
) const
906 return !isODFF(); // rewrite only for PODF
912 class FormulaMissingContext
915 const FormulaToken
* mpFunc
;
918 void Clear() { mpFunc
= NULL
; mnCurArg
= 0; }
919 inline bool AddDefaultArg( FormulaTokenArray
* pNewArr
, int nArg
, double f
) const;
920 bool AddMissingExternal( FormulaTokenArray
* pNewArr
) const;
921 bool AddMissing( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const;
922 void AddMoreArgs( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const;
925 void FormulaMissingContext::AddMoreArgs( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const
930 switch (mpFunc
->GetOpCode())
935 pNewArr
->AddOpCode( ocSep
);
936 pNewArr
->AddDouble( 1.0 ); // 4th, Cumulative=TRUE()
942 pNewArr
->AddOpCode( ocSep
);
943 pNewArr
->AddDouble( 1.0 ); // 3rd, Cumulative=TRUE()
947 if ( !rConv
.isODFF() && mnCurArg
== 0 )
949 pNewArr
->AddOpCode( ocSep
);
950 pNewArr
->AddDouble( 10.0 ); // 2nd, basis 10
958 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray
* pNewArr
, int nArg
, double f
) const
960 if (mnCurArg
== nArg
)
962 pNewArr
->AddDouble( f
);
968 bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray
*pNewArr
) const
970 // Only called for PODF, not ODFF. No need to distinguish.
972 const String
&rName
= mpFunc
->GetExternal();
974 // initial (fast) check:
975 sal_Unicode nLastChar
= rName
.GetChar( rName
.Len() - 1);
976 if ( nLastChar
!= 't' && nLastChar
!= 'm' )
979 if (rName
.EqualsIgnoreCaseAscii(
980 "com.sun.star.sheet.addin.Analysis.getAccrint" ))
982 return AddDefaultArg( pNewArr
, 4, 1000.0 );
984 if (rName
.EqualsIgnoreCaseAscii(
985 "com.sun.star.sheet.addin.Analysis.getAccrintm" ))
987 return AddDefaultArg( pNewArr
, 3, 1000.0 );
992 bool FormulaMissingContext::AddMissing( FormulaTokenArray
*pNewArr
, const MissingConvention
& rConv
) const
998 const OpCode eOp
= mpFunc
->GetOpCode();
1000 // Add for both, PODF and ODFF
1004 return AddDefaultArg( pNewArr
, 2, 1.0 ); // abs
1019 return AddDefaultArg( pNewArr
, 1, 2.0 );
1023 return AddDefaultArg( pNewArr
, 3, 0.0 );
1024 case ocZinsZ
: // IPMT
1025 case ocKapz
: // PPMT
1026 return AddDefaultArg( pNewArr
, 4, 0.0 );
1029 bRet
|= AddDefaultArg( pNewArr
, 2, 0.0 ); // pmt
1030 bRet
|= AddDefaultArg( pNewArr
, 3, 0.0 ); // [fp]v
1032 case ocZins
: // RATE
1033 bRet
|= AddDefaultArg( pNewArr
, 1, 0.0 ); // pmt
1034 bRet
|= AddDefaultArg( pNewArr
, 3, 0.0 ); // fv
1035 bRet
|= AddDefaultArg( pNewArr
, 4, 0.0 ); // type
1038 return AddMissingExternal( pNewArr
);
1040 // --- more complex cases ---
1043 // FIXME: rather tough.
1044 // if arg 3 (height) ommitted, export arg1 (rows)
1054 bool FormulaTokenArray::NeedsPofRewrite( const MissingConvention
& rConv
)
1056 for ( FormulaToken
*pCur
= First(); pCur
; pCur
= Next() )
1058 if ( rConv
.isRewriteNeeded( pCur
->GetOpCode()))
1065 FormulaTokenArray
* FormulaTokenArray::RewriteMissingToPof( const MissingConvention
& rConv
)
1067 const size_t nAlloc
= 256;
1068 FormulaMissingContext aCtx
[ nAlloc
];
1069 int aOpCodeAddressStack
[ nAlloc
]; // use of ADDRESS() function
1070 const int nOmitAddressArg
= 3; // ADDRESS() 4th parameter A1/R1C1
1071 USHORT nTokens
= GetLen() + 1;
1072 FormulaMissingContext
* pCtx
= (nAlloc
< nTokens
? new FormulaMissingContext
[nTokens
] : &aCtx
[0]);
1073 int* pOcas
= (nAlloc
< nTokens
? new int[nTokens
] : &aOpCodeAddressStack
[0]);
1074 // Never go below 0, never use 0, mpFunc always NULL.
1079 FormulaTokenArray
*pNewArr
= new FormulaTokenArray
;
1080 // At least RECALCMODE_ALWAYS needs to be set.
1081 pNewArr
->AddRecalcMode( GetRecalcMode());
1083 for ( FormulaToken
*pCur
= First(); pCur
; pCur
= Next() )
1086 // Don't write the expression of the new inserted ADDRESS() parameter.
1087 // Do NOT omit the new second parameter of INDIRECT() though. If that
1088 // was done for both, INDIRECT() actually could calculate different and
1089 // valid (but wrong) results with the then changed return value of
1090 // ADDRESS(). Better let it generate an error instead.
1091 for (int i
= nOcas
; i
-- > 0 && bAdd
; )
1093 if (pCtx
[ pOcas
[ i
] ].mnCurArg
== nOmitAddressArg
)
1095 // Omit erverything except a trailing separator, the leading
1096 // separator is omitted below. The other way around would leave
1097 // an extraneous separator if no parameter followed.
1098 if (!(pOcas
[ i
] == nFn
&& pCur
->GetOpCode() == ocSep
))
1101 //fprintf( stderr, "ocAddress %d arg %d%s\n", (int)i, (int)pCtx[ pOcas[ i ] ].mnCurArg, (bAdd ? "" : " omitted"));
1103 switch ( pCur
->GetOpCode() )
1106 ++nFn
; // all following operations on _that_ function
1107 pCtx
[ nFn
].mpFunc
= PeekPrevNoSpaces();
1108 pCtx
[ nFn
].mnCurArg
= 0;
1109 if (pCtx
[ nFn
].mpFunc
&& pCtx
[ nFn
].mpFunc
->GetOpCode() == ocAddress
&& !rConv
.isODFF())
1110 pOcas
[ nOcas
++ ] = nFn
; // entering ADDRESS() if PODF
1113 pCtx
[ nFn
].AddMoreArgs( pNewArr
, rConv
);
1114 DBG_ASSERT( nFn
> 0, "FormulaTokenArray::RewriteMissingToPof: underflow");
1115 if (nOcas
> 0 && pOcas
[ nOcas
-1 ] == nFn
)
1116 --nOcas
; // leaving ADDRESS()
1121 pCtx
[ nFn
].mnCurArg
++;
1122 // Omit leading separator of ADDRESS() parameter.
1123 if (nOcas
&& pOcas
[ nOcas
-1 ] == nFn
&& pCtx
[ nFn
].mnCurArg
== nOmitAddressArg
)
1126 //fprintf( stderr, "ocAddress %d sep %d omitted\n", (int)nOcas-1, nOmitAddressArg);
1131 bAdd
= !pCtx
[ nFn
].AddMissing( pNewArr
, rConv
);
1137 pNewArr
->AddToken( *pCur
);
1140 if (pOcas
!= &aOpCodeAddressStack
[0])
1142 if (pCtx
!= &aCtx
[0])
1148 bool FormulaTokenArray::MayReferenceFollow()
1150 if ( pCode
&& nLen
> 0 )
1152 // ignore trailing spaces
1153 USHORT i
= nLen
- 1;
1154 while ( i
> 0 && pCode
[i
]->GetOpCode() == SC_OPCODE_SPACES
)
1158 if ( i
> 0 || pCode
[i
]->GetOpCode() != SC_OPCODE_SPACES
)
1160 OpCode eOp
= pCode
[i
]->GetOpCode();
1161 if ( (SC_OPCODE_START_BIN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_BIN_OP
) ||
1162 (SC_OPCODE_START_UN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_UN_OP
) ||
1163 eOp
== SC_OPCODE_OPEN
|| eOp
== SC_OPCODE_SEP
)
1171 FormulaToken
* FormulaTokenArray::AddOpCode( OpCode eOp
)
1173 FormulaToken
* pRet
= NULL
;
1183 pRet
= new FormulaToken( svSep
,eOp
);
1188 short nJump
[MAXJUMPCOUNT
+ 1];
1189 nJump
[ 0 ] = ocIf
== eOp
? 3 : MAXJUMPCOUNT
+1;
1190 pRet
= new FormulaJumpToken( eOp
, (short*)nJump
);
1194 pRet
= new FormulaByteToken( eOp
, 0, FALSE
);
1197 return AddToken( *pRet
);
1201 /*----------------------------------------------------------------------*/
1203 FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray
& rArr
)
1209 FormulaTokenIterator::~FormulaTokenIterator()
1215 void FormulaTokenIterator::Push( const FormulaTokenArray
* pArr
)
1217 ImpTokenIterator
* p
= new ImpTokenIterator
;
1220 p
->nStop
= SHRT_MAX
;
1225 void FormulaTokenIterator::Pop()
1227 ImpTokenIterator
* p
= pCur
;
1235 void FormulaTokenIterator::Reset()
1237 while( pCur
->pNext
)
1242 const FormulaToken
* FormulaTokenIterator::First()
1248 const FormulaToken
* FormulaTokenIterator::Next()
1250 const FormulaToken
* t
= NULL
;
1252 if( pCur
->nPC
< pCur
->pArr
->nRPN
&& pCur
->nPC
< pCur
->nStop
)
1254 t
= pCur
->pArr
->pRPN
[ pCur
->nPC
];
1255 // such an OpCode ends an IF() or CHOOSE() path
1256 if( t
->GetOpCode() == ocSep
|| t
->GetOpCode() == ocClose
)
1259 if( !t
&& pCur
->pNext
)
1267 //! The nPC counts after a Push() are -1
1269 void FormulaTokenIterator::Jump( short nStart
, short nNext
, short nStop
)
1272 if( nStart
!= nNext
)
1276 pCur
->nStop
= nStop
;
1280 bool FormulaTokenIterator::IsEndOfPath() const
1282 USHORT nTest
= pCur
->nPC
+ 1;
1283 if( nTest
< pCur
->pArr
->nRPN
&& nTest
< pCur
->nStop
)
1285 const FormulaToken
* t
= pCur
->pArr
->pRPN
[ nTest
];
1286 // such an OpCode ends an IF() or CHOOSE() path
1287 return t
->GetOpCode() == ocSep
|| t
->GetOpCode() == ocClose
;
1291 // -----------------------------------------------------------------------------
1292 // ==========================================================================
1293 // real implementations of virtual functions
1294 // --------------------------------------------------------------------------
1296 double FormulaDoubleToken::GetDouble() const { return fDouble
; }
1297 double & FormulaDoubleToken::GetDoubleAsReference() { return fDouble
; }
1298 BOOL
FormulaDoubleToken::operator==( const FormulaToken
& r
) const
1300 return FormulaToken::operator==( r
) && fDouble
== r
.GetDouble();
1304 const String
& FormulaStringToken::GetString() const { return aString
; }
1305 BOOL
FormulaStringToken::operator==( const FormulaToken
& r
) const
1307 return FormulaToken::operator==( r
) && aString
== r
.GetString();
1311 const String
& FormulaStringOpToken::GetString() const { return aString
; }
1312 BOOL
FormulaStringOpToken::operator==( const FormulaToken
& r
) const
1314 return FormulaByteToken::operator==( r
) && aString
== r
.GetString();
1317 USHORT
FormulaIndexToken::GetIndex() const { return nIndex
; }
1318 void FormulaIndexToken::SetIndex( USHORT n
) { nIndex
= n
; }
1319 BOOL
FormulaIndexToken::operator==( const FormulaToken
& r
) const
1321 return FormulaToken::operator==( r
) && nIndex
== r
.GetIndex();
1323 const String
& FormulaExternalToken::GetExternal() const { return aExternal
; }
1324 BYTE
FormulaExternalToken::GetByte() const { return nByte
; }
1325 void FormulaExternalToken::SetByte( BYTE n
) { nByte
= n
; }
1326 BOOL
FormulaExternalToken::operator==( const FormulaToken
& r
) const
1328 return FormulaToken::operator==( r
) && nByte
== r
.GetByte() &&
1329 aExternal
== r
.GetExternal();
1333 USHORT
FormulaErrorToken::GetError() const { return nError
; }
1334 void FormulaErrorToken::SetError( USHORT nErr
) { nError
= nErr
; }
1335 BOOL
FormulaErrorToken::operator==( const FormulaToken
& r
) const
1337 return FormulaToken::operator==( r
) &&
1338 nError
== static_cast< const FormulaErrorToken
& >(r
).GetError();
1340 double FormulaMissingToken::GetDouble() const { return 0.0; }
1341 const String
& FormulaMissingToken::GetString() const
1343 static String aDummyString
;
1344 return aDummyString
;
1346 BOOL
FormulaMissingToken::operator==( const FormulaToken
& r
) const
1348 return FormulaToken::operator==( r
);
1352 BOOL
FormulaUnknownToken::operator==( const FormulaToken
& r
) const
1354 return FormulaToken::operator==( r
);
1357 // -----------------------------------------------------------------------------
1359 // -----------------------------------------------------------------------------