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 #include "precompiled_formula.hxx" 28 #include "formula/FormulaCompiler.hxx" 29 #include "formula/errorcodes.hxx" 30 #include "formula/token.hxx" 31 #include "formula/tokenarray.hxx" 32 #include "core_resource.hxx" 33 #include "core_resource.hrc" 34 35 #include <svl/zforlist.hxx> 36 #include <tools/rc.hxx> 37 #include <tools/rcid.h> 38 #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp> 39 #include <com/sun/star/sheet/FormulaMapGroup.hpp> 40 #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp> 41 #include <stdio.h> 42 43 // ============================================================================= 44 namespace formula 45 { 46 // ============================================================================= 47 using namespace ::com::sun::star; 48 49 static const sal_Char* pInternal[ 1 ] = { "TTT" }; 50 51 // ============================================================================= 52 namespace 53 { 54 // ============================================================================= 55 class FormulaCompilerRecursionGuard 56 { 57 private: 58 short& rRecursion; 59 public: 60 FormulaCompilerRecursionGuard( short& rRec ) 61 : rRecursion( rRec ) { ++rRecursion; } 62 ~FormulaCompilerRecursionGuard() { --rRecursion; } 63 }; 64 65 short lcl_GetRetFormat( OpCode eOpCode ) 66 { 67 switch (eOpCode) 68 { 69 case ocEqual: 70 case ocNotEqual: 71 case ocLess: 72 case ocGreater: 73 case ocLessEqual: 74 case ocGreaterEqual: 75 case ocAnd: 76 case ocOr: 77 case ocNot: 78 case ocTrue: 79 case ocFalse: 80 case ocIsEmpty: 81 case ocIsString: 82 case ocIsNonString: 83 case ocIsLogical: 84 case ocIsRef: 85 case ocIsValue: 86 case ocIsFormula: 87 case ocIsNA: 88 case ocIsErr: 89 case ocIsError: 90 case ocIsEven: 91 case ocIsOdd: 92 case ocExact: 93 return NUMBERFORMAT_LOGICAL; 94 case ocGetActDate: 95 case ocGetDate: 96 case ocEasterSunday : 97 return NUMBERFORMAT_DATE; 98 case ocGetActTime: 99 return NUMBERFORMAT_DATETIME; 100 case ocGetTime: 101 return NUMBERFORMAT_TIME; 102 case ocNPV: 103 case ocBW: 104 case ocDIA: 105 case ocGDA: 106 case ocGDA2: 107 case ocVBD: 108 case ocLIA: 109 case ocRMZ: 110 case ocZW: 111 case ocZinsZ: 112 case ocKapz: 113 case ocKumZinsZ: 114 case ocKumKapZ: 115 return NUMBERFORMAT_CURRENCY; 116 case ocZins: 117 case ocIRR: 118 case ocMIRR: 119 case ocZGZ: 120 case ocEffektiv: 121 case ocNominal: 122 case ocPercentSign: 123 return NUMBERFORMAT_PERCENT; 124 // case ocSum: 125 // case ocSumSQ: 126 // case ocProduct: 127 // case ocAverage: 128 // return -1; 129 default: 130 return NUMBERFORMAT_NUMBER; 131 } 132 return NUMBERFORMAT_NUMBER; 133 } 134 135 inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, sal_uInt16 nOpCode ) 136 { 137 sheet::FormulaOpCodeMapEntry aEntry; 138 aEntry.Token.OpCode = nOpCode; 139 aEntry.Name = pTable[nOpCode]; 140 rVec.push_back( aEntry); 141 } 142 143 void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, sal_uInt16 nOpCodeBeg, sal_uInt16 nOpCodeEnd ) 144 { 145 for (sal_uInt16 nOpCode = nOpCodeBeg; nOpCode < nOpCodeEnd; ++nOpCode) 146 lclPushOpCodeMapEntry( rVec, pTable, nOpCode ); 147 } 148 149 void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, const sal_uInt16* pnOpCodes, size_t nCount ) 150 { 151 for (const sal_uInt16* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes) 152 lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes ); 153 } 154 155 class OpCodeList : public Resource // temp object for resource 156 { 157 public: 158 159 OpCodeList( sal_uInt16, FormulaCompiler::NonConstOpCodeMapPtr ); 160 161 private: 162 bool getOpCodeString( String& rStr, sal_uInt16 nOp ); 163 void putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp ); 164 165 private: 166 enum SeparatorType 167 { 168 SEMICOLON_BASE, 169 COMMA_BASE 170 }; 171 SeparatorType meSepType; 172 }; 173 174 OpCodeList::OpCodeList( sal_uInt16 nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap ) : 175 Resource( ResId(nRID,*ResourceManager::getResManager()) ) 176 ,meSepType(SEMICOLON_BASE) 177 { 178 for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i) 179 { 180 String aOpStr; 181 if ( getOpCodeString(aOpStr, i) ) 182 xMap->putOpCode(aOpStr, OpCode(i)); 183 else 184 putDefaultOpCode(xMap, i); 185 } 186 187 FreeResource(); 188 } 189 190 bool OpCodeList::getOpCodeString( String& rStr, sal_uInt16 nOp ) 191 { 192 switch (nOp) 193 { 194 case SC_OPCODE_SEP: 195 { 196 if (meSepType == COMMA_BASE) 197 { 198 rStr = String::CreateFromAscii(","); 199 return true; 200 } 201 else if (meSepType == SEMICOLON_BASE) 202 { 203 rStr = String::CreateFromAscii(";"); 204 return true; 205 } 206 } 207 break; 208 case SC_OPCODE_ARRAY_COL_SEP: 209 { 210 if (meSepType == COMMA_BASE) 211 { 212 rStr = String::CreateFromAscii(","); 213 return true; 214 } 215 else if (meSepType == SEMICOLON_BASE) 216 { 217 rStr = String::CreateFromAscii(";"); 218 return true; 219 } 220 } 221 break; 222 case SC_OPCODE_ARRAY_ROW_SEP: 223 { 224 if (meSepType == COMMA_BASE) 225 { 226 rStr = String::CreateFromAscii(";"); 227 return true; 228 } 229 else if (meSepType == SEMICOLON_BASE) 230 { 231 rStr = String::CreateFromAscii("|"); 232 return true; 233 } 234 } 235 break; 236 } 237 238 return false; 239 } 240 241 void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp ) 242 { 243 ResId aRes(nOp,*ResourceManager::getResManager()); 244 aRes.SetRT(RSC_STRING); 245 if (IsAvailableRes(aRes)) 246 xMap->putOpCode(aRes, OpCode(nOp)); 247 } 248 // ----------------------------------------------------------------------------- 249 // static 250 const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,sal_Unicode c ) 251 { 252 if ( !pStr ) 253 return NULL; 254 while ( *pStr ) 255 { 256 if ( *pStr == c ) 257 return pStr; 258 pStr++; 259 } 260 return NULL; 261 } 262 // ============================================================================= 263 } // empty 264 // ============================================================================= 265 266 void FormulaCompiler::OpCodeMap::putExternal( const String & rSymbol, const String & rAddIn ) 267 { 268 bool bOk = mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second; 269 if (bOk) 270 bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second; 271 DBG_ASSERT( bOk, "OpCodeMap::putExternal: symbol not inserted"); 272 } 273 274 void FormulaCompiler::OpCodeMap::putExternalSoftly( const String & rSymbol, const String & rAddIn ) 275 { 276 bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second; 277 if (bOk) 278 mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second; 279 } 280 uno::Sequence< sheet::FormulaToken > FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(const FormulaCompiler& _rCompiler,const uno::Sequence< ::rtl::OUString >& rNames ) const 281 { 282 const sal_Int32 nLen = rNames.getLength(); 283 uno::Sequence< sheet::FormulaToken > aTokens( nLen); 284 sheet::FormulaToken* pToken = aTokens.getArray(); 285 ::rtl::OUString const * pName = rNames.getConstArray(); 286 ::rtl::OUString const * const pStop = pName + nLen; 287 for ( ; pName < pStop; ++pName, ++pToken) 288 { 289 OpCodeHashMap::const_iterator iLook( mpHashMap->find( *pName)); 290 if (iLook != mpHashMap->end()) 291 pToken->OpCode = (*iLook).second; 292 else 293 { 294 ::rtl::OUString aIntName; 295 if (hasExternals()) 296 { 297 ExternalHashMap::const_iterator iExt( mpExternalHashMap->find( *pName)); 298 if (iExt != mpExternalHashMap->end()) 299 aIntName = (*iExt).second; 300 // Check for existence not needed here, only name-mapping is of 301 // interest. 302 } 303 if (!aIntName.getLength()) 304 aIntName = _rCompiler.FindAddInFunction(*pName, !isEnglish()); // bLocalFirst=sal_False for english 305 if (!aIntName.getLength()) 306 pToken->OpCode = getOpCodeUnknown(); 307 else 308 { 309 pToken->OpCode = ocExternal; 310 pToken->Data <<= aIntName; 311 } 312 } 313 } 314 return aTokens; 315 } 316 uno::Sequence< sheet::FormulaOpCodeMapEntry > FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(const FormulaCompiler& _rCompiler,const sal_Int32 nGroups ) const 317 { 318 using namespace sheet; 319 320 // Unfortunately uno::Sequence can't grow without cumbersome reallocs. As 321 // we don't know in advance how many elements it will have we use a 322 // temporary vector to add elements and then copy to Sequence :-( 323 ::std::vector< FormulaOpCodeMapEntry > aVec; 324 325 if (nGroups == FormulaMapGroup::SPECIAL) 326 { 327 // Use specific order, keep in sync with 328 // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl 329 static const struct 330 { 331 sal_Int32 nOff; 332 OpCode eOp; 333 } aMap[] = { 334 { FormulaMapGroupSpecialOffset::PUSH , ocPush } , 335 { FormulaMapGroupSpecialOffset::CALL , ocCall } , 336 { FormulaMapGroupSpecialOffset::STOP , ocStop } , 337 { FormulaMapGroupSpecialOffset::EXTERNAL , ocExternal } , 338 { FormulaMapGroupSpecialOffset::NAME , ocName } , 339 { FormulaMapGroupSpecialOffset::NO_NAME , ocNoName } , 340 { FormulaMapGroupSpecialOffset::MISSING , ocMissing } , 341 { FormulaMapGroupSpecialOffset::BAD , ocBad } , 342 { FormulaMapGroupSpecialOffset::SPACES , ocSpaces } , 343 { FormulaMapGroupSpecialOffset::MAT_REF , ocMatRef } , 344 { FormulaMapGroupSpecialOffset::DB_AREA , ocDBArea } , 345 { FormulaMapGroupSpecialOffset::MACRO , ocMacro } , 346 { FormulaMapGroupSpecialOffset::COL_ROW_NAME , ocColRowName } 347 }; 348 const size_t nCount = sizeof(aMap)/sizeof(aMap[0]); 349 // Preallocate vector elements. 350 if (aVec.size() < nCount) 351 { 352 FormulaOpCodeMapEntry aEntry; 353 aEntry.Token.OpCode = getOpCodeUnknown(); 354 aVec.resize( nCount, aEntry); 355 } // if (aVec.size() < nCount) 356 357 FormulaOpCodeMapEntry aEntry; 358 for (size_t i=0; i < nCount; ++i) 359 { 360 size_t nIndex = static_cast< size_t >( aMap[i].nOff ); 361 if (aVec.size() <= nIndex) 362 { 363 // The offsets really should be aligned with the size, so if 364 // the vector was preallocated above this code to resize it is 365 // just a measure in case the table isn't in sync with the API, 366 // usually it isn't executed. 367 aEntry.Token.OpCode = getOpCodeUnknown(); 368 aVec.resize( nIndex + 1, aEntry ); 369 } 370 aEntry.Token.OpCode = aMap[i].eOp; 371 aVec[nIndex] = aEntry; 372 } 373 } 374 else 375 { 376 /* FIXME: Once we support error constants in formulas we'll need a map 377 * group for that, e.g. FormulaMapGroup::ERROR_CONSTANTS, and fill 378 * SC_OPCODE_START_ERRORS to SC_OPCODE_STOP_ERRORS. */ 379 380 // Anything else but SPECIAL. 381 if ((nGroups & FormulaMapGroup::SEPARATORS) != 0) 382 { 383 static const sal_uInt16 aOpCodes[] = { 384 SC_OPCODE_OPEN, 385 SC_OPCODE_CLOSE, 386 SC_OPCODE_SEP, 387 }; 388 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) ); 389 } 390 if ((nGroups & FormulaMapGroup::ARRAY_SEPARATORS) != 0) 391 { 392 static const sal_uInt16 aOpCodes[] = { 393 SC_OPCODE_ARRAY_OPEN, 394 SC_OPCODE_ARRAY_CLOSE, 395 SC_OPCODE_ARRAY_ROW_SEP, 396 SC_OPCODE_ARRAY_COL_SEP 397 }; 398 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) ); 399 } 400 if ((nGroups & FormulaMapGroup::UNARY_OPERATORS) != 0) 401 { 402 // Due to the nature of the percent operator following its operand 403 // it isn't sorted into unary operators for compiler interna. 404 lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign ); 405 // "+" can be used as unary operator too, push only if binary group is not set 406 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0) 407 lclPushOpCodeMapEntry( aVec, mpTable, ocAdd ); 408 // regular unary operators 409 for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp) 410 { 411 switch (nOp) 412 { 413 // NOT and NEG in fact are functions but for legacy reasons 414 // are sorted into unary operators for compiler interna. 415 case SC_OPCODE_NOT : 416 case SC_OPCODE_NEG : 417 break; // nothing, 418 default: 419 lclPushOpCodeMapEntry( aVec, mpTable, nOp ); 420 } 421 } 422 } 423 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0) 424 { 425 for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp) 426 { 427 switch (nOp) 428 { 429 // AND and OR in fact are functions but for legacy reasons 430 // are sorted into binary operators for compiler interna. 431 case SC_OPCODE_AND : 432 case SC_OPCODE_OR : 433 break; // nothing, 434 default: 435 lclPushOpCodeMapEntry( aVec, mpTable, nOp ); 436 } 437 } 438 } 439 if ((nGroups & FormulaMapGroup::FUNCTIONS) != 0) 440 { 441 // Function names are not consecutive, skip the gaps between 442 // functions with no parameter, functions with 1 parameter 443 lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_NO_PAR, ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) ); 444 lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_1_PAR, ::std::min< sal_uInt16 >( SC_OPCODE_STOP_1_PAR, mnSymbols ) ); 445 // Additional functions not within range of functions. 446 static const sal_uInt16 aOpCodes[] = { 447 SC_OPCODE_IF, 448 SC_OPCODE_CHOSE, 449 SC_OPCODE_AND, 450 SC_OPCODE_OR, 451 SC_OPCODE_NOT, 452 SC_OPCODE_NEG 453 }; 454 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) ); 455 // functions with 2 or more parameters. 456 for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp) 457 { 458 switch (nOp) 459 { 460 // NO_NAME is in SPECIAL. 461 case SC_OPCODE_NO_NAME : 462 break; // nothing, 463 default: 464 lclPushOpCodeMapEntry( aVec, mpTable, nOp ); 465 } 466 } 467 // If AddIn functions are present in this mapping, use them, and only those. 468 if (hasExternals()) 469 { 470 for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it) 471 { 472 FormulaOpCodeMapEntry aEntry; 473 aEntry.Name = (*it).first; 474 aEntry.Token.Data <<= ::rtl::OUString( (*it).second); 475 aEntry.Token.OpCode = ocExternal; 476 aVec.push_back( aEntry); 477 } 478 } 479 else 480 { 481 //DBG_ASSERT( isCore(), "FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings: AddIn mapping from collection only implemented for core languages"); 482 _rCompiler.fillAddInToken(aVec,isEnglish()); 483 } 484 } 485 } 486 const FormulaOpCodeMapEntry* pRet = aVec.empty() ? 0 : &aVec[0]; 487 return uno::Sequence< FormulaOpCodeMapEntry >(pRet, aVec.size()); 488 } 489 //----------------------------------------------------------------------------- 490 491 void FormulaCompiler::OpCodeMap::putOpCode( const String & rStr, const OpCode eOp ) 492 { 493 DBG_ASSERT( 0 < eOp && sal_uInt16(eOp) < mnSymbols, "OpCodeMap::putOpCode: OpCode out of range"); 494 if (0 < eOp && sal_uInt16(eOp) < mnSymbols) 495 { 496 DBG_ASSERT( (mpTable[eOp].Len() == 0) || (mpTable[eOp] == rStr) || (eOp == ocCurrency), 497 ByteString( "OpCodeMap::putOpCode: reusing OpCode "). 498 Append( ByteString::CreateFromInt32( sal_Int32( eOp))).Append( " ("). 499 Append( ByteString( rStr, RTL_TEXTENCODING_ASCII_US)).Append( ')').GetBuffer()); 500 mpTable[eOp] = rStr; 501 mpHashMap->insert( OpCodeHashMap::value_type( rStr, eOp)); 502 } 503 } 504 // ----------------------------------------------------------------------------- 505 // class FormulaCompiler 506 // ----------------------------------------------------------------------------- 507 DBG_NAME(FormulaCompiler) 508 FormulaCompiler::FormulaCompiler(FormulaTokenArray& _rArr) 509 : 510 pArr( &_rArr ), 511 pExternalRef(NULL), 512 pStack( NULL ), 513 nRecursion(0), 514 nNumFmt( NUMBERFORMAT_UNDEFINED ), 515 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ), 516 bAutoCorrect( sal_False ), 517 bCorrected( sal_False ), 518 bCompileForFAP( sal_False ), 519 bIgnoreErrors( sal_False ) 520 521 { 522 DBG_CTOR(FormulaCompiler,NULL); 523 } 524 FormulaCompiler::FormulaCompiler() 525 : 526 pArr( NULL ), 527 pExternalRef(NULL), 528 pStack( NULL ), 529 nRecursion(0), 530 nNumFmt( NUMBERFORMAT_UNDEFINED ), 531 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ), 532 bAutoCorrect( sal_False ), 533 bCorrected( sal_False ), 534 bCompileForFAP( sal_False ), 535 bIgnoreErrors( sal_False ) 536 537 { 538 DBG_CTOR(FormulaCompiler,NULL); 539 } 540 FormulaCompiler::~FormulaCompiler() 541 { 542 DBG_DTOR(FormulaCompiler,NULL); 543 } 544 545 FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const 546 { 547 FormulaCompiler::OpCodeMapPtr xMap; 548 using namespace sheet; 549 switch (nLanguage) 550 { 551 case FormulaLanguage::ODFF : 552 if (!mxSymbolsODFF) 553 InitSymbolsODFF(); 554 xMap = mxSymbolsODFF; 555 break; 556 case FormulaLanguage::ODF_11 : 557 if (!mxSymbolsPODF) 558 InitSymbolsPODF(); 559 xMap = mxSymbolsPODF; 560 break; 561 case FormulaLanguage::ENGLISH : 562 if (!mxSymbolsEnglish) 563 InitSymbolsEnglish(); 564 xMap = mxSymbolsEnglish; 565 break; 566 case FormulaLanguage::NATIVE : 567 if (!mxSymbolsNative) 568 InitSymbolsNative(); 569 xMap = mxSymbolsNative; 570 break; 571 default: 572 ; // nothing, NULL map returned 573 } 574 return xMap; 575 } 576 // ----------------------------------------------------------------------------- 577 578 String FormulaCompiler::FindAddInFunction( const String& /*rUpperName*/, sal_Bool /*bLocalFirst*/ ) const 579 { 580 return String(); 581 } 582 // ----------------------------------------------------------------------------- 583 FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap( 584 const uno::Sequence< 585 const sheet::FormulaOpCodeMapEntry > & rMapping, 586 bool bEnglish ) 587 { 588 using sheet::FormulaOpCodeMapEntry; 589 // Filter / API maps are never Core 590 NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1,false, FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(FormulaGrammar::GRAM_EXTERNAL, bEnglish),FormulaGrammar::CONV_UNSPECIFIED))); 591 FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray(); 592 FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength(); 593 for ( ; pArr2 < pStop; ++pArr2) 594 { 595 OpCode eOp = OpCode(pArr2->Token.OpCode); 596 if (eOp != ocExternal) 597 xMap->putOpCode( pArr2->Name, eOp); 598 else 599 { 600 ::rtl::OUString aExternalName; 601 if (pArr2->Token.Data >>= aExternalName) 602 xMap->putExternal( pArr2->Name, aExternalName); 603 else 604 { 605 DBG_ERRORFILE( "FormulaCompiler::CreateOpCodeMap: no Token.Data external name"); 606 } 607 } 608 } 609 return xMap; 610 } 611 612 // ----------------------------------------------------------------------------- 613 void lcl_fillNativeSymbols(FormulaCompiler::NonConstOpCodeMapPtr& _xMap,bool _destroy = false) 614 { 615 static FormulaCompiler::NonConstOpCodeMapPtr s_SymbolMap; 616 if ( _destroy ) 617 { 618 s_SymbolMap.reset(); 619 } // if ( _destroy ) 620 else if ( !s_SymbolMap.get() ) 621 { 622 // Core 623 s_SymbolMap.reset( new FormulaCompiler::OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI)); 624 OModuleClient aModuleClient; 625 OpCodeList aOpCodeListNative( RID_STRLIST_FUNCTION_NAMES, s_SymbolMap ); 626 // No AddInMap for native core mapping. 627 } // if ( !s_SymbolMap.get() ) 628 _xMap = s_SymbolMap; 629 } 630 // ----------------------------------------------------------------------------- 631 const String& FormulaCompiler::GetNativeSymbol( OpCode eOp ) 632 { 633 NonConstOpCodeMapPtr xSymbolsNative; 634 lcl_fillNativeSymbols(xSymbolsNative); 635 return xSymbolsNative->getSymbol( eOp ); 636 } 637 // ----------------------------------------------------------------------------- 638 void FormulaCompiler::InitSymbolsNative() const 639 { 640 if (mxSymbolsNative.get()) 641 return; 642 //! Experimental! 643 // Use English function names and separators instead of native in UI. 644 static const sal_Char aEnvVarName[] = "OOO_CALC_USE_ENGLISH_FORMULAS"; 645 const char* pEnv = getenv( aEnvVarName); 646 if (pEnv && (*pEnv == 'Y' || *pEnv == 'y' || *pEnv == '1') ) 647 { 648 fprintf( stderr, "%s=%s => UI uses English function names and separators in formulas.\n", 649 aEnvVarName, pEnv); 650 InitSymbolsEnglish(); 651 mxSymbolsNative = mxSymbolsEnglish; 652 return; 653 } 654 static NonConstOpCodeMapPtr s_sSymbol; 655 if ( !s_sSymbol.get() ) 656 lcl_fillNativeSymbols(s_sSymbol); 657 mxSymbolsNative = s_sSymbol; 658 } 659 // ----------------------------------------------------------------------------- 660 void FormulaCompiler::InitSymbolsEnglish() const 661 { 662 static NonConstOpCodeMapPtr s_sSymbol; 663 if ( !s_sSymbol.get() ) 664 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol); 665 mxSymbolsEnglish = s_sSymbol; 666 } 667 // ----------------------------------------------------------------------------- 668 void FormulaCompiler::InitSymbolsPODF() const 669 { 670 static NonConstOpCodeMapPtr s_sSymbol; 671 if ( !s_sSymbol.get() ) 672 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_PODF,s_sSymbol); 673 mxSymbolsPODF = s_sSymbol; 674 } 675 // ----------------------------------------------------------------------------- 676 void FormulaCompiler::InitSymbolsODFF() const 677 { 678 static NonConstOpCodeMapPtr s_sSymbol; 679 if ( !s_sSymbol.get() ) 680 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF,FormulaGrammar::GRAM_ODFF,s_sSymbol); 681 mxSymbolsODFF = s_sSymbol; 682 } 683 // ----------------------------------------------------------------------------- 684 void FormulaCompiler::loadSymbols(sal_uInt16 _nSymbols,FormulaGrammar::Grammar _eGrammar,NonConstOpCodeMapPtr& _xMap) const 685 { 686 if ( !_xMap.get() ) 687 { 688 // not Core 689 _xMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, _eGrammar != FormulaGrammar::GRAM_ODFF, _eGrammar )); 690 OModuleClient aModuleClient; 691 OpCodeList aOpCodeList( _nSymbols, _xMap ); 692 693 fillFromAddInMap( _xMap, _eGrammar); 694 // Fill from collection for AddIns not already present. 695 if ( FormulaGrammar::GRAM_ENGLISH != _eGrammar ) 696 fillFromAddInCollectionUpperName( _xMap); 697 else 698 fillFromAddInCollectionEnglishName( _xMap); 699 } 700 } 701 // ----------------------------------------------------------------------------- 702 void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const 703 { 704 } 705 // ----------------------------------------------------------------------------- 706 void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const 707 { 708 } 709 // ----------------------------------------------------------------------------- 710 void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const 711 { 712 } 713 // ----------------------------------------------------------------------------- 714 OpCode FormulaCompiler::GetEnglishOpCode( const String& rName ) const 715 { 716 FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap(sheet::FormulaLanguage::ENGLISH); 717 718 formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) ); 719 bool bFound = (iLook != xMap->getHashMap()->end()); 720 return bFound ? (*iLook).second : OpCode(ocNone); 721 } 722 723 // Remove quotes, escaped quotes are unescaped. 724 sal_Bool FormulaCompiler::DeQuote( String& rStr ) 725 { 726 xub_StrLen nLen = rStr.Len(); 727 if ( nLen > 1 && rStr.GetChar(0) == '\'' && rStr.GetChar( nLen-1 ) == '\'' ) 728 { 729 rStr.Erase( nLen-1, 1 ); 730 rStr.Erase( 0, 1 ); 731 xub_StrLen nPos = 0; 732 while ( (nPos = rStr.SearchAscii( "\\\'", nPos)) != STRING_NOTFOUND ) 733 { 734 rStr.Erase( nPos, 1 ); 735 ++nPos; 736 } 737 return sal_True; 738 } 739 return sal_False; 740 } 741 // ----------------------------------------------------------------------------- 742 void FormulaCompiler::fillAddInToken(::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,bool /*_bIsEnglish*/) const 743 { 744 } 745 // ----------------------------------------------------------------------------- 746 sal_Bool FormulaCompiler::IsMatrixFunction(OpCode _eOpCode) 747 { 748 switch ( _eOpCode ) 749 { 750 case ocDde : 751 case ocGrowth : 752 case ocTrend : 753 case ocRKP : 754 case ocRGP : 755 case ocFrequency : 756 case ocMatTrans : 757 case ocMatMult : 758 case ocMatInv : 759 case ocMatrixUnit : 760 return sal_True; 761 default: 762 { 763 // added to avoid warnings 764 } 765 } 766 return sal_False; 767 } 768 769 // ----------------------------------------------------------------------------- 770 FormulaCompiler::OpCodeMap::~OpCodeMap() 771 { 772 delete mpReverseExternalHashMap; 773 delete mpExternalHashMap; 774 delete [] mpTable; 775 delete mpHashMap; 776 } 777 // ----------------------------------------------------------------------------- 778 sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown() 779 { 780 static const sal_Int32 kOpCodeUnknown = -1; 781 return kOpCodeUnknown; 782 } 783 // ----------------------------------------------------------------------------- 784 sal_Bool FormulaCompiler::GetToken() 785 { 786 static const short nRecursionMax = 42; 787 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion ); 788 if ( nRecursion > nRecursionMax ) 789 { 790 SetError( errStackOverflow ); 791 pToken = new FormulaByteToken( ocStop ); 792 return sal_False; 793 } 794 if ( bAutoCorrect && !pStack ) 795 { // #61426# don't merge stacked subroutine code into entered formula 796 aCorrectedFormula += aCorrectedSymbol; 797 aCorrectedSymbol.Erase(); 798 } 799 sal_Bool bStop = sal_False; 800 if( pArr->GetCodeError() && !bIgnoreErrors ) 801 bStop = sal_True; 802 else 803 { 804 short nWasColRowName; 805 if ( pArr->nIndex 806 && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName ) 807 nWasColRowName = 1; 808 else 809 nWasColRowName = 0; 810 pToken = pArr->Next(); 811 while( pToken && pToken->GetOpCode() == ocSpaces ) 812 { 813 if ( nWasColRowName ) 814 nWasColRowName++; 815 if ( bAutoCorrect && !pStack ) 816 CreateStringFromToken( aCorrectedFormula, pToken, sal_False ); 817 pToken = pArr->Next(); 818 } 819 if ( bAutoCorrect && !pStack && pToken ) 820 CreateStringFromToken( aCorrectedSymbol, pToken, sal_False ); 821 if( !pToken ) 822 { 823 if( pStack ) 824 { 825 PopTokenArray(); 826 return GetToken(); 827 } 828 else 829 bStop = sal_True; 830 } 831 else 832 { 833 if ( nWasColRowName >= 2 && pToken->GetOpCode() == ocColRowName ) 834 { // convert an ocSpaces to ocIntersect in RPN 835 pToken = new FormulaByteToken( ocIntersect ); 836 pArr->nIndex--; // we advanced to the second ocColRowName, step back 837 } 838 } 839 } 840 if( bStop ) 841 { 842 pToken = new FormulaByteToken( ocStop ); 843 return sal_False; 844 } 845 if( pToken->GetOpCode() == ocSubTotal ) 846 glSubTotal = sal_True; 847 else if ( pToken->GetOpCode() == ocExternalRef ) 848 { 849 return HandleExternalReference(*pToken); 850 } 851 else if( pToken->GetOpCode() == ocName ) 852 { 853 return HandleRange(); 854 } 855 else if( pToken->GetOpCode() == ocColRowName ) 856 { 857 return HandleSingleRef(); 858 } 859 else if( pToken->GetOpCode() == ocDBArea ) 860 { 861 return HandleDbData(); 862 } 863 else if( pToken->GetType() == svSingleRef ) 864 { 865 pArr->nRefs++; 866 } 867 else if( pToken->GetType() == svDoubleRef ) 868 { 869 pArr->nRefs++; 870 } 871 return sal_True; 872 } 873 //--------------------------------------------------------------------------- 874 // RPN creation by recursion 875 //--------------------------------------------------------------------------- 876 877 void FormulaCompiler::Factor() 878 { 879 if ( pArr->GetCodeError() && !bIgnoreErrors ) 880 return; 881 882 CurrentFactor pFacToken( this ); 883 884 OpCode eOp = pToken->GetOpCode(); 885 if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef || 886 eOp == ocDBArea 887 || (bCompileForFAP && ((eOp == ocName) || (eOp == ocDBArea) 888 || (eOp == ocColRowName) || (eOp == ocBad))) 889 ) 890 { 891 PutCode( pToken ); 892 eOp = NextToken(); 893 if( eOp == ocOpen ) 894 { 895 // PUSH( is an error that may be caused by an unknown function. 896 SetError( 897 ( pToken->GetType() == svString 898 || pToken->GetType() == svSingleRef ) 899 ? errNoName : errOperatorExpected ); 900 if ( bAutoCorrect && !pStack ) 901 { // assume multiplication 902 aCorrectedFormula += mxSymbols->getSymbol(ocMul); 903 bCorrected = sal_True; 904 NextToken(); 905 eOp = Expression(); 906 if( eOp != ocClose ) 907 SetError(errPairExpected); 908 else 909 eOp = NextToken(); 910 } 911 } 912 } 913 else if( eOp == ocOpen ) 914 { 915 NextToken(); 916 eOp = Expression(); 917 while ((eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors)) 918 { // range list (A1;A2) converted to (A1~A2) 919 pFacToken = pToken; 920 NextToken(); 921 eOp = Expression(); 922 // Do not ignore error here, regardless of bIgnoreErrors, otherwise 923 // errors like =(1;) would also result in display of =(1~) 924 if (!pArr->GetCodeError()) 925 { 926 pFacToken->NewOpCode( ocUnion,FormulaToken::PrivateAccess()); 927 PutCode( pFacToken); 928 } 929 } 930 if (eOp != ocClose) 931 SetError(errPairExpected); 932 else 933 eOp = NextToken(); 934 } 935 else 936 { 937 if( nNumFmt == NUMBERFORMAT_UNDEFINED ) 938 nNumFmt = lcl_GetRetFormat( eOp ); 939 // Functions that have to be always recalculated 940 switch( eOp ) 941 { 942 // no parameters: 943 case ocRandom: 944 case ocGetActDate: 945 case ocGetActTime: 946 // one parameter: 947 case ocFormula: 948 case ocInfo: 949 // more than one parameters: 950 // ocIndirect/ocIndirectXL otherwise would have to do 951 // StopListening and StartListening on a reference for every 952 // interpreted value. 953 case ocIndirect: 954 case ocIndirectXL: 955 // ocOffset results in indirect references. 956 case ocOffset: 957 pArr->SetRecalcModeAlways(); 958 break; 959 // Functions recalculated on every document load. 960 // Don't use SetRecalcModeOnLoad() which would override 961 // ModeAlways. 962 case ocConvert : 963 pArr->AddRecalcMode( RECALCMODE_ONLOAD ); 964 break; 965 // If the referred cell is moved the value changes. 966 case ocColumn : 967 case ocRow : 968 // ocCell needs recalc on move for some possible type values. 969 case ocCell : 970 pArr->SetRecalcModeOnRefMove(); 971 break; 972 case ocHyperLink : 973 pArr->SetHyperLink(sal_True); 974 break; 975 default: 976 ; // nothing 977 } 978 if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR) 979 { 980 pFacToken = pToken; 981 eOp = NextToken(); 982 if (eOp != ocOpen) 983 { 984 SetError(errPairExpected); 985 PutCode( pFacToken ); 986 } 987 else 988 { 989 eOp = NextToken(); 990 if (eOp != ocClose) 991 SetError(errPairExpected); 992 PutCode(pFacToken); 993 eOp = NextToken(); 994 } 995 } 996 // special cases NOT() and NEG() 997 else if( eOp == ocNot || eOp == ocNeg 998 || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) ) 999 { 1000 pFacToken = pToken; 1001 eOp = NextToken(); 1002 if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot ) 1003 nNumFmt = NUMBERFORMAT_LOGICAL; 1004 if (eOp == ocOpen) 1005 { 1006 NextToken(); 1007 eOp = Expression(); 1008 } 1009 else 1010 SetError(errPairExpected); 1011 if (eOp != ocClose) 1012 SetError(errPairExpected); 1013 else if ( !pArr->GetCodeError() ) 1014 pFacToken->SetByte( 1 ); 1015 PutCode( pFacToken ); 1016 eOp = NextToken(); 1017 } 1018 else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR) 1019 || eOp == ocExternal 1020 || eOp == ocMacro 1021 || eOp == ocAnd 1022 || eOp == ocOr 1023 || eOp == ocBad 1024 || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd ) 1025 || (bCompileForFAP && ((eOp == ocIf) || (eOp == ocChose))) 1026 ) 1027 { 1028 pFacToken = pToken; 1029 OpCode eMyLastOp = eOp; 1030 eOp = NextToken(); 1031 bool bNoParam = false; 1032 bool bBadName = false; 1033 if (eOp == ocOpen) 1034 { 1035 eOp = NextToken(); 1036 if (eOp == ocClose) 1037 bNoParam = true; 1038 else 1039 eOp = Expression(); 1040 } 1041 else if (eMyLastOp == ocBad) 1042 { 1043 // Just a bad name, not an unknown function, no parameters, no 1044 // closing expected. 1045 bBadName = true; 1046 bNoParam = true; 1047 } 1048 else 1049 SetError(errPairExpected); 1050 sal_uInt8 nSepCount = 0; 1051 if( !bNoParam ) 1052 { 1053 nSepCount++; 1054 while ( (eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors) ) 1055 { 1056 nSepCount++; 1057 NextToken(); 1058 eOp = Expression(); 1059 } 1060 } 1061 if (bBadName) 1062 ; // nothing, keep current token for return 1063 else if (eOp != ocClose) 1064 SetError(errPairExpected); 1065 else 1066 eOp = NextToken(); 1067 // Jumps are just normal functions for the FunctionAutoPilot tree view 1068 if ( bCompileForFAP && pFacToken->GetType() == svJump ) 1069 pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken ); 1070 else 1071 pFacToken->SetByte( nSepCount ); 1072 PutCode( pFacToken ); 1073 } 1074 else if (eOp == ocIf || eOp == ocChose) 1075 { 1076 // the PC counters are -1 1077 pFacToken = pToken; 1078 if ( eOp == ocIf ) 1079 pFacToken->GetJump()[ 0 ] = 3; // if, else, behind 1080 else 1081 pFacToken->GetJump()[ 0 ] = MAXJUMPCOUNT+1; 1082 eOp = NextToken(); 1083 if (eOp == ocOpen) 1084 { 1085 NextToken(); 1086 eOp = Expression(); 1087 } 1088 else 1089 SetError(errPairExpected); 1090 short nJumpCount = 0; 1091 PutCode( pFacToken ); 1092 // #36253# during AutoCorrect (since pArr->GetCodeError() is 1093 // ignored) an unlimited ocIf would crash because 1094 // ScRawToken::Clone() allocates the JumpBuffer according to 1095 // nJump[0]*2+2, which is 3*2+2 on ocIf. 1096 const short nJumpMax = 1097 (pFacToken->GetOpCode() == ocIf ? 3 : MAXJUMPCOUNT); 1098 while ( (nJumpCount < (MAXJUMPCOUNT - 1)) && (eOp == ocSep) 1099 && (!pArr->GetCodeError() || bIgnoreErrors) ) 1100 { 1101 if ( ++nJumpCount <= nJumpMax ) 1102 pFacToken->GetJump()[nJumpCount] = pc-1; 1103 NextToken(); 1104 eOp = Expression(); 1105 // ocSep or ocClose terminate the subexpression 1106 PutCode( pToken ); 1107 } 1108 if (eOp != ocClose) 1109 SetError(errPairExpected); 1110 else 1111 { 1112 eOp = NextToken(); 1113 // always limit to nJumpMax, no arbitrary overwrites 1114 if ( ++nJumpCount <= nJumpMax ) 1115 pFacToken->GetJump()[ nJumpCount ] = pc-1; 1116 if ((pFacToken->GetOpCode() == ocIf && (nJumpCount > 3)) || 1117 (nJumpCount >= MAXJUMPCOUNT)) 1118 SetError(errIllegalParameter); 1119 else 1120 pFacToken->GetJump()[ 0 ] = nJumpCount; 1121 } 1122 } 1123 else if ( eOp == ocMissing ) 1124 { 1125 PutCode( pToken ); 1126 eOp = NextToken(); 1127 } 1128 else if ( eOp == ocClose ) 1129 { 1130 SetError( errParameterExpected ); 1131 } 1132 else if ( eOp == ocSep ) 1133 { // Subsequent ocSep 1134 SetError( errParameterExpected ); 1135 if ( bAutoCorrect && !pStack ) 1136 { 1137 aCorrectedSymbol.Erase(); 1138 bCorrected = sal_True; 1139 } 1140 } 1141 else if ( eOp == ocExternalRef ) 1142 { 1143 PutCode(pToken); 1144 eOp = NextToken(); 1145 } 1146 else 1147 { 1148 SetError( errUnknownToken ); 1149 if ( bAutoCorrect && !pStack ) 1150 { 1151 if ( eOp == ocStop ) 1152 { // trailing operator w/o operand 1153 xub_StrLen nLen = aCorrectedFormula.Len(); 1154 if ( nLen ) 1155 aCorrectedFormula.Erase( nLen - 1 ); 1156 aCorrectedSymbol.Erase(); 1157 bCorrected = sal_True; 1158 } 1159 } 1160 } 1161 } 1162 } 1163 1164 //--------------------------------------------------------------------------- 1165 1166 void FormulaCompiler::RangeLine() 1167 { 1168 Factor(); 1169 while (pToken->GetOpCode() == ocRange) 1170 { 1171 FormulaToken** pCode1 = pCode - 1; 1172 FormulaTokenRef p = pToken; 1173 NextToken(); 1174 Factor(); 1175 FormulaToken** pCode2 = pCode - 1; 1176 if (!MergeRangeReference( pCode1, pCode2)) 1177 PutCode(p); 1178 } 1179 } 1180 1181 //--------------------------------------------------------------------------- 1182 1183 void FormulaCompiler::IntersectionLine() 1184 { 1185 RangeLine(); 1186 while (pToken->GetOpCode() == ocIntersect) 1187 { 1188 FormulaTokenRef p = pToken; 1189 NextToken(); 1190 RangeLine(); 1191 PutCode(p); 1192 } 1193 } 1194 1195 //--------------------------------------------------------------------------- 1196 1197 void FormulaCompiler::UnionLine() 1198 { 1199 IntersectionLine(); 1200 while (pToken->GetOpCode() == ocUnion) 1201 { 1202 FormulaTokenRef p = pToken; 1203 NextToken(); 1204 IntersectionLine(); 1205 PutCode(p); 1206 } 1207 } 1208 1209 //--------------------------------------------------------------------------- 1210 1211 void FormulaCompiler::UnaryLine() 1212 { 1213 if( pToken->GetOpCode() == ocAdd ) 1214 GetToken(); 1215 else if (SC_OPCODE_START_UN_OP <= pToken->GetOpCode() && 1216 pToken->GetOpCode() < SC_OPCODE_STOP_UN_OP) 1217 { 1218 FormulaTokenRef p = pToken; 1219 NextToken(); 1220 UnaryLine(); 1221 PutCode( p ); 1222 } 1223 else 1224 UnionLine(); 1225 } 1226 1227 //--------------------------------------------------------------------------- 1228 1229 void FormulaCompiler::PostOpLine() 1230 { 1231 UnaryLine(); 1232 while ( pToken->GetOpCode() == ocPercentSign ) 1233 { // this operator _follows_ its operand 1234 PutCode( pToken ); 1235 NextToken(); 1236 } 1237 } 1238 1239 //--------------------------------------------------------------------------- 1240 1241 void FormulaCompiler::PowLine() 1242 { 1243 PostOpLine(); 1244 while (pToken->GetOpCode() == ocPow) 1245 { 1246 FormulaTokenRef p = pToken; 1247 NextToken(); 1248 PostOpLine(); 1249 PutCode(p); 1250 } 1251 } 1252 1253 //--------------------------------------------------------------------------- 1254 1255 void FormulaCompiler::MulDivLine() 1256 { 1257 PowLine(); 1258 while (pToken->GetOpCode() == ocMul || pToken->GetOpCode() == ocDiv) 1259 { 1260 FormulaTokenRef p = pToken; 1261 NextToken(); 1262 PowLine(); 1263 PutCode(p); 1264 } 1265 } 1266 1267 //--------------------------------------------------------------------------- 1268 1269 void FormulaCompiler::AddSubLine() 1270 { 1271 MulDivLine(); 1272 while (pToken->GetOpCode() == ocAdd || pToken->GetOpCode() == ocSub) 1273 { 1274 FormulaTokenRef p = pToken; 1275 NextToken(); 1276 MulDivLine(); 1277 PutCode(p); 1278 } 1279 } 1280 1281 //--------------------------------------------------------------------------- 1282 1283 void FormulaCompiler::ConcatLine() 1284 { 1285 AddSubLine(); 1286 while (pToken->GetOpCode() == ocAmpersand) 1287 { 1288 FormulaTokenRef p = pToken; 1289 NextToken(); 1290 AddSubLine(); 1291 PutCode(p); 1292 } 1293 } 1294 1295 //--------------------------------------------------------------------------- 1296 1297 void FormulaCompiler::CompareLine() 1298 { 1299 ConcatLine(); 1300 while (pToken->GetOpCode() >= ocEqual && pToken->GetOpCode() <= ocGreaterEqual) 1301 { 1302 FormulaTokenRef p = pToken; 1303 NextToken(); 1304 ConcatLine(); 1305 PutCode(p); 1306 } 1307 } 1308 1309 //--------------------------------------------------------------------------- 1310 1311 void FormulaCompiler::NotLine() 1312 { 1313 CompareLine(); 1314 while (pToken->GetOpCode() == ocNot) 1315 { 1316 FormulaTokenRef p = pToken; 1317 NextToken(); 1318 CompareLine(); 1319 PutCode(p); 1320 } 1321 } 1322 1323 //--------------------------------------------------------------------------- 1324 1325 OpCode FormulaCompiler::Expression() 1326 { 1327 static const short nRecursionMax = 42; 1328 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion ); 1329 if ( nRecursion > nRecursionMax ) 1330 { 1331 SetError( errStackOverflow ); 1332 return ocStop; //! generate token instead? 1333 } 1334 NotLine(); 1335 while (pToken->GetOpCode() == ocAnd || pToken->GetOpCode() == ocOr) 1336 { 1337 FormulaTokenRef p = pToken; 1338 pToken->SetByte( 2 ); // 2 parameters! 1339 NextToken(); 1340 NotLine(); 1341 PutCode(p); 1342 } 1343 return pToken->GetOpCode(); 1344 } 1345 // ----------------------------------------------------------------------------- 1346 void FormulaCompiler::SetError(sal_uInt16 /*nError*/) 1347 { 1348 } 1349 // ----------------------------------------------------------------------------- 1350 FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/, bool /*bReuseDoubleRef*/ ) 1351 { 1352 return FormulaTokenRef(); 1353 } 1354 // ----------------------------------------------------------------------------- 1355 bool FormulaCompiler::MergeRangeReference(FormulaToken * * const pCode1, FormulaToken * const * const pCode2 ) 1356 { 1357 FormulaToken *p1, *p2; 1358 if (pc < 2 || !pCode1 || !pCode2 || 1359 (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) || 1360 ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) ) 1361 return false; 1362 1363 FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true); 1364 if (!p) 1365 return false; 1366 1367 p->IncRef(); 1368 p1->DecRef(); 1369 p2->DecRef(); 1370 *pCode1 = p; 1371 --pCode, --pc; 1372 pArr->nRefs--; 1373 1374 return true; 1375 } 1376 // ----------------------------------------------------------------------------- 1377 sal_Bool FormulaCompiler::CompileTokenArray() 1378 { 1379 glSubTotal = sal_False; 1380 bCorrected = sal_False; 1381 if( !pArr->GetCodeError() || bIgnoreErrors ) 1382 { 1383 if ( bAutoCorrect ) 1384 { 1385 aCorrectedFormula.Erase(); 1386 aCorrectedSymbol.Erase(); 1387 } 1388 pArr->nRefs = 0; // count from start 1389 pArr->DelRPN(); 1390 pStack = NULL; 1391 FormulaToken* pData[ MAXCODE ]; 1392 pCode = pData; 1393 sal_Bool bWasForced = pArr->IsRecalcModeForced(); 1394 if ( bWasForced ) 1395 { 1396 if ( bAutoCorrect ) 1397 aCorrectedFormula = '='; 1398 } 1399 pArr->ClearRecalcMode(); 1400 pArr->Reset(); 1401 eLastOp = ocOpen; 1402 pc = 0; 1403 NextToken(); 1404 OpCode eOp = Expression(); 1405 // Some trailing garbage that doesn't form an expression? 1406 if (eOp != ocStop) 1407 SetError( errOperatorExpected); 1408 1409 sal_uInt16 nErrorBeforePop = pArr->GetCodeError(); 1410 1411 while( pStack ) 1412 PopTokenArray(); 1413 if( pc ) 1414 { 1415 pArr->pRPN = new FormulaToken*[ pc ]; 1416 pArr->nRPN = pc; 1417 memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) ); 1418 } 1419 1420 // once an error, always an error 1421 if( !pArr->GetCodeError() && nErrorBeforePop ) 1422 pArr->SetCodeError( nErrorBeforePop); 1423 1424 if( pArr->GetCodeError() && !bIgnoreErrors ) 1425 { 1426 pArr->DelRPN(); 1427 pArr->SetHyperLink(sal_False); 1428 } 1429 1430 if ( bWasForced ) 1431 pArr->SetRecalcModeForced(); 1432 } 1433 if( nNumFmt == NUMBERFORMAT_UNDEFINED ) 1434 nNumFmt = NUMBERFORMAT_NUMBER; 1435 return glSubTotal; 1436 } 1437 // ----------------------------------------------------------------------------- 1438 void FormulaCompiler::PopTokenArray() 1439 { 1440 if( pStack ) 1441 { 1442 FormulaArrayStack* p = pStack; 1443 pStack = p->pNext; 1444 p->pArr->nRefs = sal::static_int_cast<short>( p->pArr->nRefs + pArr->nRefs ); 1445 // obtain special RecalcMode from SharedFormula 1446 if ( pArr->IsRecalcModeAlways() ) 1447 p->pArr->SetRecalcModeAlways(); 1448 else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() ) 1449 p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() ); 1450 p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() ); 1451 if( p->bTemp ) 1452 delete pArr; 1453 pArr = p->pArr; 1454 delete p; 1455 } 1456 } 1457 // ----------------------------------------------------------------------------- 1458 void FormulaCompiler::CreateStringFromTokenArray( String& rFormula ) 1459 { 1460 rtl::OUStringBuffer aBuffer( pArr->GetLen() * 5 ); 1461 CreateStringFromTokenArray( aBuffer ); 1462 rFormula = aBuffer; 1463 } 1464 1465 void FormulaCompiler::CreateStringFromTokenArray( rtl::OUStringBuffer& rBuffer ) 1466 { 1467 rBuffer.setLength(0); 1468 if( !pArr->GetLen() ) 1469 return; 1470 1471 FormulaTokenArray* pSaveArr = pArr; 1472 bool bODFF = FormulaGrammar::isODFF( meGrammar); 1473 if (bODFF || FormulaGrammar::isPODF( meGrammar) ) 1474 { 1475 // Scan token array for missing args and re-write if present. 1476 MissingConvention aConv( bODFF); 1477 if (pArr->NeedsPofRewrite( aConv)) 1478 pArr = pArr->RewriteMissingToPof( aConv); 1479 } 1480 1481 // At least one character per token, plus some are references, some are 1482 // function names, some are numbers, ... 1483 rBuffer.ensureCapacity( pArr->GetLen() * 5 ); 1484 1485 if ( pArr->IsRecalcModeForced() ) 1486 rBuffer.append(sal_Unicode('=')); 1487 FormulaToken* t = pArr->First(); 1488 while( t ) 1489 t = CreateStringFromToken( rBuffer, t, sal_True ); 1490 1491 if (pSaveArr != pArr) 1492 { 1493 delete pArr; 1494 pArr = pSaveArr; 1495 } 1496 } 1497 // ----------------------------------------------------------------------------- 1498 FormulaToken* FormulaCompiler::CreateStringFromToken( String& rFormula, FormulaToken* pTokenP,sal_Bool bAllowArrAdvance ) 1499 { 1500 rtl::OUStringBuffer aBuffer; 1501 FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance ); 1502 rFormula += aBuffer; 1503 return p; 1504 } 1505 1506 FormulaToken* FormulaCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP,sal_Bool bAllowArrAdvance ) 1507 { 1508 sal_Bool bNext = sal_True; 1509 sal_Bool bSpaces = sal_False; 1510 FormulaToken* t = pTokenP; 1511 OpCode eOp = t->GetOpCode(); 1512 if( eOp >= ocAnd && eOp <= ocOr ) 1513 { 1514 // AND, OR infix? 1515 if ( bAllowArrAdvance ) 1516 t = pArr->Next(); 1517 else 1518 t = pArr->PeekNext(); 1519 bNext = sal_False; 1520 bSpaces = ( !t || t->GetOpCode() != ocOpen ); 1521 } 1522 if( bSpaces ) 1523 rBuffer.append(sal_Unicode(' ')); 1524 1525 if( eOp == ocSpaces ) 1526 { 1527 bool bIntersectionOp = mxSymbols->isODFF(); 1528 if (bIntersectionOp) 1529 { 1530 const FormulaToken* p = pArr->PeekPrevNoSpaces(); 1531 bIntersectionOp = (p && p->GetOpCode() == ocColRowName); 1532 if (bIntersectionOp) 1533 { 1534 p = pArr->PeekNextNoSpaces(); 1535 bIntersectionOp = (p && p->GetOpCode() == ocColRowName); 1536 } 1537 } 1538 if (bIntersectionOp) 1539 rBuffer.appendAscii( "!!"); 1540 else 1541 { 1542 // most times it's just one blank 1543 sal_uInt8 n = t->GetByte(); 1544 for ( sal_uInt8 j=0; j<n; ++j ) 1545 { 1546 rBuffer.append(sal_Unicode(' ')); 1547 } 1548 } 1549 } 1550 else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd ) 1551 rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] ); 1552 else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount()) // Keyword: 1553 rBuffer.append(mxSymbols->getSymbol(eOp)); 1554 else 1555 { 1556 DBG_ERRORFILE("unknown OpCode"); 1557 rBuffer.append(GetNativeSymbol( ocErrName )); 1558 } 1559 if( bNext ) 1560 { 1561 if (eOp == ocExternalRef) 1562 { 1563 CreateStringFromExternal(rBuffer, pTokenP); 1564 } 1565 else 1566 { 1567 switch( t->GetType() ) 1568 { 1569 case svDouble: 1570 AppendDouble( rBuffer, t->GetDouble() ); 1571 break; 1572 1573 case svString: 1574 if( eOp == ocBad ) 1575 rBuffer.append(t->GetString()); 1576 else 1577 AppendString( rBuffer, t->GetString() ); 1578 break; 1579 case svSingleRef: 1580 CreateStringFromSingleRef(rBuffer,t); 1581 break; 1582 case svDoubleRef: 1583 CreateStringFromDoubleRef(rBuffer,t); 1584 break; 1585 case svMatrix: 1586 CreateStringFromMatrix( rBuffer, t ); 1587 break; 1588 1589 case svIndex: 1590 CreateStringFromIndex( rBuffer, t ); 1591 break; 1592 case svExternal: 1593 { 1594 // mapped or translated name of AddIns 1595 String aAddIn( t->GetExternal() ); 1596 bool bMapped = mxSymbols->isPODF(); // ODF 1.1 directly uses programmatical name 1597 if (!bMapped && mxSymbols->hasExternals()) 1598 { 1599 ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn); 1600 if (iLook != mxSymbols->getReverseExternalHashMap()->end()) 1601 { 1602 aAddIn = (*iLook).second; 1603 bMapped = true; 1604 } 1605 } 1606 if (!bMapped && !mxSymbols->isEnglish()) 1607 LocalizeString( aAddIn ); 1608 rBuffer.append(aAddIn); 1609 } 1610 break; 1611 case svByte: 1612 case svJump: 1613 case svFAP: 1614 case svMissing: 1615 case svSep: 1616 break; // Opcodes 1617 default: 1618 DBG_ERROR("FormulaCompiler:: GetStringFromToken errUnknownVariable"); 1619 } // of switch 1620 } 1621 } 1622 if( bSpaces ) 1623 rBuffer.append(sal_Unicode(' ')); 1624 if ( bAllowArrAdvance ) 1625 { 1626 if( bNext ) 1627 t = pArr->Next(); 1628 return t; 1629 } 1630 return pTokenP; 1631 } 1632 // ----------------------------------------------------------------------------- 1633 1634 void FormulaCompiler::AppendDouble( rtl::OUStringBuffer& rBuffer, double fVal ) 1635 { 1636 if ( mxSymbols->isEnglish() ) 1637 { 1638 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal, 1639 rtl_math_StringFormat_Automatic, 1640 rtl_math_DecimalPlaces_Max, '.', sal_True ); 1641 } 1642 else 1643 { 1644 SvtSysLocale aSysLocale; 1645 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal, 1646 rtl_math_StringFormat_Automatic, 1647 rtl_math_DecimalPlaces_Max, 1648 aSysLocale.GetLocaleDataPtr()->getNumDecimalSep().GetChar(0), 1649 sal_True ); 1650 } 1651 } 1652 // ----------------------------------------------------------------------------- 1653 void FormulaCompiler::AppendBoolean( rtl::OUStringBuffer& rBuffer, bool bVal ) 1654 { 1655 rBuffer.append( mxSymbols->getSymbol(static_cast<OpCode>(bVal ? ocTrue : ocFalse)) ); 1656 } 1657 // ----------------------------------------------------------------------------- 1658 sal_Bool FormulaCompiler::IsImportingXML() const 1659 { 1660 return sal_False; 1661 } 1662 // ----------------------------------------------------------------------------- 1663 void FormulaCompiler::AppendString( rtl::OUStringBuffer& rBuffer, const String & rStr ) 1664 { 1665 if (IsImportingXML()) 1666 rBuffer.append( rStr ); 1667 else 1668 { 1669 rBuffer.append(sal_Unicode('"')); 1670 if ( lcl_UnicodeStrChr( rStr.GetBuffer(), '"' ) == NULL ) 1671 rBuffer.append( rStr ); 1672 else 1673 { 1674 String aStr( rStr ); 1675 aStr.SearchAndReplaceAll( '"', String( RTL_CONSTASCII_USTRINGPARAM( "\"\""))); 1676 rBuffer.append(aStr); 1677 } 1678 rBuffer.append(sal_Unicode('"')); 1679 } 1680 } 1681 // ----------------------------------------------------------------------------- 1682 OpCode FormulaCompiler::NextToken() 1683 { 1684 if( !GetToken() ) 1685 return ocStop; 1686 OpCode eOp = pToken->GetOpCode(); 1687 // There must be an operator before a push 1688 if ( (eOp == ocPush || eOp == ocColRowNameAuto) && 1689 !( (eLastOp == ocOpen) || (eLastOp == ocSep) || 1690 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) ) 1691 SetError(errOperatorExpected); 1692 // Operator and Plus => operator 1693 if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep || 1694 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP))) 1695 eOp = NextToken(); 1696 else 1697 { 1698 // Before an operator there must not be another operator, with the 1699 // exception of AND and OR. 1700 if ( eOp != ocAnd && eOp != ocOr && 1701 (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP ) 1702 && (eLastOp == ocOpen || eLastOp == ocSep || 1703 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP))) 1704 { 1705 SetError(errVariableExpected); 1706 if ( bAutoCorrect && !pStack ) 1707 { 1708 if ( eOp == eLastOp || eLastOp == ocOpen ) 1709 { // throw away duplicated operator 1710 aCorrectedSymbol.Erase(); 1711 bCorrected = sal_True; 1712 } 1713 else 1714 { 1715 xub_StrLen nPos = aCorrectedFormula.Len(); 1716 if ( nPos ) 1717 { 1718 nPos--; 1719 sal_Unicode c = aCorrectedFormula.GetChar( nPos ); 1720 switch ( eOp ) 1721 { // swap operators 1722 case ocGreater: 1723 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) ) 1724 { // >= instead of => 1725 aCorrectedFormula.SetChar( nPos, 1726 mxSymbols->getSymbol(ocGreater).GetChar(0) ); 1727 aCorrectedSymbol = c; 1728 bCorrected = sal_True; 1729 } 1730 break; 1731 case ocLess: 1732 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) ) 1733 { // <= instead of =< 1734 aCorrectedFormula.SetChar( nPos, 1735 mxSymbols->getSymbol(ocLess).GetChar(0) ); 1736 aCorrectedSymbol = c; 1737 bCorrected = sal_True; 1738 } 1739 else if ( c == mxSymbols->getSymbol(ocGreater).GetChar(0) ) 1740 { // <> instead of >< 1741 aCorrectedFormula.SetChar( nPos, 1742 mxSymbols->getSymbol(ocLess).GetChar(0) ); 1743 aCorrectedSymbol = c; 1744 bCorrected = sal_True; 1745 } 1746 break; 1747 case ocMul: 1748 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) ) 1749 { // *- instead of -* 1750 aCorrectedFormula.SetChar( nPos, 1751 mxSymbols->getSymbol(ocMul).GetChar(0) ); 1752 aCorrectedSymbol = c; 1753 bCorrected = sal_True; 1754 } 1755 break; 1756 case ocDiv: 1757 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) ) 1758 { // /- instead of -/ 1759 aCorrectedFormula.SetChar( nPos, 1760 mxSymbols->getSymbol(ocDiv).GetChar(0) ); 1761 aCorrectedSymbol = c; 1762 bCorrected = sal_True; 1763 } 1764 break; 1765 default: 1766 ; // nothing 1767 } 1768 } 1769 } 1770 } 1771 } 1772 eLastOp = eOp; 1773 } 1774 return eOp; 1775 } 1776 void FormulaCompiler::PutCode( FormulaTokenRef& p ) 1777 { 1778 if( pc >= MAXCODE-1 ) 1779 { 1780 if ( pc == MAXCODE-1 ) 1781 { 1782 p = new FormulaByteToken( ocStop ); 1783 p->IncRef(); 1784 *pCode++ = p; 1785 ++pc; 1786 } 1787 SetError(errCodeOverflow); 1788 return; 1789 } 1790 if( pArr->GetCodeError() && !bCompileForFAP ) 1791 return; 1792 ForceArrayOperator( p, pCurrentFactorToken); 1793 p->IncRef(); 1794 *pCode++ = p; 1795 pc++; 1796 } 1797 1798 // ----------------------------------------------------------------------------- 1799 sal_Bool FormulaCompiler::HandleExternalReference(const FormulaToken& /*_aToken*/) 1800 { 1801 return sal_True; 1802 } 1803 // ----------------------------------------------------------------------------- 1804 sal_Bool FormulaCompiler::HandleRange() 1805 { 1806 return sal_True; 1807 } 1808 // ----------------------------------------------------------------------------- 1809 sal_Bool FormulaCompiler::HandleSingleRef() 1810 { 1811 return sal_True; 1812 } 1813 // ----------------------------------------------------------------------------- 1814 sal_Bool FormulaCompiler::HandleDbData() 1815 { 1816 return sal_True; 1817 } 1818 // ----------------------------------------------------------------------------- 1819 void FormulaCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/) 1820 { 1821 } 1822 // ----------------------------------------------------------------------------- 1823 void FormulaCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/) 1824 { 1825 } 1826 // ----------------------------------------------------------------------------- 1827 void FormulaCompiler::CreateStringFromIndex(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/) 1828 { 1829 } 1830 // ----------------------------------------------------------------------------- 1831 void FormulaCompiler::CreateStringFromMatrix(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/) 1832 { 1833 } 1834 // ----------------------------------------------------------------------------- 1835 void FormulaCompiler::CreateStringFromExternal(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/) 1836 { 1837 } 1838 // ----------------------------------------------------------------------------- 1839 void FormulaCompiler::LocalizeString( String& /*rName*/ ) 1840 { 1841 } 1842 void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, sal_Bool bTemp ) 1843 { 1844 if ( bAutoCorrect && !pStack ) 1845 { // #61426# don't merge stacked subroutine code into entered formula 1846 aCorrectedFormula += aCorrectedSymbol; 1847 aCorrectedSymbol.Erase(); 1848 } 1849 FormulaArrayStack* p = new FormulaArrayStack; 1850 p->pNext = pStack; 1851 p->pArr = pArr; 1852 p->bTemp = bTemp; 1853 pStack = p; 1854 pArr = pa; 1855 } 1856 1857 // ============================================================================= 1858 } // formula 1859 // ============================================================================= 1860