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