merge the formfield patch from ooo-build
[ooovba.git] / formula / source / core / api / token.cxx
blob74795e32fe743ab9c27d9fb2026a737be3a32fe7
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: token.cxx,v $
10 * $Revision: 1.34 $
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
39 #include <stddef.h>
40 #else
41 #include <cstddef>
42 #endif
43 #include <cstdio>
45 #include <string.h>
46 #include <limits.h>
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) */
58 namespace formula
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 )
82 return
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
97 return FALSE;
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
110 // FuncAutoPilot)
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)
130 return 2; // binary
131 else if ((SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)
132 || eOp == ocPercentSign)
133 return 1; // unary
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
140 else
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
163 return 0;
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
174 return false;
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" );
185 return 0.0;
188 double & FormulaToken::GetDoubleAsReference()
190 DBG_ERRORFILE( "FormulaToken::GetDouble: virtual dummy called" );
191 static double fVal = 0.0;
192 return fVal;
195 const String& FormulaToken::GetString() const
197 DBG_ERRORFILE( "FormulaToken::GetString: virtual dummy called" );
198 static String aDummyString;
199 return aDummyString;
202 USHORT FormulaToken::GetIndex() const
204 DBG_ERRORFILE( "FormulaToken::GetIndex: virtual dummy called" );
205 return 0;
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" );
216 return NULL;
220 const String& FormulaToken::GetExternal() const
222 DBG_ERRORFILE( "FormulaToken::GetExternal: virtual dummy called" );
223 static String aDummyString;
224 return aDummyString;
227 FormulaToken* FormulaToken::GetFAPOrigToken() const
229 DBG_ERRORFILE( "FormulaToken::GetFAPOrigToken: virtual dummy called" );
230 return NULL;
233 USHORT FormulaToken::GetError() const
235 DBG_ERRORFILE( "FormulaToken::GetError: virtual dummy called" );
236 return 0;
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()
276 delete [] pJump;
280 bool FormulaTokenArray::AddFormulaToken(const sheet::FormulaToken& _aToken,ExternalReferenceHelper* /*_pRef*/)
282 bool bError = false;
283 const OpCode eOpCode = static_cast<OpCode>(_aToken.OpCode); //! assuming equal values for the moment
285 const uno::TypeClass eClass = _aToken.Data.getValueTypeClass();
286 switch ( eClass )
288 case uno::TypeClass_VOID:
289 // empty data -> use AddOpCode (does some special cases)
290 AddOpCode( eOpCode );
291 break;
292 case uno::TypeClass_DOUBLE:
293 // double is only used for "push"
294 if ( eOpCode == ocPush )
295 AddDouble( _aToken.Data.get<double>() );
296 else
297 bError = true;
298 break;
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) ) );
307 else
308 bError = true;
310 break;
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 )
317 AddBad( aStrVal );
318 else if ( eOpCode == ocExternal || eOpCode == ocMacro )
319 AddToken( formula::FormulaExternalToken( eOpCode, aStrVal ) );
320 else
321 bError = true; // unexpected string: don't know what to do with it
323 break;
324 default:
325 bError = true;
326 } // switch ( eClass )
327 return bError;
329 bool FormulaTokenArray::Fill(const uno::Sequence< sheet::FormulaToken >& _aSequence,ExternalReferenceHelper* _pRef)
331 bool bError = false;
332 const sal_Int32 nCount = _aSequence.getLength();
333 for (sal_Int32 nPos=0; nPos<nCount; nPos++)
335 bError |= AddFormulaToken( _aSequence[nPos] ,_pRef);
337 return bError;
339 //////////////////////////////////////////////////////////////////////////
340 FormulaToken* FormulaTokenArray::GetNextReference()
342 while( nIndex < nLen )
344 FormulaToken* t = pCode[ nIndex++ ];
345 switch( t->GetType() )
347 case svSingleRef:
348 case svDoubleRef:
349 case svExternalSingleRef:
350 case svExternalDoubleRef:
351 return t;
352 default:
354 // added to avoid warnings
358 return NULL;
361 FormulaToken* FormulaTokenArray::GetNextColRowName()
363 while( nIndex < nLen )
365 FormulaToken* t = pCode[ nIndex++ ];
366 if ( t->GetOpCode() == ocColRowName )
367 return t;
369 return NULL;
372 FormulaToken* FormulaTokenArray::GetNextReferenceRPN()
374 while( nIndex < nRPN )
376 FormulaToken* t = pRPN[ nIndex++ ];
377 switch( t->GetType() )
379 case svSingleRef:
380 case svDoubleRef:
381 case svExternalSingleRef:
382 case svExternalDoubleRef:
383 return t;
384 default:
386 // added to avoid warnings
390 return NULL;
393 FormulaToken* FormulaTokenArray::GetNextReferenceOrName()
395 if( pCode )
397 while ( nIndex < nLen )
399 FormulaToken* t = pCode[ nIndex++ ];
400 switch( t->GetType() )
402 case svSingleRef:
403 case svDoubleRef:
404 case svIndex:
405 case svExternalSingleRef:
406 case svExternalDoubleRef:
407 case svExternalName:
408 return t;
409 default:
411 // added to avoid warnings
416 return NULL;
419 FormulaToken* FormulaTokenArray::GetNextName()
421 if( pCode )
423 while ( nIndex < nLen )
425 FormulaToken* t = pCode[ nIndex++ ];
426 if( t->GetType() == svIndex )
427 return t;
429 } // if( pCode )
430 return NULL;
433 FormulaToken* FormulaTokenArray::GetNextDBArea()
435 if( pCode )
437 while ( nIndex < nLen )
439 FormulaToken* t = pCode[ nIndex++ ];
440 if( t->GetOpCode() == ocDBArea )
441 return t;
442 } // while ( nIndex < nLen )+
444 return NULL;
447 FormulaToken* FormulaTokenArray::GetNextOpCodeRPN( OpCode eOp )
449 while( nIndex < nRPN )
451 FormulaToken* t = pRPN[ nIndex++ ];
452 if ( t->GetOpCode() == eOp )
453 return t;
455 return NULL;
458 FormulaToken* FormulaTokenArray::Next()
460 if( pCode && nIndex < nLen )
461 return pCode[ nIndex++ ];
462 else
463 return NULL;
466 FormulaToken* FormulaTokenArray::NextNoSpaces()
468 if( pCode )
470 while( (nIndex < nLen) && (pCode[ nIndex ]->GetOpCode() == ocSpaces) )
471 ++nIndex;
472 if( nIndex < nLen )
473 return pCode[ nIndex++ ];
475 return NULL;
478 FormulaToken* FormulaTokenArray::NextRPN()
480 if( pRPN && nIndex < nRPN )
481 return pRPN[ nIndex++ ];
482 else
483 return NULL;
486 FormulaToken* FormulaTokenArray::PrevRPN()
488 if( pRPN && nIndex )
489 return pRPN[ --nIndex ];
490 else
491 return NULL;
494 void FormulaTokenArray::DelRPN()
496 if( nRPN )
498 FormulaToken** p = pRPN;
499 for( USHORT i = 0; i < nRPN; i++ )
501 (*p++)->DecRef();
503 delete [] pRPN;
505 pRPN = NULL;
506 nRPN = nIndex = 0;
509 FormulaToken* FormulaTokenArray::PeekPrev( USHORT & nIdx )
511 if (0 < nIdx && nIdx <= nLen)
512 return pCode[--nIdx];
513 return NULL;
516 FormulaToken* FormulaTokenArray::PeekNext()
518 if( pCode && nIndex < nLen )
519 return pCode[ nIndex ];
520 else
521 return NULL;
524 FormulaToken* FormulaTokenArray::PeekNextNoSpaces()
526 if( pCode && nIndex < nLen )
528 USHORT j = nIndex;
529 while ( pCode[j]->GetOpCode() == ocSpaces && j < nLen )
530 j++;
531 if ( j < nLen )
532 return pCode[ j ];
533 else
534 return NULL;
536 else
537 return NULL;
540 FormulaToken* FormulaTokenArray::PeekPrevNoSpaces()
542 if( pCode && nIndex > 1 )
544 USHORT j = nIndex - 2;
545 while ( pCode[j]->GetOpCode() == ocSpaces && j > 0 )
546 j--;
547 if ( j > 0 || pCode[j]->GetOpCode() != ocSpaces )
548 return pCode[ j ];
549 else
550 return NULL;
552 else
553 return NULL;
556 BOOL FormulaTokenArray::HasOpCode( OpCode eOp ) const
558 for ( USHORT j=0; j < nLen; j++ )
560 if ( pCode[j]->GetOpCode() == eOp )
561 return TRUE;
563 return FALSE;
566 BOOL FormulaTokenArray::HasOpCodeRPN( OpCode eOp ) const
568 for ( USHORT j=0; j < nRPN; j++ )
570 if ( pRPN[j]->GetOpCode() == eOp )
571 return TRUE;
573 return FALSE;
576 BOOL FormulaTokenArray::HasNameOrColRowName() const
578 for ( USHORT j=0; j < nLen; j++ )
580 if( pCode[j]->GetType() == svIndex || pCode[j]->GetOpCode() == ocColRowName )
581 return TRUE;
583 return FALSE;
586 ////////////////////////////////////////////////////////////////////////////
588 FormulaTokenArray::FormulaTokenArray()
590 pCode = NULL; pRPN = NULL;
591 nError = nLen = nIndex = nRPN = nRefs = 0;
592 bHyperLink = FALSE;
593 ClearRecalcMode();
596 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray& rArr )
598 Assign( rArr );
601 FormulaTokenArray::~FormulaTokenArray()
603 Clear();
606 void FormulaTokenArray::Assign( const FormulaTokenArray& r )
608 nLen = r.nLen;
609 nRPN = r.nRPN;
610 nIndex = r.nIndex;
611 nError = r.nError;
612 nRefs = r.nRefs;
613 nMode = r.nMode;
614 bHyperLink = r.bHyperLink;
615 pCode = NULL;
616 pRPN = NULL;
617 FormulaToken** pp;
618 if( nLen )
620 pp = pCode = new FormulaToken*[ nLen ];
621 memcpy( pp, r.pCode, nLen * sizeof( FormulaToken* ) );
622 for( USHORT i = 0; i < nLen; i++ )
623 (*pp++)->IncRef();
625 if( nRPN )
627 pp = pRPN = new FormulaToken*[ nRPN ];
628 memcpy( pp, r.pRPN, nRPN * sizeof( FormulaToken* ) );
629 for( USHORT i = 0; i < nRPN; i++ )
630 (*pp++)->IncRef();
634 FormulaTokenArray& FormulaTokenArray::operator=( const FormulaTokenArray& rArr )
636 Clear();
637 Assign( rArr );
638 return *this;
641 FormulaTokenArray* FormulaTokenArray::Clone() const
643 FormulaTokenArray* p = new FormulaTokenArray;
644 p->nLen = nLen;
645 p->nRPN = nRPN;
646 p->nRefs = nRefs;
647 p->nMode = nMode;
648 p->nError = nError;
649 p->bHyperLink = bHyperLink;
650 FormulaToken** pp;
651 if( nLen )
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();
658 (*pp)->IncRef();
661 if( nRPN )
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++ )
674 if( *p2 == t )
676 nIdx = j; break;
679 if( nIdx == 0xFFFF )
680 *pp = t->Clone();
681 else
682 *pp = p->pCode[ nIdx ];
684 else
685 *pp = t->Clone();
686 (*pp)->IncRef();
689 return p;
692 void FormulaTokenArray::Clear()
694 if( nRPN ) DelRPN();
695 if( pCode )
697 FormulaToken** p = pCode;
698 for( USHORT i = 0; i < nLen; i++ )
700 (*p++)->DecRef();
702 delete [] pCode;
704 pCode = NULL; pRPN = NULL;
705 nError = nLen = nIndex = nRPN = nRefs = 0;
706 bHyperLink = FALSE;
707 ClearRecalcMode();
710 FormulaToken* FormulaTokenArray::AddToken( const FormulaToken& r )
712 return Add( r.Clone() );
715 FormulaToken* FormulaTokenArray::MergeArray( )
717 return NULL;
720 FormulaToken* FormulaTokenArray::Add( FormulaToken* t )
722 if( !pCode )
723 pCode = new FormulaToken*[ MAXCODE ];
724 if( nLen < MAXCODE-1 )
726 // fprintf (stderr, "Add : %d\n", t->GetOpCode());
727 pCode[ nLen++ ] = t;
728 if( t->GetOpCode() == ocPush
729 && ( t->GetType() == svSingleRef || t->GetType() == svDoubleRef ) )
730 nRefs++;
731 t->IncRef();
732 if( t->GetOpCode() == ocArrayClose )
733 return MergeArray();
734 return t;
736 else
738 t->Delete();
739 if ( nLen == MAXCODE-1 )
741 t = new FormulaByteToken( ocStop );
742 pCode[ nLen++ ] = t;
743 t->IncRef();
745 return NULL;
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()
810 if ( pRPN && nRPN )
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 );
816 short sp = 0;
817 for ( USHORT j = 0; j < nRPN; j++ )
819 FormulaToken* t = pRPN[j];
820 OpCode eOp = t->GetOpCode();
821 BYTE nParams = t->GetParamCount();
822 switch ( eOp )
824 case ocAdd :
825 case ocSub :
826 case ocMul :
827 case ocDiv :
828 case ocPow :
829 case ocPower :
830 case ocAmpersand :
831 case ocEqual :
832 case ocNotEqual :
833 case ocLess :
834 case ocGreater :
835 case ocLessEqual :
836 case ocGreaterEqual :
838 for ( BYTE k = nParams; k; k-- )
840 if ( sp >= k && pStack[sp-k]->GetType() == svDoubleRef )
842 pResult->Delete();
843 delete [] pStack;
844 return TRUE;
848 break;
849 default:
851 // added to avoid warnings
854 if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() ) )
855 pStack[sp++] = t;
856 else if ( eOp == ocIf || eOp == ocChose )
857 { // Jumps ignorieren, vorheriges Result (Condition) poppen
858 if ( sp )
859 --sp;
861 else
862 { // pop parameters, push result
863 sp = sal::static_int_cast<short>( sp - nParams );
864 if ( sp < 0 )
866 DBG_ERROR( "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
867 sp = 0;
869 pStack[sp++] = pResult;
872 pResult->Delete();
873 delete [] pStack;
876 return FALSE;
881 // --- POF (plain old formula) rewrite of a token array ---------------------
883 #if 0
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");
894 #endif
896 inline bool MissingConvention::isRewriteNeeded( OpCode eOp ) const
898 switch (eOp)
900 case ocGammaDist:
901 case ocPoissonDist:
902 case ocAddress:
903 case ocLogNormDist:
904 case ocNormDist:
905 return true;
906 case ocMissing:
907 case ocLog:
908 return !isODFF(); // rewrite only for PODF
909 default:
910 return false;
914 class FormulaMissingContext
916 public:
917 const FormulaToken* mpFunc;
918 int mnCurArg;
920 void Clear() { mpFunc = NULL; mnCurArg = 0; }
921 inline bool AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const;
922 bool AddMissingExternal( FormulaTokenArray* pNewArr ) const;
923 bool AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
924 void AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
927 void FormulaMissingContext::AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
929 if ( !mpFunc )
930 return;
932 switch (mpFunc->GetOpCode())
934 case ocGammaDist:
935 if (mnCurArg == 2)
937 pNewArr->AddOpCode( ocSep );
938 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=TRUE()
940 break;
941 case ocPoissonDist:
942 if (mnCurArg == 1)
944 pNewArr->AddOpCode( ocSep );
945 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=TRUE()
947 break;
948 case ocNormDist:
949 if ( mnCurArg == 2 )
951 pNewArr->AddOpCode( ocSep );
952 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=TRUE()
954 break;
955 case ocLogNormDist:
956 if ( mnCurArg == 0 )
958 pNewArr->AddOpCode( ocSep );
959 pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0
961 if ( mnCurArg <= 1 )
963 pNewArr->AddOpCode( ocSep );
964 pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
966 break;
967 case ocLog:
968 if ( !rConv.isODFF() && mnCurArg == 0 )
970 pNewArr->AddOpCode( ocSep );
971 pNewArr->AddDouble( 10.0 ); // 2nd, basis 10
973 break;
974 default:
975 break;
979 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const
981 if (mnCurArg == nArg)
983 pNewArr->AddDouble( f );
984 return true;
986 return false;
989 bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray *pNewArr ) const
991 // Only called for PODF, not ODFF. No need to distinguish.
993 const String &rName = mpFunc->GetExternal();
995 // initial (fast) check:
996 sal_Unicode nLastChar = rName.GetChar( rName.Len() - 1);
997 if ( nLastChar != 't' && nLastChar != 'm' )
998 return false;
1000 if (rName.EqualsIgnoreCaseAscii(
1001 "com.sun.star.sheet.addin.Analysis.getAccrint" ))
1003 return AddDefaultArg( pNewArr, 4, 1000.0 );
1005 if (rName.EqualsIgnoreCaseAscii(
1006 "com.sun.star.sheet.addin.Analysis.getAccrintm" ))
1008 return AddDefaultArg( pNewArr, 3, 1000.0 );
1010 return false;
1013 bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
1015 if ( !mpFunc )
1016 return false;
1018 bool bRet = false;
1019 const OpCode eOp = mpFunc->GetOpCode();
1021 // Add for both, PODF and ODFF
1022 switch (eOp)
1024 case ocAddress:
1025 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1026 default:
1027 break;
1030 if (rConv.isODFF())
1032 // Add for ODFF
1034 else
1036 // Add for PODF
1037 switch (eOp)
1039 case ocFixed:
1040 return AddDefaultArg( pNewArr, 1, 2.0 );
1041 case ocBetaDist:
1042 case ocBetaInv:
1043 case ocRMZ: // PMT
1044 return AddDefaultArg( pNewArr, 3, 0.0 );
1045 case ocZinsZ: // IPMT
1046 case ocKapz: // PPMT
1047 return AddDefaultArg( pNewArr, 4, 0.0 );
1048 case ocBW: // PV
1049 case ocZW: // FV
1050 bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt
1051 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v
1052 break;
1053 case ocZins: // RATE
1054 bRet |= AddDefaultArg( pNewArr, 1, 0.0 ); // pmt
1055 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // fv
1056 bRet |= AddDefaultArg( pNewArr, 4, 0.0 ); // type
1057 break;
1058 case ocExternal:
1059 return AddMissingExternal( pNewArr );
1061 // --- more complex cases ---
1063 case ocOffset:
1064 // FIXME: rather tough.
1065 // if arg 3 (height) ommitted, export arg1 (rows)
1066 break;
1067 default:
1068 break;
1072 return bRet;
1075 bool FormulaTokenArray::NeedsPofRewrite( const MissingConvention & rConv )
1077 for ( FormulaToken *pCur = First(); pCur; pCur = Next() )
1079 if ( rConv.isRewriteNeeded( pCur->GetOpCode()))
1080 return true;
1082 return false;
1086 FormulaTokenArray * FormulaTokenArray::RewriteMissingToPof( const MissingConvention & rConv )
1088 const size_t nAlloc = 256;
1089 FormulaMissingContext aCtx[ nAlloc ];
1090 int aOpCodeAddressStack[ nAlloc ]; // use of ADDRESS() function
1091 const int nOmitAddressArg = 3; // ADDRESS() 4th parameter A1/R1C1
1092 USHORT nTokens = GetLen() + 1;
1093 FormulaMissingContext* pCtx = (nAlloc < nTokens ? new FormulaMissingContext[nTokens] : &aCtx[0]);
1094 int* pOcas = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeAddressStack[0]);
1095 // Never go below 0, never use 0, mpFunc always NULL.
1096 pCtx[0].Clear();
1097 int nFn = 0;
1098 int nOcas = 0;
1100 FormulaTokenArray *pNewArr = new FormulaTokenArray;
1101 // At least RECALCMODE_ALWAYS needs to be set.
1102 pNewArr->AddRecalcMode( GetRecalcMode());
1104 for ( FormulaToken *pCur = First(); pCur; pCur = Next() )
1106 bool bAdd = true;
1107 // Don't write the expression of the new inserted ADDRESS() parameter.
1108 // Do NOT omit the new second parameter of INDIRECT() though. If that
1109 // was done for both, INDIRECT() actually could calculate different and
1110 // valid (but wrong) results with the then changed return value of
1111 // ADDRESS(). Better let it generate an error instead.
1112 for (int i = nOcas; i-- > 0 && bAdd; )
1114 if (pCtx[ pOcas[ i ] ].mnCurArg == nOmitAddressArg)
1116 // Omit erverything except a trailing separator, the leading
1117 // separator is omitted below. The other way around would leave
1118 // an extraneous separator if no parameter followed.
1119 if (!(pOcas[ i ] == nFn && pCur->GetOpCode() == ocSep))
1120 bAdd = false;
1122 //fprintf( stderr, "ocAddress %d arg %d%s\n", (int)i, (int)pCtx[ pOcas[ i ] ].mnCurArg, (bAdd ? "" : " omitted"));
1124 switch ( pCur->GetOpCode() )
1126 case ocOpen:
1127 ++nFn; // all following operations on _that_ function
1128 pCtx[ nFn ].mpFunc = PeekPrevNoSpaces();
1129 pCtx[ nFn ].mnCurArg = 0;
1130 if (pCtx[ nFn ].mpFunc && pCtx[ nFn ].mpFunc->GetOpCode() == ocAddress && !rConv.isODFF())
1131 pOcas[ nOcas++ ] = nFn; // entering ADDRESS() if PODF
1132 break;
1133 case ocClose:
1134 pCtx[ nFn ].AddMoreArgs( pNewArr, rConv );
1135 DBG_ASSERT( nFn > 0, "FormulaTokenArray::RewriteMissingToPof: underflow");
1136 if (nOcas > 0 && pOcas[ nOcas-1 ] == nFn)
1137 --nOcas; // leaving ADDRESS()
1138 if (nFn > 0)
1139 --nFn;
1140 break;
1141 case ocSep:
1142 pCtx[ nFn ].mnCurArg++;
1143 // Omit leading separator of ADDRESS() parameter.
1144 if (nOcas && pOcas[ nOcas-1 ] == nFn && pCtx[ nFn ].mnCurArg == nOmitAddressArg)
1146 bAdd = false;
1147 //fprintf( stderr, "ocAddress %d sep %d omitted\n", (int)nOcas-1, nOmitAddressArg);
1149 break;
1150 case ocMissing:
1151 if (bAdd)
1152 bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv );
1153 break;
1154 default:
1155 break;
1157 if (bAdd)
1158 pNewArr->AddToken( *pCur );
1161 if (pOcas != &aOpCodeAddressStack[0])
1162 delete [] pOcas;
1163 if (pCtx != &aCtx[0])
1164 delete [] pCtx;
1166 return pNewArr;
1169 bool FormulaTokenArray::MayReferenceFollow()
1171 if ( pCode && nLen > 0 )
1173 // ignore trailing spaces
1174 USHORT i = nLen - 1;
1175 while ( i > 0 && pCode[i]->GetOpCode() == SC_OPCODE_SPACES )
1177 --i;
1179 if ( i > 0 || pCode[i]->GetOpCode() != SC_OPCODE_SPACES )
1181 OpCode eOp = pCode[i]->GetOpCode();
1182 if ( (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP ) ||
1183 (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP ) ||
1184 eOp == SC_OPCODE_OPEN || eOp == SC_OPCODE_SEP )
1186 return true;
1190 return false;
1192 FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp )
1194 FormulaToken* pRet = NULL;
1195 switch ( eOp )
1197 case ocOpen:
1198 case ocClose:
1199 case ocSep:
1200 case ocArrayOpen:
1201 case ocArrayClose:
1202 case ocArrayRowSep:
1203 case ocArrayColSep:
1204 pRet = new FormulaToken( svSep,eOp );
1205 break;
1206 case ocIf:
1207 case ocChose:
1209 short nJump[MAXJUMPCOUNT + 1];
1210 nJump[ 0 ] = ocIf == eOp ? 3 : MAXJUMPCOUNT+1;
1211 pRet = new FormulaJumpToken( eOp, (short*)nJump );
1213 break;
1214 default:
1215 pRet = new FormulaByteToken( eOp, 0, FALSE );
1216 break;
1218 return AddToken( *pRet );
1222 /*----------------------------------------------------------------------*/
1224 FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray& rArr )
1226 pCur = NULL;
1227 Push( &rArr );
1230 FormulaTokenIterator::~FormulaTokenIterator()
1232 while( pCur )
1233 Pop();
1236 void FormulaTokenIterator::Push( const FormulaTokenArray* pArr )
1238 ImpTokenIterator* p = new ImpTokenIterator;
1239 p->pArr = pArr;
1240 p->nPC = -1;
1241 p->nStop = SHRT_MAX;
1242 p->pNext = pCur;
1243 pCur = p;
1246 void FormulaTokenIterator::Pop()
1248 ImpTokenIterator* p = pCur;
1249 if( p )
1251 pCur = p->pNext;
1252 delete p;
1256 void FormulaTokenIterator::Reset()
1258 while( pCur->pNext )
1259 Pop();
1260 pCur->nPC = -1;
1263 const FormulaToken* FormulaTokenIterator::First()
1265 Reset();
1266 return Next();
1269 const FormulaToken* FormulaTokenIterator::Next()
1271 const FormulaToken* t = NULL;
1272 ++pCur->nPC;
1273 if( pCur->nPC < pCur->pArr->nRPN && pCur->nPC < pCur->nStop )
1275 t = pCur->pArr->pRPN[ pCur->nPC ];
1276 // such an OpCode ends an IF() or CHOOSE() path
1277 if( t->GetOpCode() == ocSep || t->GetOpCode() == ocClose )
1278 t = NULL;
1280 if( !t && pCur->pNext )
1282 Pop();
1283 t = Next();
1285 return t;
1288 //! The nPC counts after a Push() are -1
1290 void FormulaTokenIterator::Jump( short nStart, short nNext, short nStop )
1292 pCur->nPC = nNext;
1293 if( nStart != nNext )
1295 Push( pCur->pArr );
1296 pCur->nPC = nStart;
1297 pCur->nStop = nStop;
1301 bool FormulaTokenIterator::IsEndOfPath() const
1303 USHORT nTest = pCur->nPC + 1;
1304 if( nTest < pCur->pArr->nRPN && nTest < pCur->nStop )
1306 const FormulaToken* t = pCur->pArr->pRPN[ nTest ];
1307 // such an OpCode ends an IF() or CHOOSE() path
1308 return t->GetOpCode() == ocSep || t->GetOpCode() == ocClose;
1310 return true;
1312 // -----------------------------------------------------------------------------
1313 // ==========================================================================
1314 // real implementations of virtual functions
1315 // --------------------------------------------------------------------------
1317 double FormulaDoubleToken::GetDouble() const { return fDouble; }
1318 double & FormulaDoubleToken::GetDoubleAsReference() { return fDouble; }
1319 BOOL FormulaDoubleToken::operator==( const FormulaToken& r ) const
1321 return FormulaToken::operator==( r ) && fDouble == r.GetDouble();
1325 const String& FormulaStringToken::GetString() const { return aString; }
1326 BOOL FormulaStringToken::operator==( const FormulaToken& r ) const
1328 return FormulaToken::operator==( r ) && aString == r.GetString();
1332 const String& FormulaStringOpToken::GetString() const { return aString; }
1333 BOOL FormulaStringOpToken::operator==( const FormulaToken& r ) const
1335 return FormulaByteToken::operator==( r ) && aString == r.GetString();
1338 USHORT FormulaIndexToken::GetIndex() const { return nIndex; }
1339 void FormulaIndexToken::SetIndex( USHORT n ) { nIndex = n; }
1340 BOOL FormulaIndexToken::operator==( const FormulaToken& r ) const
1342 return FormulaToken::operator==( r ) && nIndex == r.GetIndex();
1344 const String& FormulaExternalToken::GetExternal() const { return aExternal; }
1345 BYTE FormulaExternalToken::GetByte() const { return nByte; }
1346 void FormulaExternalToken::SetByte( BYTE n ) { nByte = n; }
1347 BOOL FormulaExternalToken::operator==( const FormulaToken& r ) const
1349 return FormulaToken::operator==( r ) && nByte == r.GetByte() &&
1350 aExternal == r.GetExternal();
1354 USHORT FormulaErrorToken::GetError() const { return nError; }
1355 void FormulaErrorToken::SetError( USHORT nErr ) { nError = nErr; }
1356 BOOL FormulaErrorToken::operator==( const FormulaToken& r ) const
1358 return FormulaToken::operator==( r ) &&
1359 nError == static_cast< const FormulaErrorToken & >(r).GetError();
1361 double FormulaMissingToken::GetDouble() const { return 0.0; }
1362 const String& FormulaMissingToken::GetString() const
1364 static String aDummyString;
1365 return aDummyString;
1367 BOOL FormulaMissingToken::operator==( const FormulaToken& r ) const
1369 return FormulaToken::operator==( r );
1373 BOOL FormulaUnknownToken::operator==( const FormulaToken& r ) const
1375 return FormulaToken::operator==( r );
1378 // -----------------------------------------------------------------------------
1379 } // formula
1380 // -----------------------------------------------------------------------------