update dev300-m58
[ooovba.git] / formula / source / core / api / token.cxx
blob7262388bc5b0376b707755a3c252df0698bbad6f
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 return true;
904 case ocMissing:
905 case ocLog:
906 return !isODFF(); // rewrite only for PODF
907 default:
908 return false;
912 class FormulaMissingContext
914 public:
915 const FormulaToken* mpFunc;
916 int mnCurArg;
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
927 if ( !mpFunc )
928 return;
930 switch (mpFunc->GetOpCode())
932 case ocGammaDist:
933 if (mnCurArg == 2)
935 pNewArr->AddOpCode( ocSep );
936 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=TRUE()
938 break;
939 case ocPoissonDist:
940 if (mnCurArg == 1)
942 pNewArr->AddOpCode( ocSep );
943 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=TRUE()
945 break;
946 case ocLog:
947 if ( !rConv.isODFF() && mnCurArg == 0 )
949 pNewArr->AddOpCode( ocSep );
950 pNewArr->AddDouble( 10.0 ); // 2nd, basis 10
952 break;
953 default:
954 break;
958 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const
960 if (mnCurArg == nArg)
962 pNewArr->AddDouble( f );
963 return true;
965 return false;
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' )
977 return false;
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 );
989 return false;
992 bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
994 if ( !mpFunc )
995 return false;
997 bool bRet = false;
998 const OpCode eOp = mpFunc->GetOpCode();
1000 // Add for both, PODF and ODFF
1001 switch (eOp)
1003 case ocAddress:
1004 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1005 default:
1006 break;
1009 if (rConv.isODFF())
1011 // Add for ODFF
1013 else
1015 // Add for PODF
1016 switch (eOp)
1018 case ocFixed:
1019 return AddDefaultArg( pNewArr, 1, 2.0 );
1020 case ocBetaDist:
1021 case ocBetaInv:
1022 case ocRMZ: // PMT
1023 return AddDefaultArg( pNewArr, 3, 0.0 );
1024 case ocZinsZ: // IPMT
1025 case ocKapz: // PPMT
1026 return AddDefaultArg( pNewArr, 4, 0.0 );
1027 case ocBW: // PV
1028 case ocZW: // FV
1029 bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt
1030 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v
1031 break;
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
1036 break;
1037 case ocExternal:
1038 return AddMissingExternal( pNewArr );
1040 // --- more complex cases ---
1042 case ocOffset:
1043 // FIXME: rather tough.
1044 // if arg 3 (height) ommitted, export arg1 (rows)
1045 break;
1046 default:
1047 break;
1051 return bRet;
1054 bool FormulaTokenArray::NeedsPofRewrite( const MissingConvention & rConv )
1056 for ( FormulaToken *pCur = First(); pCur; pCur = Next() )
1058 if ( rConv.isRewriteNeeded( pCur->GetOpCode()))
1059 return true;
1061 return false;
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.
1075 pCtx[0].Clear();
1076 int nFn = 0;
1077 int nOcas = 0;
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() )
1085 bool bAdd = true;
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))
1099 bAdd = false;
1101 //fprintf( stderr, "ocAddress %d arg %d%s\n", (int)i, (int)pCtx[ pOcas[ i ] ].mnCurArg, (bAdd ? "" : " omitted"));
1103 switch ( pCur->GetOpCode() )
1105 case ocOpen:
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
1111 break;
1112 case ocClose:
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()
1117 if (nFn > 0)
1118 --nFn;
1119 break;
1120 case ocSep:
1121 pCtx[ nFn ].mnCurArg++;
1122 // Omit leading separator of ADDRESS() parameter.
1123 if (nOcas && pOcas[ nOcas-1 ] == nFn && pCtx[ nFn ].mnCurArg == nOmitAddressArg)
1125 bAdd = false;
1126 //fprintf( stderr, "ocAddress %d sep %d omitted\n", (int)nOcas-1, nOmitAddressArg);
1128 break;
1129 case ocMissing:
1130 if (bAdd)
1131 bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv );
1132 break;
1133 default:
1134 break;
1136 if (bAdd)
1137 pNewArr->AddToken( *pCur );
1140 if (pOcas != &aOpCodeAddressStack[0])
1141 delete [] pOcas;
1142 if (pCtx != &aCtx[0])
1143 delete [] pCtx;
1145 return pNewArr;
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 )
1156 --i;
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 )
1165 return true;
1169 return false;
1171 FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp )
1173 FormulaToken* pRet = NULL;
1174 switch ( eOp )
1176 case ocOpen:
1177 case ocClose:
1178 case ocSep:
1179 case ocArrayOpen:
1180 case ocArrayClose:
1181 case ocArrayRowSep:
1182 case ocArrayColSep:
1183 pRet = new FormulaToken( svSep,eOp );
1184 break;
1185 case ocIf:
1186 case ocChose:
1188 short nJump[MAXJUMPCOUNT + 1];
1189 nJump[ 0 ] = ocIf == eOp ? 3 : MAXJUMPCOUNT+1;
1190 pRet = new FormulaJumpToken( eOp, (short*)nJump );
1192 break;
1193 default:
1194 pRet = new FormulaByteToken( eOp, 0, FALSE );
1195 break;
1197 return AddToken( *pRet );
1201 /*----------------------------------------------------------------------*/
1203 FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray& rArr )
1205 pCur = NULL;
1206 Push( &rArr );
1209 FormulaTokenIterator::~FormulaTokenIterator()
1211 while( pCur )
1212 Pop();
1215 void FormulaTokenIterator::Push( const FormulaTokenArray* pArr )
1217 ImpTokenIterator* p = new ImpTokenIterator;
1218 p->pArr = pArr;
1219 p->nPC = -1;
1220 p->nStop = SHRT_MAX;
1221 p->pNext = pCur;
1222 pCur = p;
1225 void FormulaTokenIterator::Pop()
1227 ImpTokenIterator* p = pCur;
1228 if( p )
1230 pCur = p->pNext;
1231 delete p;
1235 void FormulaTokenIterator::Reset()
1237 while( pCur->pNext )
1238 Pop();
1239 pCur->nPC = -1;
1242 const FormulaToken* FormulaTokenIterator::First()
1244 Reset();
1245 return Next();
1248 const FormulaToken* FormulaTokenIterator::Next()
1250 const FormulaToken* t = NULL;
1251 ++pCur->nPC;
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 )
1257 t = NULL;
1259 if( !t && pCur->pNext )
1261 Pop();
1262 t = Next();
1264 return t;
1267 //! The nPC counts after a Push() are -1
1269 void FormulaTokenIterator::Jump( short nStart, short nNext, short nStop )
1271 pCur->nPC = nNext;
1272 if( nStart != nNext )
1274 Push( pCur->pArr );
1275 pCur->nPC = nStart;
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;
1289 return true;
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 // -----------------------------------------------------------------------------
1358 } // formula
1359 // -----------------------------------------------------------------------------