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