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