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