1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 32 #include "parclass.hxx" 33 #include "token.hxx" 34 #include "global.hxx" 35 #include "callform.hxx" 36 #include "addincol.hxx" 37 #include "funcdesc.hxx" 38 #include <unotools/charclass.hxx> 39 #include <tools/debug.hxx> 40 #include <string.h> 41 42 #if OSL_DEBUG_LEVEL > 1 43 // the documentation thingy 44 #include <stdio.h> 45 #include <com/sun/star/sheet/FormulaLanguage.hpp> 46 #include "compiler.hxx" 47 #include "sc.hrc" // VAR_ARGS 48 #endif 49 50 51 /* Following assumptions are made: 52 * - OpCodes not specified at all will have at least one and only parameters of 53 * type Value, no check is done on the count of parameters => no Bounds type 54 * is returned. 55 * - For OpCodes with a variable number of parameters the type of the last 56 * parameter specified determines the type of all following parameters. 57 */ 58 59 const ScParameterClassification::RawData ScParameterClassification::pRawData[] = 60 { 61 // IF() and CHOOSE() are somewhat special, since the ScJumpMatrix is 62 // created inside those functions and ConvertMatrixParameters() is not 63 // called for them. 64 { ocIf, {{ Array, Reference, Reference }, false }}, 65 { ocChose, {{ Array, Reference }, true }}, 66 // Other specials. 67 { ocOpen, {{ Bounds }, false }}, 68 { ocClose, {{ Bounds }, false }}, 69 { ocSep, {{ Bounds }, false }}, 70 { ocNoName, {{ Bounds }, false }}, 71 { ocErrCell, {{ Bounds }, false }}, 72 { ocStop, {{ Bounds }, false }}, 73 { ocUnion, {{ Reference, Reference }, false }}, 74 { ocRange, {{ Reference, Reference }, false }}, 75 // Functions with Value parameters only but not in resource. 76 { ocBackSolver, {{ Value, Value, Value }, false }}, 77 { ocTableOp, {{ Value, Value, Value, Value, Value }, false }}, 78 // Operators and functions. 79 { ocAdd, {{ Array, Array }, false }}, 80 { ocAmpersand, {{ Array, Array }, false }}, 81 { ocAnd, {{ Reference }, true }}, 82 { ocAreas, {{ Reference }, false }}, 83 { ocAveDev, {{ Reference }, true }}, 84 { ocAverage, {{ Reference }, true }}, 85 { ocAverageA, {{ Reference }, true }}, 86 { ocCell, {{ Value, Reference }, false }}, 87 { ocColumn, {{ Reference }, false }}, 88 { ocColumns, {{ Reference }, true }}, 89 { ocCorrel, {{ ForceArray, ForceArray }, false }}, 90 { ocCount, {{ Reference }, true }}, 91 { ocCount2, {{ Reference }, true }}, 92 { ocCountEmptyCells, {{ Reference }, false }}, 93 { ocCountIf, {{ Reference, Value }, false }}, 94 { ocCovar, {{ ForceArray, ForceArray }, false }}, 95 { ocDBAverage, {{ Reference, Reference, Reference }, false }}, 96 { ocDBCount, {{ Reference, Reference, Reference }, false }}, 97 { ocDBCount2, {{ Reference, Reference, Reference }, false }}, 98 { ocDBGet, {{ Reference, Reference, Reference }, false }}, 99 { ocDBMax, {{ Reference, Reference, Reference }, false }}, 100 { ocDBMin, {{ Reference, Reference, Reference }, false }}, 101 { ocDBProduct, {{ Reference, Reference, Reference }, false }}, 102 { ocDBStdDev, {{ Reference, Reference, Reference }, false }}, 103 { ocDBStdDevP, {{ Reference, Reference, Reference }, false }}, 104 { ocDBSum, {{ Reference, Reference, Reference }, false }}, 105 { ocDBVar, {{ Reference, Reference, Reference }, false }}, 106 { ocDBVarP, {{ Reference, Reference, Reference }, false }}, 107 { ocDevSq, {{ Reference }, true }}, 108 { ocDiv, {{ Array, Array }, false }}, 109 { ocEqual, {{ Array, Array }, false }}, 110 { ocForecast, {{ Value, ForceArray, ForceArray }, false }}, 111 { ocFrequency, {{ Reference, Reference }, false }}, 112 { ocFTest, {{ ForceArray, ForceArray }, false }}, 113 { ocGeoMean, {{ Reference }, true }}, 114 { ocGCD, {{ Reference }, true }}, 115 { ocGreater, {{ Array, Array }, false }}, 116 { ocGreaterEqual, {{ Array, Array }, false }}, 117 { ocGrowth, {{ Reference, Reference, Reference, Value }, false }}, 118 { ocHarMean, {{ Reference }, true }}, 119 { ocHLookup, {{ Value, Reference, Value, Value }, false }}, 120 { ocIRR, {{ Reference, Value }, false }}, 121 { ocIndex, {{ Reference, Value, Value, Value }, false }}, 122 { ocIntercept, {{ ForceArray, ForceArray }, false }}, 123 { ocIntersect, {{ Reference, Reference }, false }}, 124 { ocIsRef, {{ Reference }, false }}, 125 { ocLCM, {{ Reference }, true }}, 126 { ocKurt, {{ Reference }, true }}, 127 { ocLarge, {{ Reference, Value }, false }}, 128 { ocLess, {{ Array, Array }, false }}, 129 { ocLessEqual, {{ Array, Array }, false }}, 130 { ocLookup, {{ Value, ReferenceOrForceArray, ReferenceOrForceArray }, false }}, 131 { ocMatch, {{ Value, Reference, Reference }, false }}, 132 { ocMatDet, {{ ForceArray }, false }}, 133 { ocMatInv, {{ ForceArray }, false }}, 134 { ocMatMult, {{ ForceArray, ForceArray }, false }}, 135 { ocMatTrans, {{ Array }, false }}, // strange, but Xcl doesn't force MatTrans array 136 { ocMatValue, {{ Reference, Value, Value }, false }}, 137 { ocMax, {{ Reference }, true }}, 138 { ocMaxA, {{ Reference }, true }}, 139 { ocMedian, {{ Reference }, true }}, 140 { ocMin, {{ Reference }, true }}, 141 { ocMinA, {{ Reference }, true }}, 142 { ocMIRR, {{ Reference, Value, Value }, false }}, 143 { ocModalValue, {{ ForceArray }, true }}, 144 { ocMul, {{ Array, Array }, false }}, 145 { ocMultiArea, {{ Reference }, true }}, 146 { ocN, {{ Reference }, false }}, 147 { ocNPV, {{ Value, Reference }, true }}, 148 { ocNeg, {{ Array }, false }}, 149 { ocNegSub, {{ Array }, false }}, 150 { ocNot, {{ Array }, false }}, 151 { ocNotEqual, {{ Array, Array }, false }}, 152 { ocOffset, {{ Reference, Value, Value, Value, Value }, false }}, 153 { ocOr, {{ Reference }, true }}, 154 { ocPearson, {{ ForceArray, ForceArray }, false }}, 155 { ocPercentile, {{ Reference, Value }, false }}, 156 { ocPercentrank, {{ Reference, Value }, false }}, 157 { ocPow, {{ Array, Array }, false }}, 158 { ocPower, {{ Array, Array }, false }}, 159 { ocProb, {{ ForceArray, ForceArray, Value, Value }, false }}, 160 { ocProduct, {{ Reference }, true }}, 161 { ocQuartile, {{ Reference, Value }, false }}, 162 { ocRank, {{ Value, Reference, Value }, false }}, 163 { ocRGP, {{ Reference, Reference, Value, Value }, false }}, 164 { ocRKP, {{ Reference, Reference, Value, Value }, false }}, 165 { ocRow, {{ Reference }, false }}, 166 { ocRows, {{ Reference }, true }}, 167 { ocRSQ, {{ ForceArray, ForceArray }, false }}, 168 { ocSchiefe, {{ Reference }, true }}, 169 { ocSlope, {{ ForceArray, ForceArray }, false }}, 170 { ocSmall, {{ Reference, Value }, false }}, 171 { ocStDev, {{ Reference }, true }}, 172 { ocStDevA, {{ Reference }, true }}, 173 { ocStDevP, {{ Reference }, true }}, 174 { ocStDevPA, {{ Reference }, true }}, 175 { ocSTEYX, {{ ForceArray, ForceArray }, false }}, 176 { ocSub, {{ Array, Array }, false }}, 177 { ocSubTotal, {{ Value, Reference }, true }}, 178 { ocSum, {{ Reference }, true }}, 179 { ocSumIf, {{ Reference, Value, Reference }, false }}, 180 { ocSumProduct, {{ ForceArray }, true }}, 181 { ocSumSQ, {{ Reference }, true }}, 182 { ocSumX2MY2, {{ ForceArray, ForceArray }, false }}, 183 { ocSumX2DY2, {{ ForceArray, ForceArray }, false }}, 184 { ocSumXMY2, {{ ForceArray, ForceArray }, false }}, 185 { ocTable, {{ Reference }, false }}, 186 { ocTables, {{ Reference }, true }}, 187 { ocTrend, {{ Reference, Reference, Reference, Value }, false }}, 188 { ocTrimMean, {{ Reference, Value }, false }}, 189 { ocTTest, {{ ForceArray, ForceArray, Value, Value }, false }}, 190 { ocVar, {{ Reference }, true }}, 191 { ocVarA, {{ Reference }, true }}, 192 { ocVarP, {{ Reference }, true }}, 193 { ocVarPA, {{ Reference }, true }}, 194 { ocVLookup, {{ Value, Reference, Value, Value }, false }}, 195 { ocZTest, {{ Reference, Value, Value }, false }}, 196 // Excel doubts: 197 // ocT: Excel says (and handles) Reference, error? This means no position 198 // dependent SingleRef if DoubleRef, and no array calculation, just the 199 // upper left corner. We never did that. 200 { ocT, {{ Value }, false }}, 201 // The stopper. 202 { ocNone, {{ Bounds }, false } } 203 }; 204 205 ScParameterClassification::RunData * ScParameterClassification::pData = NULL; 206 207 208 void ScParameterClassification::Init() 209 { 210 if ( pData ) 211 return; 212 pData = new RunData[ SC_OPCODE_LAST_OPCODE_ID + 1 ]; 213 memset( pData, 0, sizeof(RunData) * (SC_OPCODE_LAST_OPCODE_ID + 1)); 214 215 // init from specified static data above 216 for ( size_t i=0; i < sizeof(pRawData) / sizeof(RawData); ++i ) 217 { 218 const RawData* pRaw = &pRawData[i]; 219 if ( pRaw->eOp > SC_OPCODE_LAST_OPCODE_ID ) 220 { 221 DBG_ASSERT( pRaw->eOp == ocNone, "RawData OpCode error"); 222 } 223 else 224 { 225 RunData* pRun = &pData[ pRaw->eOp ]; 226 #ifdef DBG_UTIL 227 if ( pRun->aData.nParam[0] != Unknown ) 228 { 229 DBG_ERROR1( "already assigned: %d", pRaw->eOp); 230 } 231 #endif 232 memcpy( &(pRun->aData), &(pRaw->aData), sizeof(CommonData)); 233 // fill 0-initialized fields with real values 234 if ( pRun->aData.bRepeatLast ) 235 { 236 Type eLast = Unknown; 237 for ( size_t j=0; j < CommonData::nMaxParams; ++j ) 238 { 239 if ( pRun->aData.nParam[j] ) 240 { 241 eLast = pRun->aData.nParam[j]; 242 pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j+1 ); 243 } 244 else 245 pRun->aData.nParam[j] = eLast; 246 } 247 } 248 else 249 { 250 for ( size_t j=0; j < CommonData::nMaxParams; ++j ) 251 { 252 if ( !pRun->aData.nParam[j] ) 253 { 254 if ( j == 0 || pRun->aData.nParam[j-1] != Bounds ) 255 pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j ); 256 pRun->aData.nParam[j] = Bounds; 257 } 258 } 259 if ( !pRun->nMinParams && 260 pRun->aData.nParam[CommonData::nMaxParams-1] != Bounds) 261 pRun->nMinParams = CommonData::nMaxParams; 262 } 263 for ( size_t j=0; j < CommonData::nMaxParams; ++j ) 264 { 265 if ( pRun->aData.nParam[j] == ForceArray || pRun->aData.nParam[j] == ReferenceOrForceArray ) 266 { 267 pRun->bHasForceArray = true; 268 break; // for 269 } 270 } 271 } 272 } 273 274 #if OSL_DEBUG_LEVEL > 1 275 GenerateDocumentation(); 276 #endif 277 } 278 279 280 void ScParameterClassification::Exit() 281 { 282 delete [] pData; 283 pData = NULL; 284 } 285 286 287 ScParameterClassification::Type ScParameterClassification::GetParameterType( 288 const formula::FormulaToken* pToken, sal_uInt16 nParameter) 289 { 290 OpCode eOp = pToken->GetOpCode(); 291 switch ( eOp ) 292 { 293 case ocExternal: 294 return GetExternalParameterType( pToken, nParameter); 295 //break; 296 case ocMacro: 297 return Reference; 298 //break; 299 default: 300 { 301 // added to avoid warnings 302 } 303 } 304 if ( 0 <= (short)eOp && eOp <= SC_OPCODE_LAST_OPCODE_ID ) 305 { 306 if ( nParameter < CommonData::nMaxParams ) 307 { 308 Type eT = pData[eOp].aData.nParam[nParameter]; 309 return eT == Unknown ? Value : eT; 310 } 311 else if ( pData[eOp].aData.bRepeatLast ) 312 return pData[eOp].aData.nParam[CommonData::nMaxParams-1]; 313 else 314 return Bounds; 315 } 316 return Unknown; 317 } 318 319 320 ScParameterClassification::Type 321 ScParameterClassification::GetExternalParameterType( const formula::FormulaToken* pToken, 322 sal_uInt16 nParameter) 323 { 324 Type eRet = Unknown; 325 // similar to ScInterpreter::ScExternal() 326 sal_uInt16 nIndex; 327 String aUnoName; 328 String aFuncName( ScGlobal::pCharClass->upper( pToken->GetExternal())); 329 if ( ScGlobal::GetFuncCollection()->SearchFunc( aFuncName, nIndex) ) 330 { 331 FuncData* pFuncData = (FuncData*)ScGlobal::GetFuncCollection()->At( 332 nIndex); 333 if ( nParameter >= pFuncData->GetParamCount() ) 334 eRet = Bounds; 335 else 336 { 337 switch ( pFuncData->GetParamType( nParameter) ) 338 { 339 case PTR_DOUBLE: 340 case PTR_STRING: 341 eRet = Value; 342 break; 343 default: 344 eRet = Reference; 345 // also array types are created using an area reference 346 } 347 } 348 } 349 else if ( (aUnoName = ScGlobal::GetAddInCollection()->FindFunction( 350 aFuncName, sal_False)).Len() ) 351 { 352 // the relevant parts of ScUnoAddInCall without having to create one 353 const ScUnoAddInFuncData* pFuncData = 354 ScGlobal::GetAddInCollection()->GetFuncData( aUnoName, true ); // need fully initialized data 355 if ( pFuncData ) 356 { 357 long nCount = pFuncData->GetArgumentCount(); 358 if ( nCount <= 0 ) 359 eRet = Bounds; 360 else 361 { 362 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 363 if ( nParameter >= nCount && 364 pArgs[nCount-1].eType == SC_ADDINARG_VARARGS ) 365 eRet = Value; 366 // last arg is sequence, optional "any"s, we simply can't 367 // determine the type 368 if ( eRet == Unknown ) 369 { 370 if ( nParameter >= nCount ) 371 eRet = Bounds; 372 else 373 { 374 switch ( pArgs[nParameter].eType ) 375 { 376 case SC_ADDINARG_INTEGER: 377 case SC_ADDINARG_DOUBLE: 378 case SC_ADDINARG_STRING: 379 eRet = Value; 380 break; 381 default: 382 eRet = Reference; 383 } 384 } 385 } 386 } 387 } 388 } 389 return eRet; 390 } 391 392 //----------------------------------------------------------------------------- 393 394 #if OSL_DEBUG_LEVEL > 1 395 396 // add remaining functions, all Value parameters 397 void ScParameterClassification::MergeArgumentsFromFunctionResource() 398 { 399 ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList(); 400 for ( const ScFuncDesc* pDesc = pFuncList->First(); pDesc; 401 pDesc = pFuncList->Next() ) 402 { 403 if ( pDesc->nFIndex > SC_OPCODE_LAST_OPCODE_ID || 404 pData[pDesc->nFIndex].aData.nParam[0] != Unknown ) 405 continue; // not an internal opcode or already done 406 407 RunData* pRun = &pData[ pDesc->nFIndex ]; 408 sal_uInt16 nArgs = pDesc->GetSuppressedArgCount(); 409 if ( nArgs >= VAR_ARGS ) 410 { 411 nArgs -= VAR_ARGS - 1; 412 pRun->aData.bRepeatLast = true; 413 } 414 if ( nArgs > CommonData::nMaxParams ) 415 { 416 DBG_ERROR2( "ScParameterClassification::Init: too many arguments in listed function: %s: %d", 417 ByteString( *(pDesc->pFuncName), 418 RTL_TEXTENCODING_UTF8).GetBuffer(), nArgs); 419 nArgs = CommonData::nMaxParams; 420 pRun->aData.bRepeatLast = true; 421 } 422 pRun->nMinParams = static_cast< sal_uInt8 >( nArgs ); 423 for ( size_t j=0; j < nArgs; ++j ) 424 { 425 pRun->aData.nParam[j] = Value; 426 } 427 if ( pRun->aData.bRepeatLast ) 428 { 429 for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j ) 430 { 431 pRun->aData.nParam[j] = Value; 432 } 433 } 434 else 435 { 436 for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j ) 437 { 438 pRun->aData.nParam[j] = Bounds; 439 } 440 } 441 } 442 } 443 444 445 void ScParameterClassification::GenerateDocumentation() 446 { 447 static const sal_Char aEnvVarName[] = "OOO_CALC_GENPARCLASSDOC"; 448 if ( !getenv( aEnvVarName) ) 449 return; 450 MergeArgumentsFromFunctionResource(); 451 ScAddress aAddress; 452 ScCompiler aComp(NULL,aAddress); 453 ScCompiler::OpCodeMapPtr xMap( aComp.GetOpCodeMap(::com::sun::star::sheet::FormulaLanguage::ENGLISH)); 454 if (!xMap) 455 return; 456 fflush( stderr); 457 size_t nCount = xMap->getSymbolCount(); 458 for ( size_t i=0; i<nCount; ++i ) 459 { 460 OpCode eOp = OpCode(i); 461 if ( xMap->getSymbol(eOp).Len() ) 462 { 463 fprintf( stdout, "%s: ", aEnvVarName); 464 ByteString aStr( xMap->getSymbol(eOp), RTL_TEXTENCODING_UTF8); 465 aStr += "("; 466 formula::FormulaByteToken aToken( eOp); 467 sal_uInt8 nParams = GetMinimumParameters( eOp); 468 // preset parameter count according to opcode value, with some 469 // special handling 470 if ( eOp < SC_OPCODE_STOP_DIV ) 471 { 472 switch ( eOp ) 473 { 474 case ocIf: 475 aToken.SetByte(3); 476 break; 477 case ocChose: 478 aToken.SetByte(2); 479 break; 480 case ocPercentSign: 481 aToken.SetByte(1); 482 break; 483 default:; 484 } 485 } 486 else if ( eOp < SC_OPCODE_STOP_ERRORS ) 487 aToken.SetByte(0); 488 else if ( eOp < SC_OPCODE_STOP_BIN_OP ) 489 { 490 switch ( eOp ) 491 { 492 case ocAnd: 493 case ocOr: 494 aToken.SetByte(1); // (r1)AND(r2) --> AND( r1, ...) 495 break; 496 default: 497 aToken.SetByte(2); 498 } 499 } 500 else if ( eOp < SC_OPCODE_STOP_UN_OP ) 501 aToken.SetByte(1); 502 else if ( eOp < SC_OPCODE_STOP_NO_PAR ) 503 aToken.SetByte(0); 504 else if ( eOp < SC_OPCODE_STOP_1_PAR ) 505 aToken.SetByte(1); 506 else 507 aToken.SetByte( nParams); 508 // compare (this is a mere test for opcode order Div, BinOp, UnOp, 509 // NoPar, 1Par, ...) and override parameter count with 510 // classification 511 if ( nParams != aToken.GetByte() ) 512 fprintf( stdout, "(parameter count differs, token Byte: %d classification: %d) ", 513 aToken.GetByte(), nParams); 514 aToken.SetByte( nParams); 515 if ( nParams != aToken.GetParamCount() ) 516 fprintf( stdout, "(parameter count differs, token ParamCount: %d classification: %d) ", 517 aToken.GetParamCount(), nParams); 518 for ( sal_uInt16 j=0; j < nParams; ++j ) 519 { 520 if ( j > 0 ) 521 aStr += ","; 522 Type eType = GetParameterType( &aToken, j); 523 switch ( eType ) 524 { 525 case Value : 526 aStr += " Value"; 527 break; 528 case Reference : 529 aStr += " Reference"; 530 break; 531 case Array : 532 aStr += " Array"; 533 break; 534 case ForceArray : 535 aStr += " ForceArray"; 536 break; 537 case ReferenceOrForceArray : 538 aStr += " ReferenceOrForceArray"; 539 break; 540 case Bounds : 541 aStr += " (Bounds, classification error?)"; 542 break; 543 default: 544 aStr += " (???, classification error?)"; 545 } 546 } 547 if ( HasRepeatParameters( eOp) ) 548 aStr += ", ..."; 549 if ( nParams ) 550 aStr += " "; 551 aStr += ")"; 552 switch ( eOp ) 553 { 554 case ocZGZ: 555 aStr += " // RRI in English resource, but ZGZ in English-only section"; 556 break; 557 case ocMultiArea: 558 aStr += " // e.g. combined first parameter of INDEX() function, not a real function"; 559 break; 560 case ocBackSolver: 561 aStr += " // goal seek via menu, not a real function"; 562 break; 563 case ocTableOp: 564 aStr += " // MULTIPLE.OPERATIONS in English resource, but TABLE in English-only section"; 565 break; 566 case ocNoName: 567 aStr += " // error function, not a real function"; 568 break; 569 default:; 570 } 571 fprintf( stdout, "%s\n", aStr.GetBuffer()); 572 } 573 } 574 fflush( stdout); 575 } 576 577 #endif // OSL_DEBUG_LEVEL 578 579