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