xref: /aoo41x/main/formula/source/core/api/token.cxx (revision 7aaaedba)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_formula.hxx"
30 
31 
32 
33 // INCLUDE ---------------------------------------------------------------
34 
35 #if STLPORT_VERSION<321
36 #include <stddef.h>
37 #else
38 #include <cstddef>
39 #endif
40 #include <cstdio>
41 
42 #include <string.h>
43 #include <limits.h>
44 #include <tools/debug.hxx>
45 
46 #include "formula/token.hxx"
47 #include "formula/tokenarray.hxx"
48 #include "formula/FormulaCompiler.hxx"
49 #include <formula/compiler.hrc>
50 //#include "rechead.hxx"
51 //#include "parclass.hxx"
52 //#include "jumpmatrix.hxx"
53 #define MAXJUMPCOUNT 32     /* maximum number of jumps (ocChose) */
54 
55 namespace formula
56 {
57     using namespace com::sun::star;
58 // ImpTokenIterator wird je Interpreter angelegt, mehrfache auch durch
59 // SubCode via FormulaTokenIterator Push/Pop moeglich
60 IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator, 32, 16 )
61 
62 // Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2)
63 
64 // Need a lot of FormulaDoubleToken
65 const sal_uInt16 nMemPoolDoubleToken = (0x3000 - 64) / sizeof(FormulaDoubleToken);
66 IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaDoubleToken, nMemPoolDoubleToken, nMemPoolDoubleToken )
67 // Need a lot of FormulaByteToken
68 const sal_uInt16 nMemPoolByteToken = (0x3000 - 64) / sizeof(FormulaByteToken);
69 IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaByteToken, nMemPoolByteToken, nMemPoolByteToken )
70 // Need several FormulaStringToken
71 const sal_uInt16 nMemPoolStringToken = (0x1000 - 64) / sizeof(FormulaStringToken);
72 IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaStringToken, nMemPoolStringToken, nMemPoolStringToken )
73 
74 
75 // --- helpers --------------------------------------------------------------
76 
77 inline sal_Bool lcl_IsReference( OpCode eOp, StackVar eType )
78 {
79     return
80         (eOp == ocPush && (eType == svSingleRef || eType == svDoubleRef))
81         || (eOp == ocColRowNameAuto && eType == svDoubleRef)
82         || (eOp == ocColRowName && eType == svSingleRef)
83         || (eOp == ocMatRef && eType == svSingleRef)
84         ;
85 }
86 
87 // --- class FormulaToken --------------------------------------------------------
88 FormulaToken::~FormulaToken()
89 {
90 }
91 
92 sal_Bool FormulaToken::Is3DRef() const
93 {
94     return sal_False;
95 }
96 
97 sal_Bool FormulaToken::IsFunction() const
98 {
99 //    OpCode eOp = GetOpCode();
100     return (eOp != ocPush && eOp != ocBad && eOp != ocColRowName &&
101             eOp != ocColRowNameAuto && eOp != ocName && eOp != ocDBArea &&
102            (GetByte() != 0                                                  // x parameters
103         || (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)   // no parameter
104         || (ocIf == eOp ||  ocChose ==  eOp     )                           // @ jump commands
105         || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR)     // one parameter
106         || (SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)     // x parameters (cByte==0 in
107                                                                             // FuncAutoPilot)
108         || eOp == ocMacro || eOp == ocExternal                  // macros, AddIns
109         || eOp == ocAnd || eOp == ocOr                          // former binary, now x parameters
110         || eOp == ocNot || eOp == ocNeg                         // unary but function
111         || (eOp >= ocInternalBegin && eOp <= ocInternalEnd)     // internal
112         ));
113 }
114 
115 
116 sal_uInt8 FormulaToken::GetParamCount() const
117 {
118     // OpCode eOp = GetOpCode();
119     if ( eOp < SC_OPCODE_STOP_DIV && eOp != ocExternal && eOp != ocMacro &&
120             eOp != ocIf && eOp != ocChose && eOp != ocPercentSign )
121         return 0;       // parameters and specials
122                         // ocIf and ocChose not for FAP, have cByte then
123 //2do: sal_Bool parameter whether FAP or not?
124     else if ( GetByte() )
125         return GetByte();   // all functions, also ocExternal and ocMacro
126     else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP)
127         return 2;           // binary
128     else if ((SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)
129             || eOp == ocPercentSign)
130         return 1;           // unary
131     else if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
132         return 0;           // no parameter
133     else if (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR)
134         return 1;           // one parameter
135     else if ( eOp == ocIf || eOp == ocChose )
136         return 1;           // only the condition counts as parameter
137     else
138         return 0;           // all the rest, no Parameter, or
139                             // if so then it should be in cByte
140 }
141 
142 
143 sal_Bool FormulaToken::IsMatrixFunction() const
144 {
145     return formula::FormulaCompiler::IsMatrixFunction(GetOpCode());
146 }
147 
148 sal_Bool FormulaToken::operator==( const FormulaToken& rToken ) const
149 {
150     // don't compare reference count!
151     return  eType == rToken.eType && GetOpCode() == rToken.GetOpCode();
152 }
153 
154 
155 // --- virtual dummy methods -------------------------------------------------
156 
157 sal_uInt8 FormulaToken::GetByte() const
158 {
159     // ok to be called for any derived class
160     return 0;
161 }
162 
163 void FormulaToken::SetByte( sal_uInt8 )
164 {
165     DBG_ERRORFILE( "FormulaToken::SetByte: virtual dummy called" );
166 }
167 
168 bool FormulaToken::HasForceArray() const
169 {
170     // ok to be called for any derived class
171     return false;
172 }
173 
174 void FormulaToken::SetForceArray( bool )
175 {
176     DBG_ERRORFILE( "FormulaToken::SetForceArray: virtual dummy called" );
177 }
178 
179 double FormulaToken::GetDouble() const
180 {
181     DBG_ERRORFILE( "FormulaToken::GetDouble: virtual dummy called" );
182     return 0.0;
183 }
184 
185 double & FormulaToken::GetDoubleAsReference()
186 {
187     DBG_ERRORFILE( "FormulaToken::GetDouble: virtual dummy called" );
188     static double fVal = 0.0;
189     return fVal;
190 }
191 
192 const String& FormulaToken::GetString() const
193 {
194     DBG_ERRORFILE( "FormulaToken::GetString: virtual dummy called" );
195     static  String              aDummyString;
196     return aDummyString;
197 }
198 
199 sal_uInt16 FormulaToken::GetIndex() const
200 {
201     DBG_ERRORFILE( "FormulaToken::GetIndex: virtual dummy called" );
202     return 0;
203 }
204 
205 void FormulaToken::SetIndex( sal_uInt16 )
206 {
207     DBG_ERRORFILE( "FormulaToken::SetIndex: virtual dummy called" );
208 }
209 
210 short* FormulaToken::GetJump() const
211 {
212     DBG_ERRORFILE( "FormulaToken::GetJump: virtual dummy called" );
213     return NULL;
214 }
215 
216 
217 const String& FormulaToken::GetExternal() const
218 {
219     DBG_ERRORFILE( "FormulaToken::GetExternal: virtual dummy called" );
220     static  String              aDummyString;
221     return aDummyString;
222 }
223 
224 FormulaToken* FormulaToken::GetFAPOrigToken() const
225 {
226     DBG_ERRORFILE( "FormulaToken::GetFAPOrigToken: virtual dummy called" );
227     return NULL;
228 }
229 
230 sal_uInt16 FormulaToken::GetError() const
231 {
232     DBG_ERRORFILE( "FormulaToken::GetError: virtual dummy called" );
233     return 0;
234 }
235 
236 void FormulaToken::SetError( sal_uInt16 )
237 {
238     DBG_ERRORFILE( "FormulaToken::SetError: virtual dummy called" );
239 }
240 sal_Bool FormulaToken::TextEqual( const FormulaToken& rToken ) const
241 {
242     return *this == rToken;
243 }
244 // ==========================================================================
245 // real implementations of virtual functions
246 // --------------------------------------------------------------------------
247 
248 
249 sal_uInt8 FormulaByteToken::GetByte() const                       { return nByte; }
250 void FormulaByteToken::SetByte( sal_uInt8 n )                     { nByte = n; }
251 bool FormulaByteToken::HasForceArray() const                 { return bHasForceArray; }
252 void FormulaByteToken::SetForceArray( bool b )               { bHasForceArray = b; }
253 sal_Bool FormulaByteToken::operator==( const FormulaToken& r ) const
254 {
255     return FormulaToken::operator==( r ) && nByte == r.GetByte() &&
256         bHasForceArray == r.HasForceArray();
257 }
258 
259 
260 FormulaToken* FormulaFAPToken::GetFAPOrigToken() const            { return pOrigToken; }
261 sal_Bool FormulaFAPToken::operator==( const FormulaToken& r ) const
262 {
263     return FormulaByteToken::operator==( r ) && pOrigToken == r.GetFAPOrigToken();
264 }
265 short* FormulaJumpToken::GetJump() const                     { return pJump; }
266 sal_Bool FormulaJumpToken::operator==( const FormulaToken& r ) const
267 {
268     return FormulaToken::operator==( r ) && pJump[0] == r.GetJump()[0] &&
269         memcmp( pJump+1, r.GetJump()+1, pJump[0] * sizeof(short) ) == 0;
270 }
271 FormulaJumpToken::~FormulaJumpToken()
272 {
273     delete [] pJump;
274 }
275 
276 
277 bool FormulaTokenArray::AddFormulaToken(const sheet::FormulaToken& _aToken,ExternalReferenceHelper* /*_pRef*/)
278 {
279     bool bError = false;
280     const OpCode eOpCode = static_cast<OpCode>(_aToken.OpCode);      //! assuming equal values for the moment
281 
282     const uno::TypeClass eClass = _aToken.Data.getValueTypeClass();
283     switch ( eClass )
284     {
285         case uno::TypeClass_VOID:
286             // empty data -> use AddOpCode (does some special cases)
287             AddOpCode( eOpCode );
288             break;
289         case uno::TypeClass_DOUBLE:
290             // double is only used for "push"
291             if ( eOpCode == ocPush )
292                 AddDouble( _aToken.Data.get<double>() );
293             else
294                 bError = true;
295             break;
296         case uno::TypeClass_LONG:
297             {
298                 // long is svIndex, used for name / database area, or "byte" for spaces
299                 sal_Int32 nValue = _aToken.Data.get<sal_Int32>();
300                 if ( eOpCode == ocName || eOpCode == ocDBArea )
301                     AddToken( formula::FormulaIndexToken( eOpCode, static_cast<sal_uInt16>(nValue) ) );
302                 else if ( eOpCode == ocSpaces )
303                     AddToken( formula::FormulaByteToken( ocSpaces, static_cast<sal_uInt8>(nValue) ) );
304                 else
305                     bError = true;
306             }
307             break;
308         case uno::TypeClass_STRING:
309             {
310                 String aStrVal( _aToken.Data.get<rtl::OUString>() );
311                 if ( eOpCode == ocPush )
312                     AddString( aStrVal );
313                 else if ( eOpCode == ocBad )
314                     AddBad( aStrVal );
315                 else if ( eOpCode == ocExternal || eOpCode == ocMacro )
316                     AddToken( formula::FormulaExternalToken( eOpCode, aStrVal ) );
317                 else
318                     bError = true;      // unexpected string: don't know what to do with it
319             }
320             break;
321         default:
322             bError = true;
323     } // switch ( eClass )
324     return bError;
325 }
326 bool FormulaTokenArray::Fill(const uno::Sequence< sheet::FormulaToken >& _aSequence,ExternalReferenceHelper* _pRef)
327 {
328     bool bError = false;
329     const sal_Int32 nCount = _aSequence.getLength();
330     for (sal_Int32 nPos=0; nPos<nCount; nPos++)
331     {
332         bError |= AddFormulaToken( _aSequence[nPos] ,_pRef);
333     }
334     return bError;
335 }
336 //////////////////////////////////////////////////////////////////////////
337 FormulaToken* FormulaTokenArray::GetNextReference()
338 {
339     while( nIndex < nLen )
340     {
341         FormulaToken* t = pCode[ nIndex++ ];
342         switch( t->GetType() )
343         {
344             case svSingleRef:
345             case svDoubleRef:
346             case svExternalSingleRef:
347             case svExternalDoubleRef:
348                 return t;
349             default:
350             {
351                 // added to avoid warnings
352             }
353         }
354     }
355     return NULL;
356 }
357 
358 FormulaToken* FormulaTokenArray::GetNextColRowName()
359 {
360     while( nIndex < nLen )
361     {
362         FormulaToken* t = pCode[ nIndex++ ];
363         if ( t->GetOpCode() == ocColRowName )
364             return t;
365     }
366     return NULL;
367 }
368 
369 FormulaToken* FormulaTokenArray::GetNextReferenceRPN()
370 {
371     while( nIndex < nRPN )
372     {
373         FormulaToken* t = pRPN[ nIndex++ ];
374         switch( t->GetType() )
375         {
376             case svSingleRef:
377             case svDoubleRef:
378             case svExternalSingleRef:
379             case svExternalDoubleRef:
380                 return t;
381             default:
382             {
383                 // added to avoid warnings
384             }
385         }
386     }
387     return NULL;
388 }
389 
390 FormulaToken* FormulaTokenArray::GetNextReferenceOrName()
391 {
392     if( pCode )
393     {
394         while ( nIndex < nLen )
395         {
396             FormulaToken* t = pCode[ nIndex++ ];
397             switch( t->GetType() )
398             {
399                 case svSingleRef:
400                 case svDoubleRef:
401                 case svIndex:
402             	case svExternalSingleRef:
403 	            case svExternalDoubleRef:
404     	        case svExternalName:
405                     return t;
406                 default:
407                 {
408                     // added to avoid warnings
409                 }
410              }
411          }
412      }
413     return NULL;
414 }
415 
416 FormulaToken* FormulaTokenArray::GetNextName()
417 {
418     if( pCode )
419     {
420         while ( nIndex < nLen )
421         {
422             FormulaToken* t = pCode[ nIndex++ ];
423             if( t->GetType() == svIndex )
424                 return t;
425         }
426     } // if( pCode )
427     return NULL;
428 }
429 
430 FormulaToken* FormulaTokenArray::GetNextDBArea()
431 {
432     if( pCode )
433     {
434         while ( nIndex < nLen )
435         {
436             FormulaToken* t = pCode[ nIndex++ ];
437             if( t->GetOpCode() == ocDBArea )
438                 return t;
439         } // while ( nIndex < nLen )+
440     }
441     return NULL;
442 }
443 
444 FormulaToken* FormulaTokenArray::GetNextOpCodeRPN( OpCode eOp )
445 {
446     while( nIndex < nRPN )
447     {
448         FormulaToken* t = pRPN[ nIndex++ ];
449         if ( t->GetOpCode() == eOp )
450             return t;
451     }
452     return NULL;
453 }
454 
455 FormulaToken* FormulaTokenArray::Next()
456 {
457     if( pCode && nIndex < nLen )
458         return pCode[ nIndex++ ];
459     else
460         return NULL;
461 }
462 
463 FormulaToken* FormulaTokenArray::NextNoSpaces()
464 {
465     if( pCode )
466     {
467         while( (nIndex < nLen) && (pCode[ nIndex ]->GetOpCode() == ocSpaces) )
468             ++nIndex;
469         if( nIndex < nLen )
470             return pCode[ nIndex++ ];
471     }
472     return NULL;
473 }
474 
475 FormulaToken* FormulaTokenArray::NextRPN()
476 {
477     if( pRPN && nIndex < nRPN )
478         return pRPN[ nIndex++ ];
479     else
480         return NULL;
481 }
482 
483 FormulaToken* FormulaTokenArray::PrevRPN()
484 {
485     if( pRPN && nIndex )
486         return pRPN[ --nIndex ];
487     else
488         return NULL;
489 }
490 
491 void FormulaTokenArray::DelRPN()
492 {
493     if( nRPN )
494     {
495         FormulaToken** p = pRPN;
496         for( sal_uInt16 i = 0; i < nRPN; i++ )
497         {
498             (*p++)->DecRef();
499         }
500         delete [] pRPN;
501     }
502     pRPN = NULL;
503     nRPN = nIndex = 0;
504 }
505 
506 FormulaToken* FormulaTokenArray::PeekPrev( sal_uInt16 & nIdx )
507 {
508     if (0 < nIdx && nIdx <= nLen)
509         return pCode[--nIdx];
510     return NULL;
511 }
512 
513 FormulaToken* FormulaTokenArray::PeekNext()
514 {
515     if( pCode && nIndex < nLen )
516         return pCode[ nIndex ];
517     else
518         return NULL;
519 }
520 
521 FormulaToken* FormulaTokenArray::PeekNextNoSpaces()
522 {
523     if( pCode && nIndex < nLen )
524     {
525         sal_uInt16 j = nIndex;
526         while ( pCode[j]->GetOpCode() == ocSpaces && j < nLen )
527             j++;
528         if ( j < nLen )
529             return pCode[ j ];
530         else
531             return NULL;
532     }
533     else
534         return NULL;
535 }
536 
537 FormulaToken* FormulaTokenArray::PeekPrevNoSpaces()
538 {
539     if( pCode && nIndex > 1 )
540     {
541         sal_uInt16 j = nIndex - 2;
542         while ( pCode[j]->GetOpCode() == ocSpaces && j > 0 )
543             j--;
544         if ( j > 0 || pCode[j]->GetOpCode() != ocSpaces )
545             return pCode[ j ];
546         else
547             return NULL;
548     }
549     else
550         return NULL;
551 }
552 
553 sal_Bool FormulaTokenArray::HasOpCode( OpCode eOp ) const
554 {
555     for ( sal_uInt16 j=0; j < nLen; j++ )
556     {
557         if ( pCode[j]->GetOpCode() == eOp )
558             return sal_True;
559     }
560     return sal_False;
561 }
562 
563 sal_Bool FormulaTokenArray::HasOpCodeRPN( OpCode eOp ) const
564 {
565     for ( sal_uInt16 j=0; j < nRPN; j++ )
566     {
567         if ( pRPN[j]->GetOpCode() == eOp )
568             return sal_True;
569     }
570     return sal_False;
571 }
572 
573 sal_Bool FormulaTokenArray::HasNameOrColRowName() const
574 {
575     for ( sal_uInt16 j=0; j < nLen; j++ )
576     {
577         if( pCode[j]->GetType() == svIndex || pCode[j]->GetOpCode() == ocColRowName )
578             return sal_True;
579     }
580     return sal_False;
581 }
582 
583 ////////////////////////////////////////////////////////////////////////////
584 
585 FormulaTokenArray::FormulaTokenArray()
586 {
587     pCode = NULL; pRPN = NULL;
588     nError = nLen = nIndex = nRPN = nRefs = 0;
589     bHyperLink = sal_False;
590     ClearRecalcMode();
591 }
592 
593 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray& rArr )
594 {
595     Assign( rArr );
596 }
597 
598 FormulaTokenArray::~FormulaTokenArray()
599 {
600     Clear();
601 }
602 
603 void FormulaTokenArray::Assign( const FormulaTokenArray& r )
604 {
605     nLen   = r.nLen;
606     nRPN   = r.nRPN;
607     nIndex = r.nIndex;
608     nError = r.nError;
609     nRefs  = r.nRefs;
610     nMode  = r.nMode;
611     bHyperLink = r.bHyperLink;
612     pCode  = NULL;
613     pRPN   = NULL;
614     FormulaToken** pp;
615     if( nLen )
616     {
617         pp = pCode = new FormulaToken*[ nLen ];
618         memcpy( pp, r.pCode, nLen * sizeof( FormulaToken* ) );
619         for( sal_uInt16 i = 0; i < nLen; i++ )
620             (*pp++)->IncRef();
621     }
622     if( nRPN )
623     {
624         pp = pRPN = new FormulaToken*[ nRPN ];
625         memcpy( pp, r.pRPN, nRPN * sizeof( FormulaToken* ) );
626         for( sal_uInt16 i = 0; i < nRPN; i++ )
627             (*pp++)->IncRef();
628     }
629 }
630 
631 FormulaTokenArray& FormulaTokenArray::operator=( const FormulaTokenArray& rArr )
632 {
633     Clear();
634     Assign( rArr );
635     return *this;
636 }
637 
638 FormulaTokenArray* FormulaTokenArray::Clone() const
639 {
640     FormulaTokenArray* p = new FormulaTokenArray;
641     p->nLen = nLen;
642     p->nRPN = nRPN;
643     p->nRefs = nRefs;
644     p->nMode = nMode;
645     p->nError = nError;
646     p->bHyperLink = bHyperLink;
647     FormulaToken** pp;
648     if( nLen )
649     {
650         pp = p->pCode = new FormulaToken*[ nLen ];
651         memcpy( pp, pCode, nLen * sizeof( FormulaToken* ) );
652         for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
653         {
654             *pp = (*pp)->Clone();
655             (*pp)->IncRef();
656         }
657     }
658     if( nRPN )
659     {
660         pp = p->pRPN = new FormulaToken*[ nRPN ];
661         memcpy( pp, pRPN, nRPN * sizeof( FormulaToken* ) );
662         for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
663         {
664             FormulaToken* t = *pp;
665             if( t->GetRef() > 1 )
666             {
667                 FormulaToken** p2 = pCode;
668                 sal_uInt16 nIdx = 0xFFFF;
669                 for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
670                 {
671                     if( *p2 == t )
672                     {
673                         nIdx = j; break;
674                     }
675                 }
676                 if( nIdx == 0xFFFF )
677                     *pp = t->Clone();
678                 else
679                     *pp = p->pCode[ nIdx ];
680             }
681             else
682                 *pp = t->Clone();
683             (*pp)->IncRef();
684         }
685     }
686     return p;
687 }
688 
689 void FormulaTokenArray::Clear()
690 {
691     if( nRPN ) DelRPN();
692     if( pCode )
693     {
694         FormulaToken** p = pCode;
695         for( sal_uInt16 i = 0; i < nLen; i++ )
696         {
697             (*p++)->DecRef();
698         }
699         delete [] pCode;
700     }
701     pCode = NULL; pRPN = NULL;
702     nError = nLen = nIndex = nRPN = nRefs = 0;
703     bHyperLink = sal_False;
704     ClearRecalcMode();
705 }
706 
707 FormulaToken* FormulaTokenArray::AddToken( const FormulaToken& r )
708 {
709     return Add( r.Clone() );
710 }
711 
712 FormulaToken* FormulaTokenArray::MergeArray( )
713 {
714     return NULL;
715 }
716 
717 FormulaToken* FormulaTokenArray::Add( FormulaToken* t )
718 {
719     if( !pCode )
720         pCode = new FormulaToken*[ MAXCODE ];
721     if( nLen < MAXCODE-1 )
722     {
723         // fprintf (stderr, "Add : %d\n", t->GetOpCode());
724         pCode[ nLen++ ] = t;
725         if( t->GetOpCode() == ocPush
726             && ( t->GetType() == svSingleRef || t->GetType() == svDoubleRef ) )
727             nRefs++;
728         t->IncRef();
729         if( t->GetOpCode() == ocArrayClose )
730             return MergeArray();
731         return t;
732     }
733     else
734     {
735         t->Delete();
736         if ( nLen == MAXCODE-1 )
737         {
738             t = new FormulaByteToken( ocStop );
739             pCode[ nLen++ ] = t;
740             t->IncRef();
741         }
742         return NULL;
743     }
744 }
745 
746 FormulaToken* FormulaTokenArray::AddString( const sal_Unicode* pStr )
747 {
748     return AddString( String( pStr ) );
749 }
750 
751 FormulaToken* FormulaTokenArray::AddString( const String& rStr )
752 {
753     return Add( new FormulaStringToken( rStr ) );
754 }
755 
756 FormulaToken* FormulaTokenArray::AddDouble( double fVal )
757 {
758     return Add( new FormulaDoubleToken( fVal ) );
759 }
760 
761 FormulaToken* FormulaTokenArray::AddName( sal_uInt16 n )
762 {
763     return Add( new FormulaIndexToken( ocName, n ) );
764 }
765 
766 FormulaToken* FormulaTokenArray::AddExternal( const sal_Unicode* pStr )
767 {
768     return AddExternal( String( pStr ) );
769 }
770 
771 FormulaToken* FormulaTokenArray::AddExternal( const String& rStr,
772         OpCode eOp /* = ocExternal */ )
773 {
774     return Add( new FormulaExternalToken( eOp, rStr ) );
775 }
776 
777 FormulaToken* FormulaTokenArray::AddBad( const sal_Unicode* pStr )
778 {
779     return AddBad( String( pStr ) );
780 }
781 
782 FormulaToken* FormulaTokenArray::AddBad( const String& rStr )
783 {
784     return Add( new FormulaStringOpToken( ocBad, rStr ) );
785 }
786 
787 
788 
789 void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits )
790 {
791     //! Reihenfolge ist wichtig
792     if ( nBits & RECALCMODE_ALWAYS )
793         SetRecalcModeAlways();
794     else if ( !IsRecalcModeAlways() )
795     {
796         if ( nBits & RECALCMODE_ONLOAD )
797             SetRecalcModeOnLoad();
798         else if ( nBits & RECALCMODE_ONLOAD_ONCE && !IsRecalcModeOnLoad() )
799             SetRecalcModeOnLoadOnce();
800     }
801     SetCombinedBitsRecalcMode( nBits );
802 }
803 
804 
805 sal_Bool FormulaTokenArray::HasMatrixDoubleRefOps()
806 {
807     if ( pRPN && nRPN )
808     {
809         // RPN-Interpreter Simulation
810         // als Ergebnis jeder Funktion wird einfach ein Double angenommen
811         FormulaToken** pStack = new FormulaToken* [nRPN];
812         FormulaToken* pResult = new FormulaDoubleToken( 0.0 );
813         short sp = 0;
814         for ( sal_uInt16 j = 0; j < nRPN; j++ )
815         {
816             FormulaToken* t = pRPN[j];
817             OpCode eOp = t->GetOpCode();
818             sal_uInt8 nParams = t->GetParamCount();
819             switch ( eOp )
820             {
821                 case ocAdd :
822                 case ocSub :
823                 case ocMul :
824                 case ocDiv :
825                 case ocPow :
826                 case ocPower :
827                 case ocAmpersand :
828                 case ocEqual :
829                 case ocNotEqual :
830                 case ocLess :
831                 case ocGreater :
832                 case ocLessEqual :
833                 case ocGreaterEqual :
834                 {
835                     for ( sal_uInt8 k = nParams; k; k-- )
836                     {
837                         if ( sp >= k && pStack[sp-k]->GetType() == svDoubleRef )
838                         {
839                             pResult->Delete();
840                             delete [] pStack;
841                             return sal_True;
842                         }
843                     }
844                 }
845                 break;
846                 default:
847                 {
848                     // added to avoid warnings
849                 }
850             }
851             if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() )  )
852                 pStack[sp++] = t;
853             else if ( eOp == ocIf || eOp == ocChose )
854             {   // Jumps ignorieren, vorheriges Result (Condition) poppen
855                 if ( sp )
856                     --sp;
857             }
858             else
859             {   // pop parameters, push result
860                 sp = sal::static_int_cast<short>( sp - nParams );
861                 if ( sp < 0 )
862                 {
863                     DBG_ERROR( "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
864                     sp = 0;
865                 }
866                 pStack[sp++] = pResult;
867             }
868         }
869         pResult->Delete();
870         delete [] pStack;
871     }
872 
873     return sal_False;
874 }
875 
876 
877 
878 // --- POF (plain old formula) rewrite of a token array ---------------------
879 
880 #if 0
881 // static function can't be compiled if not used (warning)
882 //#if OSL_DEBUG_LEVEL > 0
883 static void DumpTokArr( FormulaTokenArray *pCode )
884 {
885     fprintf (stderr, "TokenArr: ");
886     for ( FormulaToken *pCur = pCode->First(); pCur; pCur = pCode->Next() )
887         fprintf( stderr, "t%d,o%d ",
888                 pCur->GetType(), pCur->GetOpCode() );
889     fprintf (stderr, "\n");
890 }
891 #endif
892 
893 inline bool MissingConvention::isRewriteNeeded( OpCode eOp ) const
894 {
895     switch (eOp)
896     {
897         case ocGammaDist:
898         case ocPoissonDist:
899         case ocAddress:
900         case ocLogNormDist:
901         case ocNormDist:
902             return true;
903         case ocMissing:
904         case ocLog:
905             return !isODFF();   // rewrite only for PODF
906         default:
907             return false;
908     }
909 }
910 
911 class FormulaMissingContext
912 {
913     public:
914             const FormulaToken* mpFunc;
915             int                 mnCurArg;
916 
917                     void    Clear() { mpFunc = NULL; mnCurArg = 0; }
918             inline  bool    AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const;
919                     bool    AddMissingExternal( FormulaTokenArray* pNewArr ) const;
920                     bool    AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv  ) const;
921                     void    AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv  ) const;
922 };
923 
924 void FormulaMissingContext::AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv  ) const
925 {
926     if ( !mpFunc )
927         return;
928 
929     switch (mpFunc->GetOpCode())
930     {
931         case ocGammaDist:
932             if (mnCurArg == 2)
933             {
934                 pNewArr->AddOpCode( ocSep );
935                 pNewArr->AddDouble( 1.0 );      // 4th, Cumulative=sal_True()
936             }
937             break;
938         case ocPoissonDist:
939             if (mnCurArg == 1)
940             {
941                 pNewArr->AddOpCode( ocSep );
942                 pNewArr->AddDouble( 1.0 );      // 3rd, Cumulative=sal_True()
943             }
944             break;
945         case ocNormDist:
946             if ( mnCurArg == 2 )
947             {
948                 pNewArr->AddOpCode( ocSep );
949                 pNewArr->AddDouble( 1.0 );      // 4th, Cumulative=sal_True()
950             }
951             break;
952         case ocLogNormDist:
953             if ( mnCurArg == 0 )
954             {
955                 pNewArr->AddOpCode( ocSep );
956                 pNewArr->AddDouble( 0.0 );      // 2nd, mean = 0.0
957             }
958             if ( mnCurArg <= 1 )
959             {
960                 pNewArr->AddOpCode( ocSep );
961                 pNewArr->AddDouble( 1.0 );      // 3rd, standard deviation = 1.0
962             }
963             break;
964         case ocLog:
965             if ( !rConv.isODFF() && mnCurArg == 0 )
966             {
967                 pNewArr->AddOpCode( ocSep );
968                 pNewArr->AddDouble( 10.0 );     // 2nd, basis 10
969             }
970             break;
971         default:
972             break;
973     }
974 }
975 
976 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const
977 {
978     if (mnCurArg == nArg)
979     {
980         pNewArr->AddDouble( f );
981         return true;
982     }
983     return false;
984 }
985 
986 bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray *pNewArr ) const
987 {
988     // Only called for PODF, not ODFF. No need to distinguish.
989 
990     const String &rName = mpFunc->GetExternal();
991 
992     // initial (fast) check:
993     sal_Unicode nLastChar = rName.GetChar( rName.Len() - 1);
994     if ( nLastChar != 't' && nLastChar != 'm' )
995         return false;
996 
997     if (rName.EqualsIgnoreCaseAscii(
998                 "com.sun.star.sheet.addin.Analysis.getAccrint" ))
999     {
1000         return AddDefaultArg( pNewArr, 4, 1000.0 );
1001     }
1002     if (rName.EqualsIgnoreCaseAscii(
1003                 "com.sun.star.sheet.addin.Analysis.getAccrintm" ))
1004     {
1005         return AddDefaultArg( pNewArr, 3, 1000.0 );
1006     }
1007     return false;
1008 }
1009 
1010 bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv  ) const
1011 {
1012     if ( !mpFunc )
1013         return false;
1014 
1015     bool bRet = false;
1016     const OpCode eOp = mpFunc->GetOpCode();
1017 
1018     // Add for both, PODF and ODFF
1019     switch (eOp)
1020     {
1021         case ocAddress:
1022             return AddDefaultArg( pNewArr, 2, 1.0 );    // abs
1023         default:
1024             break;
1025     }
1026 
1027     if (rConv.isODFF())
1028     {
1029         // Add for ODFF
1030     }
1031     else
1032     {
1033         // Add for PODF
1034         switch (eOp)
1035         {
1036             case ocFixed:
1037                 return AddDefaultArg( pNewArr, 1, 2.0 );
1038             case ocBetaDist:
1039             case ocBetaInv:
1040             case ocRMZ:     // PMT
1041                 return AddDefaultArg( pNewArr, 3, 0.0 );
1042             case ocZinsZ:   // IPMT
1043             case ocKapz:    // PPMT
1044                 return AddDefaultArg( pNewArr, 4, 0.0 );
1045             case ocBW:      // PV
1046             case ocZW:      // FV
1047                 bRet |= AddDefaultArg( pNewArr, 2, 0.0 );   // pmt
1048                 bRet |= AddDefaultArg( pNewArr, 3, 0.0 );   // [fp]v
1049                 break;
1050             case ocZins:    // RATE
1051                 bRet |= AddDefaultArg( pNewArr, 1, 0.0 );   // pmt
1052                 bRet |= AddDefaultArg( pNewArr, 3, 0.0 );   // fv
1053                 bRet |= AddDefaultArg( pNewArr, 4, 0.0 );   // type
1054                 break;
1055             case ocExternal:
1056                 return AddMissingExternal( pNewArr );
1057 
1058                 // --- more complex cases ---
1059 
1060             case ocOffset:
1061                 // FIXME: rather tough.
1062                 // if arg 3 (height) ommitted, export arg1 (rows)
1063                 break;
1064             default:
1065                 break;
1066         }
1067     }
1068 
1069     return bRet;
1070 }
1071 
1072 bool FormulaTokenArray::NeedsPofRewrite( const MissingConvention & rConv )
1073 {
1074     for ( FormulaToken *pCur = First(); pCur; pCur = Next() )
1075     {
1076         if ( rConv.isRewriteNeeded( pCur->GetOpCode()))
1077             return true;
1078     }
1079     return false;
1080 }
1081 
1082 
1083 FormulaTokenArray * FormulaTokenArray::RewriteMissingToPof( const MissingConvention & rConv )
1084 {
1085     const size_t nAlloc = 256;
1086     FormulaMissingContext aCtx[ nAlloc ];
1087     int aOpCodeAddressStack[ nAlloc ];  // use of ADDRESS() function
1088     const int nOmitAddressArg = 3;      // ADDRESS() 4th parameter A1/R1C1
1089     sal_uInt16 nTokens = GetLen() + 1;
1090     FormulaMissingContext* pCtx = (nAlloc < nTokens ? new FormulaMissingContext[nTokens] : &aCtx[0]);
1091     int* pOcas = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeAddressStack[0]);
1092     // Never go below 0, never use 0, mpFunc always NULL.
1093     pCtx[0].Clear();
1094     int nFn = 0;
1095     int nOcas = 0;
1096 
1097     FormulaTokenArray *pNewArr = new FormulaTokenArray;
1098     // At least RECALCMODE_ALWAYS needs to be set.
1099     pNewArr->AddRecalcMode( GetRecalcMode());
1100 
1101     for ( FormulaToken *pCur = First(); pCur; pCur = Next() )
1102     {
1103         bool bAdd = true;
1104         // Don't write the expression of the new inserted ADDRESS() parameter.
1105         // Do NOT omit the new second parameter of INDIRECT() though. If that
1106         // was done for both, INDIRECT() actually could calculate different and
1107         // valid (but wrong) results with the then changed return value of
1108         // ADDRESS(). Better let it generate an error instead.
1109         for (int i = nOcas; i-- > 0 && bAdd; )
1110         {
1111             if (pCtx[ pOcas[ i ] ].mnCurArg == nOmitAddressArg)
1112             {
1113                 // Omit erverything except a trailing separator, the leading
1114                 // separator is omitted below. The other way around would leave
1115                 // an extraneous separator if no parameter followed.
1116                 if (!(pOcas[ i ] == nFn && pCur->GetOpCode() == ocSep))
1117                     bAdd = false;
1118             }
1119             //fprintf( stderr, "ocAddress %d arg %d%s\n", (int)i, (int)pCtx[ pOcas[ i ] ].mnCurArg, (bAdd ? "" : " omitted"));
1120         }
1121         switch ( pCur->GetOpCode() )
1122         {
1123             case ocOpen:
1124                 ++nFn;      // all following operations on _that_ function
1125                 pCtx[ nFn ].mpFunc = PeekPrevNoSpaces();
1126                 pCtx[ nFn ].mnCurArg = 0;
1127                 if (pCtx[ nFn ].mpFunc && pCtx[ nFn ].mpFunc->GetOpCode() == ocAddress && !rConv.isODFF())
1128                     pOcas[ nOcas++ ] = nFn;     // entering ADDRESS() if PODF
1129                 break;
1130             case ocClose:
1131                 pCtx[ nFn ].AddMoreArgs( pNewArr, rConv );
1132                 DBG_ASSERT( nFn > 0, "FormulaTokenArray::RewriteMissingToPof: underflow");
1133                 if (nOcas > 0 && pOcas[ nOcas-1 ] == nFn)
1134                     --nOcas;                    // leaving ADDRESS()
1135                 if (nFn > 0)
1136                     --nFn;
1137                 break;
1138             case ocSep:
1139                 pCtx[ nFn ].mnCurArg++;
1140                 // Omit leading separator of ADDRESS() parameter.
1141                 if (nOcas && pOcas[ nOcas-1 ] == nFn && pCtx[ nFn ].mnCurArg == nOmitAddressArg)
1142                 {
1143                     bAdd = false;
1144                     //fprintf( stderr, "ocAddress %d sep %d omitted\n", (int)nOcas-1, nOmitAddressArg);
1145                 }
1146                 break;
1147             case ocMissing:
1148                 if (bAdd)
1149                     bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv );
1150                 break;
1151             default:
1152                 break;
1153         }
1154         if (bAdd)
1155             pNewArr->AddToken( *pCur );
1156     }
1157 
1158     if (pOcas != &aOpCodeAddressStack[0])
1159         delete [] pOcas;
1160     if (pCtx != &aCtx[0])
1161         delete [] pCtx;
1162 
1163     return pNewArr;
1164 }
1165 
1166 bool FormulaTokenArray::MayReferenceFollow()
1167 {
1168     if ( pCode && nLen > 0 )
1169     {
1170         // ignore trailing spaces
1171         sal_uInt16 i = nLen - 1;
1172         while ( i > 0 && pCode[i]->GetOpCode() == SC_OPCODE_SPACES )
1173         {
1174             --i;
1175         }
1176         if ( i > 0 || pCode[i]->GetOpCode() != SC_OPCODE_SPACES )
1177         {
1178             OpCode eOp = pCode[i]->GetOpCode();
1179             if ( (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP ) ||
1180                  (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP ) ||
1181                  eOp == SC_OPCODE_OPEN || eOp == SC_OPCODE_SEP )
1182             {
1183                 return true;
1184             }
1185         }
1186     }
1187     return false;
1188 }
1189 FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp )
1190 {
1191     FormulaToken* pRet = NULL;
1192     switch ( eOp )
1193     {
1194         case ocOpen:
1195         case ocClose:
1196         case ocSep:
1197         case ocArrayOpen:
1198         case ocArrayClose:
1199         case ocArrayRowSep:
1200         case ocArrayColSep:
1201             pRet = new FormulaToken( svSep,eOp );
1202             break;
1203         case ocIf:
1204         case ocChose:
1205             {
1206                 short nJump[MAXJUMPCOUNT + 1];
1207                 nJump[ 0 ] = ocIf == eOp ? 3 : MAXJUMPCOUNT+1;
1208                 pRet = new FormulaJumpToken( eOp, (short*)nJump );
1209             }
1210             break;
1211         default:
1212             pRet = new FormulaByteToken( eOp, 0, sal_False );
1213             break;
1214     }
1215     return AddToken( *pRet );
1216 }
1217 
1218 
1219 /*----------------------------------------------------------------------*/
1220 
1221 FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray& rArr )
1222 {
1223     pCur = NULL;
1224     Push( &rArr );
1225 }
1226 
1227 FormulaTokenIterator::~FormulaTokenIterator()
1228 {
1229     while( pCur )
1230         Pop();
1231 }
1232 
1233 void FormulaTokenIterator::Push( const FormulaTokenArray* pArr )
1234 {
1235     ImpTokenIterator* p = new ImpTokenIterator;
1236     p->pArr  = pArr;
1237     p->nPC   = -1;
1238     p->nStop = SHRT_MAX;
1239     p->pNext = pCur;
1240     pCur     = p;
1241 }
1242 
1243 void FormulaTokenIterator::Pop()
1244 {
1245     ImpTokenIterator* p = pCur;
1246     if( p )
1247     {
1248         pCur = p->pNext;
1249         delete p;
1250     }
1251 }
1252 
1253 void FormulaTokenIterator::Reset()
1254 {
1255     while( pCur->pNext )
1256         Pop();
1257     pCur->nPC = -1;
1258 }
1259 
1260 const FormulaToken* FormulaTokenIterator::First()
1261 {
1262     Reset();
1263     return Next();
1264 }
1265 
1266 const FormulaToken* FormulaTokenIterator::Next()
1267 {
1268     const FormulaToken* t = GetNonEndOfPathToken( ++pCur->nPC );
1269     if( !t && pCur->pNext )
1270     {
1271         Pop();
1272         t = Next();
1273     }
1274     return t;
1275 }
1276 
1277 const FormulaToken* FormulaTokenIterator::PeekNextOperator()
1278 {
1279     const FormulaToken* t = NULL;
1280     short nIdx = pCur->nPC;
1281     while (!t && ((t = GetNonEndOfPathToken( ++nIdx)) != NULL))
1282     {
1283         if (t->GetOpCode() == ocPush)
1284             t = NULL;   // ignore operands
1285     }
1286     if (!t && pCur->pNext)
1287     {
1288         ImpTokenIterator* pHere = pCur;
1289         pCur = pCur->pNext;
1290         t = PeekNextOperator();
1291         pCur = pHere;
1292     }
1293     return t;
1294 }
1295 
1296 //! The nPC counts after a Push() are -1
1297 
1298 void FormulaTokenIterator::Jump( short nStart, short nNext, short nStop )
1299 {
1300     pCur->nPC = nNext;
1301     if( nStart != nNext )
1302     {
1303         Push( pCur->pArr );
1304         pCur->nPC = nStart;
1305         pCur->nStop = nStop;
1306     }
1307 }
1308 
1309 const FormulaToken* FormulaTokenIterator::GetNonEndOfPathToken( short nIdx ) const
1310 {
1311     if (nIdx < pCur->pArr->nRPN && nIdx < pCur->nStop)
1312     {
1313         const FormulaToken* t = pCur->pArr->pRPN[ nIdx ];
1314         // such an OpCode ends an IF() or CHOOSE() path
1315         return (t->GetOpCode() == ocSep || t->GetOpCode() == ocClose) ? NULL : t;
1316     }
1317     return NULL;
1318 }
1319 
1320 bool FormulaTokenIterator::IsEndOfPath() const
1321 {
1322     return GetNonEndOfPathToken( pCur->nPC + 1) == NULL;
1323 }
1324 
1325 // -----------------------------------------------------------------------------
1326 // ==========================================================================
1327 // real implementations of virtual functions
1328 // --------------------------------------------------------------------------
1329 
1330 double      FormulaDoubleToken::GetDouble() const            { return fDouble; }
1331 double &    FormulaDoubleToken::GetDoubleAsReference()       { return fDouble; }
1332 sal_Bool FormulaDoubleToken::operator==( const FormulaToken& r ) const
1333 {
1334     return FormulaToken::operator==( r ) && fDouble == r.GetDouble();
1335 }
1336 
1337 
1338 const String& FormulaStringToken::GetString() const          { return aString; }
1339 sal_Bool FormulaStringToken::operator==( const FormulaToken& r ) const
1340 {
1341     return FormulaToken::operator==( r ) && aString == r.GetString();
1342 }
1343 
1344 
1345 const String& FormulaStringOpToken::GetString() const             { return aString; }
1346 sal_Bool FormulaStringOpToken::operator==( const FormulaToken& r ) const
1347 {
1348     return FormulaByteToken::operator==( r ) && aString == r.GetString();
1349 }
1350 
1351 sal_uInt16  FormulaIndexToken::GetIndex() const                  { return nIndex; }
1352 void    FormulaIndexToken::SetIndex( sal_uInt16 n )              { nIndex = n; }
1353 sal_Bool FormulaIndexToken::operator==( const FormulaToken& r ) const
1354 {
1355     return FormulaToken::operator==( r ) && nIndex == r.GetIndex();
1356 }
1357 const String&   FormulaExternalToken::GetExternal() const    { return aExternal; }
1358 sal_uInt8            FormulaExternalToken::GetByte() const        { return nByte; }
1359 void            FormulaExternalToken::SetByte( sal_uInt8 n )      { nByte = n; }
1360 sal_Bool FormulaExternalToken::operator==( const FormulaToken& r ) const
1361 {
1362     return FormulaToken::operator==( r ) && nByte == r.GetByte() &&
1363         aExternal == r.GetExternal();
1364 }
1365 
1366 
1367 sal_uInt16          FormulaErrorToken::GetError() const          { return nError; }
1368 void            FormulaErrorToken::SetError( sal_uInt16 nErr )   { nError = nErr; }
1369 sal_Bool FormulaErrorToken::operator==( const FormulaToken& r ) const
1370 {
1371     return FormulaToken::operator==( r ) &&
1372         nError == static_cast< const FormulaErrorToken & >(r).GetError();
1373 }
1374 double          FormulaMissingToken::GetDouble() const       { return 0.0; }
1375 const String&   FormulaMissingToken::GetString() const
1376 {
1377     static  String              aDummyString;
1378     return aDummyString;
1379 }
1380 sal_Bool FormulaMissingToken::operator==( const FormulaToken& r ) const
1381 {
1382     return FormulaToken::operator==( r );
1383 }
1384 
1385 
1386 FormulaSubroutineToken::FormulaSubroutineToken( const FormulaSubroutineToken& r ) :
1387     FormulaToken( r ),
1388     mpArray( r.mpArray->Clone())
1389 {
1390 }
1391 FormulaSubroutineToken::~FormulaSubroutineToken()
1392 {
1393     delete mpArray;
1394 }
1395 const FormulaTokenArray* FormulaSubroutineToken::GetTokenArray() const
1396 {
1397     return mpArray;
1398 }
1399 sal_Bool FormulaSubroutineToken::operator==( const FormulaToken& r ) const
1400 {
1401     // Arrays don't equal..
1402     return FormulaToken::operator==( r ) &&
1403         (mpArray == static_cast<const FormulaSubroutineToken&>(r).mpArray);
1404 }
1405 
1406 
1407 sal_Bool FormulaUnknownToken::operator==( const FormulaToken& r ) const
1408 {
1409     return FormulaToken::operator==( r );
1410 }
1411 
1412 // -----------------------------------------------------------------------------
1413 } // formula
1414 // -----------------------------------------------------------------------------
1415 
1416