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 { ocSumProduct, {{ ForceArray }, true }}, 177 { ocSumSQ, {{ Reference }, true }}, 178 { ocSumX2MY2, {{ ForceArray, ForceArray }, false }}, 179 { ocSumX2DY2, {{ ForceArray, ForceArray }, false }}, 180 { ocSumXMY2, {{ ForceArray, ForceArray }, false }}, 181 { ocTable, {{ Reference }, false }}, 182 { ocTables, {{ Reference }, true }}, 183 { ocTrend, {{ Reference, Reference, Reference, Value }, false }}, 184 { ocTrimMean, {{ Reference, Value }, false }}, 185 { ocTTest, {{ ForceArray, ForceArray, Value, Value }, false }}, 186 { ocVar, {{ Reference }, true }}, 187 { ocVarA, {{ Reference }, true }}, 188 { ocVarP, {{ Reference }, true }}, 189 { ocVarPA, {{ Reference }, true }}, 190 { ocVLookup, {{ Value, Reference, Value, Value }, false }}, 191 { ocZTest, {{ Reference, Value, Value }, false }}, 192 // Excel doubts: 193 // ocT: Excel says (and handles) Reference, error? This means no position 194 // dependent SingleRef if DoubleRef, and no array calculation, just the 195 // upper left corner. We never did that. 196 { ocT, {{ Value }, false }}, 197 // The stopper. 198 { ocNone, {{ Bounds }, false } } 199 }; 200 201 ScParameterClassification::RunData * ScParameterClassification::pData = NULL; 202 203 204 void ScParameterClassification::Init() 205 { 206 if ( pData ) 207 return; 208 pData = new RunData[ SC_OPCODE_LAST_OPCODE_ID + 1 ]; 209 memset( pData, 0, sizeof(RunData) * (SC_OPCODE_LAST_OPCODE_ID + 1)); 210 211 // init from specified static data above 212 for ( size_t i=0; i < sizeof(pRawData) / sizeof(RawData); ++i ) 213 { 214 const RawData* pRaw = &pRawData[i]; 215 if ( pRaw->eOp > SC_OPCODE_LAST_OPCODE_ID ) 216 { 217 DBG_ASSERT( pRaw->eOp == ocNone, "RawData OpCode error"); 218 } 219 else 220 { 221 RunData* pRun = &pData[ pRaw->eOp ]; 222 #ifdef DBG_UTIL 223 if ( pRun->aData.nParam[0] != Unknown ) 224 { 225 DBG_ERROR1( "already assigned: %d", pRaw->eOp); 226 } 227 #endif 228 memcpy( &(pRun->aData), &(pRaw->aData), sizeof(CommonData)); 229 // fill 0-initialized fields with real values 230 if ( pRun->aData.bRepeatLast ) 231 { 232 Type eLast = Unknown; 233 for ( size_t j=0; j < CommonData::nMaxParams; ++j ) 234 { 235 if ( pRun->aData.nParam[j] ) 236 { 237 eLast = pRun->aData.nParam[j]; 238 pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j+1 ); 239 } 240 else 241 pRun->aData.nParam[j] = eLast; 242 } 243 } 244 else 245 { 246 for ( size_t j=0; j < CommonData::nMaxParams; ++j ) 247 { 248 if ( !pRun->aData.nParam[j] ) 249 { 250 if ( j == 0 || pRun->aData.nParam[j-1] != Bounds ) 251 pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j ); 252 pRun->aData.nParam[j] = Bounds; 253 } 254 } 255 if ( !pRun->nMinParams && 256 pRun->aData.nParam[CommonData::nMaxParams-1] != Bounds) 257 pRun->nMinParams = CommonData::nMaxParams; 258 } 259 for ( size_t j=0; j < CommonData::nMaxParams; ++j ) 260 { 261 if ( pRun->aData.nParam[j] == ForceArray || pRun->aData.nParam[j] == ReferenceOrForceArray ) 262 { 263 pRun->bHasForceArray = true; 264 break; // for 265 } 266 } 267 } 268 } 269 270 #if OSL_DEBUG_LEVEL > 1 271 GenerateDocumentation(); 272 #endif 273 } 274 275 276 void ScParameterClassification::Exit() 277 { 278 delete [] pData; 279 pData = NULL; 280 } 281 282 283 ScParameterClassification::Type ScParameterClassification::GetParameterType( 284 const formula::FormulaToken* pToken, sal_uInt16 nParameter) 285 { 286 OpCode eOp = pToken->GetOpCode(); 287 switch ( eOp ) 288 { 289 case ocExternal: 290 return GetExternalParameterType( pToken, nParameter); 291 //break; 292 case ocMacro: 293 return Reference; 294 //break; 295 default: 296 { 297 // added to avoid warnings 298 } 299 } 300 if ( 0 <= (short)eOp && eOp <= SC_OPCODE_LAST_OPCODE_ID ) 301 { 302 if ( nParameter < CommonData::nMaxParams ) 303 { 304 Type eT = pData[eOp].aData.nParam[nParameter]; 305 return eT == Unknown ? Value : eT; 306 } 307 else if ( pData[eOp].aData.bRepeatLast ) 308 return pData[eOp].aData.nParam[CommonData::nMaxParams-1]; 309 else 310 return Bounds; 311 } 312 return Unknown; 313 } 314 315 316 ScParameterClassification::Type 317 ScParameterClassification::GetExternalParameterType( const formula::FormulaToken* pToken, 318 sal_uInt16 nParameter) 319 { 320 Type eRet = Unknown; 321 // similar to ScInterpreter::ScExternal() 322 sal_uInt16 nIndex; 323 String aUnoName; 324 String aFuncName( ScGlobal::pCharClass->upper( pToken->GetExternal())); 325 if ( ScGlobal::GetFuncCollection()->SearchFunc( aFuncName, nIndex) ) 326 { 327 FuncData* pFuncData = (FuncData*)ScGlobal::GetFuncCollection()->At( 328 nIndex); 329 if ( nParameter >= pFuncData->GetParamCount() ) 330 eRet = Bounds; 331 else 332 { 333 switch ( pFuncData->GetParamType( nParameter) ) 334 { 335 case PTR_DOUBLE: 336 case PTR_STRING: 337 eRet = Value; 338 break; 339 default: 340 eRet = Reference; 341 // also array types are created using an area reference 342 } 343 } 344 } 345 else if ( (aUnoName = ScGlobal::GetAddInCollection()->FindFunction( 346 aFuncName, sal_False)).Len() ) 347 { 348 // the relevant parts of ScUnoAddInCall without having to create one 349 const ScUnoAddInFuncData* pFuncData = 350 ScGlobal::GetAddInCollection()->GetFuncData( aUnoName, true ); // need fully initialized data 351 if ( pFuncData ) 352 { 353 long nCount = pFuncData->GetArgumentCount(); 354 if ( nCount <= 0 ) 355 eRet = Bounds; 356 else 357 { 358 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 359 if ( nParameter >= nCount && 360 pArgs[nCount-1].eType == SC_ADDINARG_VARARGS ) 361 eRet = Value; 362 // last arg is sequence, optional "any"s, we simply can't 363 // determine the type 364 if ( eRet == Unknown ) 365 { 366 if ( nParameter >= nCount ) 367 eRet = Bounds; 368 else 369 { 370 switch ( pArgs[nParameter].eType ) 371 { 372 case SC_ADDINARG_INTEGER: 373 case SC_ADDINARG_DOUBLE: 374 case SC_ADDINARG_STRING: 375 eRet = Value; 376 break; 377 default: 378 eRet = Reference; 379 } 380 } 381 } 382 } 383 } 384 } 385 return eRet; 386 } 387 388 //----------------------------------------------------------------------------- 389 390 #if OSL_DEBUG_LEVEL > 1 391 392 // add remaining functions, all Value parameters 393 void ScParameterClassification::MergeArgumentsFromFunctionResource() 394 { 395 ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList(); 396 for ( const ScFuncDesc* pDesc = pFuncList->First(); pDesc; 397 pDesc = pFuncList->Next() ) 398 { 399 if ( pDesc->nFIndex > SC_OPCODE_LAST_OPCODE_ID || 400 pData[pDesc->nFIndex].aData.nParam[0] != Unknown ) 401 continue; // not an internal opcode or already done 402 403 RunData* pRun = &pData[ pDesc->nFIndex ]; 404 sal_uInt16 nArgs = pDesc->GetSuppressedArgCount(); 405 if ( nArgs >= VAR_ARGS ) 406 { 407 nArgs -= VAR_ARGS - 1; 408 pRun->aData.bRepeatLast = true; 409 } 410 if ( nArgs > CommonData::nMaxParams ) 411 { 412 DBG_ERROR2( "ScParameterClassification::Init: too many arguments in listed function: %s: %d", 413 ByteString( *(pDesc->pFuncName), 414 RTL_TEXTENCODING_UTF8).GetBuffer(), nArgs); 415 nArgs = CommonData::nMaxParams; 416 pRun->aData.bRepeatLast = true; 417 } 418 pRun->nMinParams = static_cast< sal_uInt8 >( nArgs ); 419 for ( size_t j=0; j < nArgs; ++j ) 420 { 421 pRun->aData.nParam[j] = Value; 422 } 423 if ( pRun->aData.bRepeatLast ) 424 { 425 for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j ) 426 { 427 pRun->aData.nParam[j] = Value; 428 } 429 } 430 else 431 { 432 for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j ) 433 { 434 pRun->aData.nParam[j] = Bounds; 435 } 436 } 437 } 438 } 439 440 441 void ScParameterClassification::GenerateDocumentation() 442 { 443 static const sal_Char aEnvVarName[] = "OOO_CALC_GENPARCLASSDOC"; 444 if ( !getenv( aEnvVarName) ) 445 return; 446 MergeArgumentsFromFunctionResource(); 447 ScAddress aAddress; 448 ScCompiler aComp(NULL,aAddress); 449 ScCompiler::OpCodeMapPtr xMap( aComp.GetOpCodeMap(::com::sun::star::sheet::FormulaLanguage::ENGLISH)); 450 if (!xMap) 451 return; 452 fflush( stderr); 453 size_t nCount = xMap->getSymbolCount(); 454 for ( size_t i=0; i<nCount; ++i ) 455 { 456 OpCode eOp = OpCode(i); 457 if ( xMap->getSymbol(eOp).Len() ) 458 { 459 fprintf( stdout, "%s: ", aEnvVarName); 460 ByteString aStr( xMap->getSymbol(eOp), RTL_TEXTENCODING_UTF8); 461 aStr += "("; 462 formula::FormulaByteToken aToken( eOp); 463 sal_uInt8 nParams = GetMinimumParameters( eOp); 464 // preset parameter count according to opcode value, with some 465 // special handling 466 if ( eOp < SC_OPCODE_STOP_DIV ) 467 { 468 switch ( eOp ) 469 { 470 case ocIf: 471 aToken.SetByte(3); 472 break; 473 case ocChose: 474 aToken.SetByte(2); 475 break; 476 case ocPercentSign: 477 aToken.SetByte(1); 478 break; 479 default:; 480 } 481 } 482 else if ( eOp < SC_OPCODE_STOP_ERRORS ) 483 aToken.SetByte(0); 484 else if ( eOp < SC_OPCODE_STOP_BIN_OP ) 485 { 486 switch ( eOp ) 487 { 488 case ocAnd: 489 case ocOr: 490 aToken.SetByte(1); // (r1)AND(r2) --> AND( r1, ...) 491 break; 492 default: 493 aToken.SetByte(2); 494 } 495 } 496 else if ( eOp < SC_OPCODE_STOP_UN_OP ) 497 aToken.SetByte(1); 498 else if ( eOp < SC_OPCODE_STOP_NO_PAR ) 499 aToken.SetByte(0); 500 else if ( eOp < SC_OPCODE_STOP_1_PAR ) 501 aToken.SetByte(1); 502 else 503 aToken.SetByte( nParams); 504 // compare (this is a mere test for opcode order Div, BinOp, UnOp, 505 // NoPar, 1Par, ...) and override parameter count with 506 // classification 507 if ( nParams != aToken.GetByte() ) 508 fprintf( stdout, "(parameter count differs, token Byte: %d classification: %d) ", 509 aToken.GetByte(), nParams); 510 aToken.SetByte( nParams); 511 if ( nParams != aToken.GetParamCount() ) 512 fprintf( stdout, "(parameter count differs, token ParamCount: %d classification: %d) ", 513 aToken.GetParamCount(), nParams); 514 for ( sal_uInt16 j=0; j < nParams; ++j ) 515 { 516 if ( j > 0 ) 517 aStr += ","; 518 Type eType = GetParameterType( &aToken, j); 519 switch ( eType ) 520 { 521 case Value : 522 aStr += " Value"; 523 break; 524 case Reference : 525 aStr += " Reference"; 526 break; 527 case Array : 528 aStr += " Array"; 529 break; 530 case ForceArray : 531 aStr += " ForceArray"; 532 break; 533 case ReferenceOrForceArray : 534 aStr += " ReferenceOrForceArray"; 535 break; 536 case Bounds : 537 aStr += " (Bounds, classification error?)"; 538 break; 539 default: 540 aStr += " (???, classification error?)"; 541 } 542 } 543 if ( HasRepeatParameters( eOp) ) 544 aStr += ", ..."; 545 if ( nParams ) 546 aStr += " "; 547 aStr += ")"; 548 switch ( eOp ) 549 { 550 case ocZGZ: 551 aStr += " // RRI in English resource, but ZGZ in English-only section"; 552 break; 553 case ocMultiArea: 554 aStr += " // e.g. combined first parameter of INDEX() function, not a real function"; 555 break; 556 case ocBackSolver: 557 aStr += " // goal seek via menu, not a real function"; 558 break; 559 case ocTableOp: 560 aStr += " // MULTIPLE.OPERATIONS in English resource, but TABLE in English-only section"; 561 break; 562 case ocNoName: 563 aStr += " // error function, not a real function"; 564 break; 565 default:; 566 } 567 fprintf( stdout, "%s\n", aStr.GetBuffer()); 568 } 569 } 570 fflush( stdout); 571 } 572 573 #endif // OSL_DEBUG_LEVEL 574 575