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