diff options
Diffstat (limited to 'sc/source/core/tool/parclass.cxx')
-rw-r--r-- | sc/source/core/tool/parclass.cxx | 710 |
1 files changed, 710 insertions, 0 deletions
diff --git a/sc/source/core/tool/parclass.cxx b/sc/source/core/tool/parclass.cxx new file mode 100644 index 000000000..473177c8f --- /dev/null +++ b/sc/source/core/tool/parclass.cxx @@ -0,0 +1,710 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <parclass.hxx> +#include <global.hxx> +#include <callform.hxx> +#include <addincol.hxx> +#include <formula/token.hxx> +#include <unotools/charclass.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <string.h> + +#if DEBUG_SC_PARCLASSDOC +// the documentation thingy +#include <com/sun/star/sheet/FormulaLanguage.hpp> +#include <rtl/strbuf.hxx> +#include <formula/funcvarargs.h> +#include "compiler.hxx" +#endif + +using namespace formula; + +/* Following assumptions are made: + * - OpCodes not specified at all will have at least one and only parameters of + * type Value, no check is done on the count of parameters => no Bounds type + * is returned. + * - For OpCodes with a variable number of parameters the type(s) of the last + * repeated parameter(s) specified determine(s) the type(s) of all following + * parameters. + */ + +const ScParameterClassification::RawData ScParameterClassification::pRawData[] = +{ + // { OpCode, {{ ParamClass, ... }, nRepeatLast, ReturnClass }}, + + // IF() and CHOOSE() are somewhat special, since the ScJumpMatrix is + // created inside those functions and ConvertMatrixParameters() is not + // called for them. + { ocIf, {{ Array, Reference, Reference }, 0, Value }}, + { ocIfError, {{ Array, Reference }, 0, Value }}, + { ocIfNA, {{ Array, Reference }, 0, Value }}, + { ocChoose, {{ Array, Reference }, 1, Value }}, + // Other specials. + { ocArrayClose, {{ Bounds }, 0, Bounds }}, + { ocArrayColSep, {{ Bounds }, 0, Bounds }}, + { ocArrayOpen, {{ Bounds }, 0, Bounds }}, + { ocArrayRowSep, {{ Bounds }, 0, Bounds }}, + { ocBad, {{ Bounds }, 0, Bounds }}, + { ocClose, {{ Bounds }, 0, Bounds }}, + { ocColRowName, {{ Bounds }, 0, Value }}, // or Reference? + { ocColRowNameAuto, {{ Bounds }, 0, Value }}, // or Reference? + { ocDBArea, {{ Bounds }, 0, Value }}, // or Reference? + { ocMatRef, {{ Bounds }, 0, Value }}, + { ocMissing, {{ Bounds }, 0, Value }}, + { ocNoName, {{ Bounds }, 0, Bounds }}, + { ocOpen, {{ Bounds }, 0, Bounds }}, + { ocSep, {{ Bounds }, 0, Bounds }}, + { ocSkip, {{ Bounds }, 0, Bounds }}, + { ocSpaces, {{ Bounds }, 0, Bounds }}, + { ocStop, {{ Bounds }, 0, Bounds }}, + { ocStringXML, {{ Bounds }, 0, Bounds }}, + { ocTableRef, {{ Bounds }, 0, Value }}, // or Reference? + { ocTableRefClose, {{ Bounds }, 0, Bounds }}, + { ocTableRefItemAll, {{ Bounds }, 0, Bounds }}, + { ocTableRefItemData, {{ Bounds }, 0, Bounds }}, + { ocTableRefItemHeaders, {{ Bounds }, 0, Bounds }}, + { ocTableRefItemThisRow, {{ Bounds }, 0, Bounds }}, + { ocTableRefItemTotals, {{ Bounds }, 0, Bounds }}, + { ocTableRefOpen, {{ Bounds }, 0, Bounds }}, + // Error constants. + { ocErrDivZero, {{ Bounds }, 0, Bounds }}, + { ocErrNA, {{ Bounds }, 0, Bounds }}, + { ocErrName, {{ Bounds }, 0, Bounds }}, + { ocErrNull, {{ Bounds }, 0, Bounds }}, + { ocErrNum, {{ Bounds }, 0, Bounds }}, + { ocErrRef, {{ Bounds }, 0, Bounds }}, + { ocErrValue, {{ Bounds }, 0, Bounds }}, + // Functions with Value parameters only but not in resource. + { ocBackSolver, {{ Value, Value, Value }, 0, Value }}, + { ocTableOp, {{ Value, Value, Value, Value, Value }, 0, Value }}, + // Operators and functions. + { ocAdd, {{ Array, Array }, 0, Value }}, + { ocAggregate, {{ Value, Value, ReferenceOrForceArray }, 1, Value }}, + { ocAmpersand, {{ Array, Array }, 0, Value }}, + { ocAnd, {{ Reference }, 1, Value }}, + { ocAreas, {{ Reference }, 0, Value }}, + { ocAveDev, {{ Reference }, 1, Value }}, + { ocAverage, {{ ReferenceOrRefArray }, 1, Value }}, + { ocAverageA, {{ ReferenceOrRefArray }, 1, Value }}, + { ocAverageIf, {{ ReferenceOrRefArray, Value, Reference }, 0, Value }}, + { ocAverageIfs, {{ ReferenceOrRefArray, ReferenceOrRefArray, Value }, 2, Value }}, + { ocCell, {{ Value, Reference }, 0, Value }}, + { ocColumn, {{ Reference }, 0, Value }}, + { ocColumns, {{ Reference }, 1, Value }}, + { ocConcat_MS, {{ Reference }, 1, Value }}, + { ocCorrel, {{ ForceArray, ForceArray }, 0, Value }}, + { ocCount, {{ ReferenceOrRefArray }, 1, Value }}, + { ocCount2, {{ ReferenceOrRefArray }, 1, Value }}, + { ocCountEmptyCells, {{ ReferenceOrRefArray }, 0, Value }}, + { ocCountIf, {{ ReferenceOrRefArray, Value }, 0, Value }}, + { ocCountIfs, {{ ReferenceOrRefArray, Value }, 2, Value }}, + { ocCovar, {{ ForceArray, ForceArray }, 0, Value }}, + { ocCovarianceP, {{ ForceArray, ForceArray }, 0, Value }}, + { ocCovarianceS, {{ ForceArray, ForceArray }, 0, Value }}, + { ocCurrent, {{ Bounds }, 0, Value }}, + { ocDBAverage, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBCount, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBCount2, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBGet, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBMax, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBMin, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBProduct, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBStdDev, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBStdDevP, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBSum, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBVar, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDBVarP, {{ Reference, Reference, Reference }, 0, Value }}, + { ocDevSq, {{ Reference }, 1, Value }}, + { ocDiv, {{ Array, Array }, 0, Value }}, + { ocEqual, {{ Array, Array }, 0, Value }}, + { ocFTest, {{ ForceArray, ForceArray }, 0, Value }}, + { ocFalse, {{ Bounds }, 0, Value }}, + { ocForecast, {{ Value, ForceArray, ForceArray }, 0, Value }}, + { ocForecast_ETS_ADD, {{ ForceArray, ForceArray, ForceArray, Value, Value, Value }, 0, Value }}, + { ocForecast_ETS_MUL, {{ ForceArray, ForceArray, ForceArray, Value, Value, Value }, 0, Value }}, + { ocForecast_ETS_PIA, {{ ForceArray, ForceArray, ForceArray, Value, Value, Value, Value }, 0, Value }}, + { ocForecast_ETS_PIM, {{ ForceArray, ForceArray, ForceArray, Value, Value, Value, Value }, 0, Value }}, + { ocForecast_ETS_SEA, {{ ForceArray, ForceArray, Value, Value }, 0, Value }}, + { ocForecast_ETS_STA, {{ ForceArray, ForceArray, ForceArray, Value, Value, Value }, 0, Value }}, + { ocForecast_ETS_STM, {{ ForceArray, ForceArray, ForceArray, Value, Value, Value }, 0, Value }}, + { ocFormula, {{ Reference }, 0, Value }}, + { ocFourier, {{ ForceArray, Value, Value, Value, Value }, 0, Value }}, + { ocFrequency, {{ ReferenceOrForceArray, ReferenceOrForceArray }, 0, ForceArrayReturn }}, + { ocGCD, {{ Reference }, 1, Value }}, + { ocGeoMean, {{ Reference }, 1, Value }}, + { ocGetActDate, {{ Bounds }, 0, Value }}, + { ocGetActTime, {{ Bounds }, 0, Value }}, + { ocGreater, {{ Array, Array }, 0, Value }}, + { ocGreaterEqual, {{ Array, Array }, 0, Value }}, + { ocGrowth, {{ Reference, Reference, Reference, Value }, 0, Value }}, + { ocHLookup, {{ Value, ReferenceOrForceArray, Value, Value }, 0, Value }}, + { ocHarMean, {{ Reference }, 1, Value }}, + { ocIRR, {{ Reference, Value }, 0, Value }}, + { ocIndex, {{ Reference, Value, Value, Value }, 0, Value }}, + { ocIndirect, {{ Value, Value }, 0, Reference }}, + { ocIntercept, {{ ForceArray, ForceArray }, 0, Value }}, + { ocIntersect, {{ Reference, Reference }, 0, Reference }}, + { ocIsFormula, {{ Reference }, 0, Value }}, + { ocIsRef, {{ Reference }, 0, Value }}, + { ocKurt, {{ Reference }, 1, Value }}, + { ocLCM, {{ Reference }, 1, Value }}, + { ocLarge, {{ Reference, Value }, 0, Value }}, + { ocLess, {{ Array, Array }, 0, Value }}, + { ocLessEqual, {{ Array, Array }, 0, Value }}, + { ocLinest, {{ ForceArray, ForceArray, Value, Value }, 0, Value }}, + { ocLogest, {{ ForceArray, ForceArray, Value, Value }, 0, Value }}, + { ocLookup, {{ Value, ReferenceOrForceArray, ReferenceOrForceArray }, 0, Value }}, + { ocMIRR, {{ Reference, Value, Value }, 0, Value }}, + { ocMatDet, {{ ForceArray }, 0, Value }}, + { ocMatInv, {{ ForceArray }, 0, Value }}, + { ocMatMult, {{ ForceArray, ForceArray }, 0, Value }}, + { ocMatTrans, {{ ForceArray }, 0, ForceArrayReturn }}, + { ocMatValue, {{ Reference, Value, Value }, 0, Value }}, + { ocMatch, {{ Value, ReferenceOrForceArray, Value }, 0, Value }}, + { ocMax, {{ ReferenceOrRefArray }, 1, Value }}, + { ocMaxA, {{ ReferenceOrRefArray }, 1, Value }}, + { ocMaxIfs_MS, {{ ReferenceOrRefArray, ReferenceOrRefArray, Value }, 2, Value }}, + { ocMedian, {{ Reference }, 1, Value }}, + { ocMin, {{ ReferenceOrRefArray }, 1, Value }}, + { ocMinA, {{ ReferenceOrRefArray }, 1, Value }}, + { ocMinIfs_MS, {{ ReferenceOrRefArray, ReferenceOrRefArray, Value }, 2, Value }}, + { ocModalValue, {{ ForceArray }, 1, Value }}, + { ocModalValue_MS, {{ ForceArray }, 1, Value }}, + { ocModalValue_Multi,{{ ForceArray }, 1, Value }}, + { ocMul, {{ Array, Array }, 0, Value }}, + { ocMultiArea, {{ Reference }, 1, Reference }}, + { ocNPV, {{ Value, Reference }, 1, Value }}, + { ocNeg, {{ Array }, 0, Value }}, + { ocNegSub, {{ Array }, 0, Value }}, + { ocNetWorkdays, {{ Value, Value, Reference, Reference }, 0, Value }}, + { ocNetWorkdays_MS, {{ Value, Value, Value, Reference }, 0, Value }}, + { ocNot, {{ Array }, 0, Value }}, + { ocNotAvail, {{ Bounds }, 0, Value }}, + { ocNotEqual, {{ Array, Array }, 0, Value }}, + { ocOffset, {{ Reference, Value, Value, Value, Value }, 0, Reference }}, + { ocOr, {{ Reference }, 1, Value }}, + { ocPearson, {{ ForceArray, ForceArray }, 0, Value }}, + { ocPercentSign, {{ Array }, 0, Value }}, + { ocPercentile, {{ Reference, Value }, 0, Value }}, + { ocPercentile_Exc, {{ Reference, Value }, 0, Value }}, + { ocPercentile_Inc, {{ Reference, Value }, 0, Value }}, + { ocPercentrank, {{ Reference, Value, Value }, 0, Value }}, + { ocPercentrank_Exc, {{ Reference, Value, Value }, 0, Value }}, + { ocPercentrank_Inc, {{ Reference, Value, Value }, 0, Value }}, + { ocPi, {{ Bounds }, 0, Value }}, + { ocPow, {{ Array, Array }, 0, Value }}, + { ocPower, {{ Array, Array }, 0, Value }}, + { ocProb, {{ ForceArray, ForceArray, Value, Value }, 0, Value }}, + { ocProduct, {{ ReferenceOrRefArray }, 1, Value }}, + { ocQuartile, {{ Reference, Value }, 0, Value }}, + { ocQuartile_Exc, {{ Reference, Value }, 0, Value }}, + { ocQuartile_Inc, {{ Reference, Value }, 0, Value }}, + { ocRSQ, {{ ForceArray, ForceArray }, 0, Value }}, + { ocRandom, {{ Bounds }, 0, Value }}, + { ocRandomNV, {{ Bounds }, 0, Value }}, + { ocRange, {{ Reference, Reference }, 0, Reference }}, + { ocRank, {{ Value, Reference, Value }, 0, Value }}, + { ocRank_Avg, {{ Value, Reference, Value }, 0, Value }}, + { ocRank_Eq, {{ Value, Reference, Value }, 0, Value }}, + { ocRow, {{ Reference }, 0, Value }}, + { ocRows, {{ Reference }, 1, Value }}, + { ocSTEYX, {{ ForceArray, ForceArray }, 0, Value }}, + { ocSheet, {{ Reference }, 0, Value }}, + { ocSheets, {{ Reference }, 1, Value }}, + { ocSkew, {{ Reference }, 1, Value }}, + { ocSkewp, {{ Reference }, 1, Value }}, + { ocSlope, {{ ForceArray, ForceArray }, 0, Value }}, + { ocSmall, {{ Reference, Value }, 0, Value }}, + { ocStDev, {{ Reference }, 1, Value }}, + { ocStDevA, {{ Reference }, 1, Value }}, + { ocStDevP, {{ Reference }, 1, Value }}, + { ocStDevPA, {{ Reference }, 1, Value }}, + { ocStDevP_MS, {{ Reference }, 1, Value }}, + { ocStDevS, {{ Reference }, 1, Value }}, + { ocSub, {{ Array, Array }, 0, Value }}, + { ocSubTotal, {{ Value, ReferenceOrRefArray }, 1, Value }}, + { ocSum, {{ ReferenceOrRefArray }, 1, Value }}, + { ocSumIf, {{ ReferenceOrRefArray, Value, Reference }, 0, Value }}, + { ocSumIfs, {{ ReferenceOrRefArray, ReferenceOrRefArray, Value }, 2, Value }}, + { ocSumProduct, {{ ForceArray }, 1, Value }}, + { ocSumSQ, {{ ReferenceOrRefArray }, 1, Value }}, + { ocSumX2DY2, {{ ForceArray, ForceArray }, 0, Value }}, + { ocSumX2MY2, {{ ForceArray, ForceArray }, 0, Value }}, + { ocSumXMY2, {{ ForceArray, ForceArray }, 0, Value }}, + { ocTTest, {{ ForceArray, ForceArray, Value, Value }, 0, Value }}, + { ocTextJoin_MS, {{ Reference, Value, Reference }, 1, Value }}, + { ocTrend, {{ Reference, Reference, Reference, Value }, 0, Value }}, + { ocTrimMean, {{ Reference, Value }, 0, Value }}, + { ocTrue, {{ Bounds }, 0, Value }}, + { ocUnion, {{ Reference, Reference }, 0, Reference }}, + { ocVLookup, {{ Value, ReferenceOrForceArray, Value, Value }, 0, Value }}, + { ocVar, {{ ReferenceOrRefArray }, 1, Value }}, + { ocVarA, {{ ReferenceOrRefArray }, 1, Value }}, + { ocVarP, {{ ReferenceOrRefArray }, 1, Value }}, + { ocVarPA, {{ ReferenceOrRefArray }, 1, Value }}, + { ocVarP_MS, {{ Reference }, 1, Value }}, + { ocVarS, {{ Reference }, 1, Value }}, + { ocWhitespace, {{ Bounds }, 0, Bounds }}, + { ocWorkday_MS, {{ Value, Value, Value, Reference }, 0, Value }}, + { ocXor, {{ Reference }, 1, Value }}, + { ocZTest, {{ Reference, Value, Value }, 0, Value }}, + { ocZTest_MS, {{ Reference, Value, Value }, 0, Value }}, + // Excel doubts: + // ocN, ocT: Excel says (and handles) Reference, error? This means no + // position dependent SingleRef if DoubleRef, and no array calculation, + // just the upper left corner. We never did that for ocT and now also not + // for ocN (position dependent intersection worked before but array + // didn't). No specifics in ODFF, so the general rule applies. Gnumeric + // does the same. + { ocN, {{ Value }, 0, Value }}, + { ocT, {{ Value }, 0, Value }}, + // The stopper. + { ocNone, {{ Bounds }, 0, Value }} +}; + +ScParameterClassification::RunData * ScParameterClassification::pData = nullptr; + +void ScParameterClassification::Init() +{ + if ( pData ) + return; + pData = new RunData[ SC_OPCODE_LAST_OPCODE_ID + 1 ]; + memset( pData, 0, sizeof(RunData) * (SC_OPCODE_LAST_OPCODE_ID + 1)); + + // init from specified static data above + for (const auto & i : pRawData) + { + const RawData* pRaw = &i; + if ( pRaw->eOp > SC_OPCODE_LAST_OPCODE_ID ) + { + OSL_ENSURE( pRaw->eOp == ocNone, "RawData OpCode error"); + } + else + { + RunData* pRun = &pData[ pRaw->eOp ]; + SAL_WARN_IF(pRun->aData.nParam[0] != Unknown, "sc.core", "already assigned: " << static_cast<int>(pRaw->eOp)); + memcpy( &(pRun->aData), &(pRaw->aData), sizeof(CommonData)); + // fill 0-initialized fields with real values + if ( pRun->aData.nRepeatLast ) + { + for ( sal_Int32 j=0; j < CommonData::nMaxParams; ++j ) + { + if ( pRun->aData.nParam[j] ) + pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j+1 ); + else if (j >= pRun->aData.nRepeatLast) + pRun->aData.nParam[j] = pRun->aData.nParam[j - pRun->aData.nRepeatLast]; + else + { + SAL_INFO( + "sc.core", + "bad classification: eOp " << +pRaw->eOp + << ", repeated param " << j + << " negative offset"); + pRun->aData.nParam[j] = Unknown; + } + } + } + else + { + for ( sal_Int32 j=0; j < CommonData::nMaxParams; ++j ) + { + if ( !pRun->aData.nParam[j] ) + { + if ( j == 0 || pRun->aData.nParam[j-1] != Bounds ) + pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j ); + pRun->aData.nParam[j] = Bounds; + } + } + if ( !pRun->nMinParams && + pRun->aData.nParam[CommonData::nMaxParams-1] != Bounds) + pRun->nMinParams = CommonData::nMaxParams; + } + for (const formula::ParamClass & j : pRun->aData.nParam) + { + if ( j == ForceArray || j == ReferenceOrForceArray ) + { + pRun->bHasForceArray = true; + break; // for + } + } + } + } + +#if DEBUG_SC_PARCLASSDOC + GenerateDocumentation(); +#endif +} + +void ScParameterClassification::Exit() +{ + delete [] pData; + pData = nullptr; +} + +formula::ParamClass ScParameterClassification::GetParameterType( + const formula::FormulaToken* pToken, sal_uInt16 nParameter) +{ + OpCode eOp = pToken->GetOpCode(); + switch ( eOp ) + { + case ocExternal: + return GetExternalParameterType( pToken, nParameter); + case ocMacro: + return (nParameter == SAL_MAX_UINT16 ? Value : Reference); + default: + { + // added to avoid warnings + } + } + if ( 0 <= static_cast<short>(eOp) && eOp <= SC_OPCODE_LAST_OPCODE_ID ) + { + sal_uInt8 nRepeat; + formula::ParamClass eType; + if (nParameter == SAL_MAX_UINT16) + eType = pData[eOp].aData.eReturn; + else if ( nParameter < CommonData::nMaxParams ) + eType = pData[eOp].aData.nParam[nParameter]; + else if ( (nRepeat = pData[eOp].aData.nRepeatLast) > 0 ) + { + // The usual case is 1 repeated parameter, we don't need to + // calculate that on each call. + sal_uInt16 nParam = (nRepeat > 1 ? + (pData[eOp].nMinParams - + ((nParameter - pData[eOp].nMinParams) % nRepeat)) : + pData[eOp].nMinParams); + return pData[eOp].aData.nParam[nParam]; + } + else + eType = Bounds; + return eType == Unknown ? Value : eType; + } + return Unknown; +} + +formula::ParamClass ScParameterClassification::GetExternalParameterType( const formula::FormulaToken* pToken, + sal_uInt16 nParameter) +{ + formula::ParamClass eRet = Unknown; + if (nParameter == SAL_MAX_UINT16) + return eRet; + + // similar to ScInterpreter::ScExternal() + OUString aFuncName = pToken->GetExternal().toAsciiUpperCase(); // programmatic name + { + const LegacyFuncData* pLegacyFuncData = ScGlobal::GetLegacyFuncCollection()->findByName(aFuncName); + if (pLegacyFuncData) + { + if ( nParameter >= pLegacyFuncData->GetParamCount() ) + eRet = Bounds; + else + { + switch ( pLegacyFuncData->GetParamType( nParameter) ) + { + case ParamType::PTR_DOUBLE: + case ParamType::PTR_STRING: + eRet = Value; + break; + default: + eRet = Reference; + // also array types are created using an area reference + } + } + return eRet; + } + } + + OUString aUnoName = + ScGlobal::GetAddInCollection()->FindFunction(aFuncName, false); + + if (!aUnoName.isEmpty()) + { + // the relevant parts of ScUnoAddInCall without having to create one + const ScUnoAddInFuncData* pFuncData = + ScGlobal::GetAddInCollection()->GetFuncData( aUnoName, true ); // need fully initialized data + if ( pFuncData ) + { + tools::Long nCount = pFuncData->GetArgumentCount(); + if ( nCount <= 0 ) + eRet = Bounds; + else + { + const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); + if ( nParameter >= nCount && + pArgs[nCount-1].eType == SC_ADDINARG_VARARGS ) + eRet = Value; + // last arg is sequence, optional "any"s, we simply can't + // determine the type + if ( eRet == Unknown ) + { + if ( nParameter >= nCount ) + eRet = Bounds; + else + { + switch ( pArgs[nParameter].eType ) + { + case SC_ADDINARG_INTEGER: + case SC_ADDINARG_DOUBLE: + case SC_ADDINARG_STRING: + eRet = Value; + break; + default: + eRet = Reference; + } + } + } + } + } + } + return eRet; +} + +#if DEBUG_SC_PARCLASSDOC + +// add remaining functions, all Value parameters +void ScParameterClassification::MergeArgumentsFromFunctionResource() +{ + ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList(); + for ( const ScFuncDesc* pDesc = pFuncList->First(); pDesc; + pDesc = pFuncList->Next() ) + { + if ( pDesc->nFIndex > SC_OPCODE_LAST_OPCODE_ID || + pData[pDesc->nFIndex].aData.nParam[0] != Unknown ) + continue; // not an internal opcode or already done + + RunData* pRun = &pData[ pDesc->nFIndex ]; + sal_uInt16 nArgs = pDesc->GetSuppressedArgCount(); + if ( nArgs >= PAIRED_VAR_ARGS ) + { + nArgs -= PAIRED_VAR_ARGS - 2; + pRun->aData.nRepeatLast = 2; + } + else if ( nArgs >= VAR_ARGS ) + { + nArgs -= VAR_ARGS - 1; + pRun->aData.nRepeatLast = 1; + } + if ( nArgs > CommonData::nMaxParams ) + { + SAL_WARN( "sc", "ScParameterClassification::Init: too many arguments in listed function: " + << *(pDesc->pFuncName) + << ": " << nArgs ); + nArgs = CommonData::nMaxParams - 1; + pRun->aData.nRepeatLast = 1; + } + pRun->nMinParams = static_cast< sal_uInt8 >( nArgs ); + for ( sal_Int32 j=0; j < nArgs; ++j ) + { + pRun->aData.nParam[j] = Value; + } + if ( pRun->aData.nRepeatLast ) + { + for ( sal_Int32 j = nArgs; j < CommonData::nMaxParams; ++j ) + { + pRun->aData.nParam[j] = Value; + } + } + else + { + for ( sal_Int32 j = nArgs; j < CommonData::nMaxParams; ++j ) + { + pRun->aData.nParam[j] = Bounds; + } + } + } +} + +void ScParameterClassification::GenerateDocumentation() +{ + static const char aEnvVarName[] = "OOO_CALC_GENPARCLASSDOC"; + if ( !getenv( aEnvVarName) ) + return; + MergeArgumentsFromFunctionResource(); + ScAddress aAddress; + ScCompiler aComp(NULL,aAddress); + ScCompiler::OpCodeMapPtr xMap( aComp.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH)); + if (!xMap) + return; + fflush( stderr); + size_t nCount = xMap->getSymbolCount(); + for ( size_t i=0; i<nCount; ++i ) + { + OpCode eOp = OpCode(i); + if ( !xMap->getSymbol(eOp).isEmpty() ) + { + OUStringBuffer aStr(xMap->getSymbol(eOp)); + formula::FormulaByteToken aToken( eOp); + sal_uInt8 nParams = GetMinimumParameters( eOp); + // preset parameter count according to opcode value, with some + // special handling + bool bAddParentheses = true; + if ( eOp < SC_OPCODE_STOP_DIV ) + { + bAddParentheses = false; // will be overridden below if parameters + switch ( eOp ) + { + case ocIf: + aToken.SetByte(3); + break; + case ocIfError: + case ocIfNA: + case ocChoose: + aToken.SetByte(2); + break; + case ocPercentSign: + aToken.SetByte(1); + break; + default:; + } + } + else if ( eOp < SC_OPCODE_STOP_ERRORS ) + { + bAddParentheses = false; + aToken.SetByte(0); + } + else if ( eOp < SC_OPCODE_STOP_BIN_OP ) + { + switch ( eOp ) + { + case ocAnd: + case ocOr: + aToken.SetByte(1); // (r1)AND(r2) --> AND( r1, ...) + break; + default: + aToken.SetByte(2); + } + } + else if ( eOp < SC_OPCODE_STOP_UN_OP ) + aToken.SetByte(1); + else if ( eOp < SC_OPCODE_STOP_NO_PAR ) + aToken.SetByte(0); + else if ( eOp < SC_OPCODE_STOP_1_PAR ) + aToken.SetByte(1); + else + aToken.SetByte( nParams); + // compare (this is a mere test for opcode order Div, BinOp, UnOp, + // NoPar, 1Par, ...) and override parameter count with + // classification + if ( nParams != aToken.GetByte() ) + SAL_WARN("sc.core", "(parameter count differs, token Byte: " << (int)aToken.GetByte() << " classification: " << (int)nParams << ") "); + aToken.SetByte( nParams); + if ( nParams != aToken.GetParamCount() ) + SAL_WARN("sc.core", "(parameter count differs, token ParamCount: " << (int)aToken.GetParamCount() << " classification: " << (int)nParams << ") "); + if (aToken.GetByte()) + bAddParentheses = true; + if (bAddParentheses) + aStr.append('('); + for ( sal_uInt16 j=0; j < nParams; ++j ) + { + if ( j > 0 ) + aStr.append(','); + formula::ParamClass eType = GetParameterType( &aToken, j); + switch ( eType ) + { + case Value : + aStr.append(" Value"); + break; + case Reference : + aStr.append(" Reference"); + break; + case ReferenceOrRefArray : + aStr.append(" ReferenceOrRefArray"); + break; + case Array : + aStr.append(" Array"); + break; + case ForceArray : + aStr.append(" ForceArray"); + break; + case ReferenceOrForceArray : + aStr.append(" ReferenceOrForceArray"); + break; + case Bounds : + aStr.append(" (Bounds, classification error?)"); + break; + default: + aStr.append(" (???, classification error?)"); + } + } + if ( HasRepeatParameters( eOp) ) + aStr.append(", ..."); + if ( nParams ) + aStr.append(' '); + if (bAddParentheses) + aStr.append(')'); + switch ( eOp ) + { + case ocRRI: + aStr.append(" // RRI in English resource, but ZGZ in English-only section"); + break; + case ocMultiArea: + aStr.append(" // e.g. combined first parameter of INDEX() function, not a real function"); + break; + case ocBackSolver: + aStr.append(" // goal seek via menu, not a real function"); + break; + case ocTableOp: + aStr.append(" // MULTIPLE.OPERATIONS in English resource, but TABLE in English-only section"); + break; + case ocNoName: + aStr.append(" // error function, not a real function"); + break; + default:; + } + // Return type. + formula::ParamClass eType = GetParameterType( &aToken, SAL_MAX_UINT16); + switch ( eType ) + { + case Value : + aStr.append(" -> Value"); + break; + case Reference : + aStr.append(" -> Reference"); + break; + case ReferenceOrRefArray : + aStr.append(" -> ReferenceOrRefArray"); + break; + case Array : + aStr.append(" -> Array"); + break; + case ForceArray : + aStr.append(" -> ForceArray"); + break; + case ReferenceOrForceArray : + aStr.append(" -> ReferenceOrForceArray"); + break; + case Bounds : + ; // nothing + break; + default: + aStr.append(" (-> ???, classification error?)"); + } + /* We could add yet another log domain for this, if we wanted... but + * as it more seldom than rarely used it's not actually necessary, + * just grep output. */ + SAL_INFO( "sc.core", "CALC_GENPARCLASSDOC: " << aStr.makeStringAndClear()); + } + } + fflush( stdout); +} + +#endif // OSL_DEBUG_LEVEL + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |