Update ooo320-m1
[ooovba.git] / sc / source / core / tool / parclass.cxx
blob7f5a9c82a505a2dbc6d89755d6de469cc63d4d2c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: parclass.cxx,v $
10 * $Revision: 1.12.148.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
35 #include "parclass.hxx"
36 #include "token.hxx"
37 #include "global.hxx"
38 #include "callform.hxx"
39 #include "addincol.hxx"
40 #include "funcdesc.hxx"
41 #include <unotools/charclass.hxx>
42 #include <tools/debug.hxx>
43 #include <string.h>
45 #if OSL_DEBUG_LEVEL > 1
46 // the documentation thingy
47 #include <stdio.h>
48 #include <com/sun/star/sheet/FormulaLanguage.hpp>
49 #include "compiler.hxx"
50 #include "sc.hrc" // VAR_ARGS
51 #endif
54 /* Following assumptions are made:
55 * - OpCodes not specified at all will have at least one and only parameters of
56 * type Value, no check is done on the count of parameters => no Bounds type
57 * is returned.
58 * - For OpCodes with a variable number of parameters the type of the last
59 * parameter specified determines the type of all following parameters.
62 const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
64 // IF() and CHOOSE() are somewhat special, since the ScJumpMatrix is
65 // created inside those functions and ConvertMatrixParameters() is not
66 // called for them.
67 { ocIf, {{ Array, Reference, Reference }, false }},
68 { ocChose, {{ Array, Reference }, true }},
69 // Other specials.
70 { ocOpen, {{ Bounds }, false }},
71 { ocClose, {{ Bounds }, false }},
72 { ocSep, {{ Bounds }, false }},
73 { ocNoName, {{ Bounds }, false }},
74 { ocErrCell, {{ Bounds }, false }},
75 { ocStop, {{ Bounds }, false }},
76 { ocUnion, {{ Reference, Reference }, false }},
77 { ocRange, {{ Reference, Reference }, false }},
78 // Functions with Value parameters only but not in resource.
79 { ocBackSolver, {{ Value, Value, Value }, false }},
80 { ocTableOp, {{ Value, Value, Value, Value, Value }, false }},
81 // Operators and functions.
82 { ocAdd, {{ Array, Array }, false }},
83 { ocAmpersand, {{ Array, Array }, false }},
84 { ocAnd, {{ Reference }, true }},
85 { ocAreas, {{ Reference }, false }},
86 { ocAveDev, {{ Reference }, true }},
87 { ocAverage, {{ Reference }, true }},
88 { ocAverageA, {{ Reference }, true }},
89 { ocCell, {{ Value, Reference }, false }},
90 { ocColumn, {{ Reference }, false }},
91 { ocColumns, {{ Reference }, true }},
92 { ocCorrel, {{ ForceArray, ForceArray }, false }},
93 { ocCount, {{ Reference }, true }},
94 { ocCount2, {{ Reference }, true }},
95 { ocCountEmptyCells, {{ Reference }, false }},
96 { ocCountIf, {{ Reference, Value }, false }},
97 { ocCovar, {{ ForceArray, ForceArray }, false }},
98 { ocDBAverage, {{ Reference, Reference, Reference }, false }},
99 { ocDBCount, {{ Reference, Reference, Reference }, false }},
100 { ocDBCount2, {{ Reference, Reference, Reference }, false }},
101 { ocDBGet, {{ Reference, Reference, Reference }, false }},
102 { ocDBMax, {{ Reference, Reference, Reference }, false }},
103 { ocDBMin, {{ Reference, Reference, Reference }, false }},
104 { ocDBProduct, {{ Reference, Reference, Reference }, false }},
105 { ocDBStdDev, {{ Reference, Reference, Reference }, false }},
106 { ocDBStdDevP, {{ Reference, Reference, Reference }, false }},
107 { ocDBSum, {{ Reference, Reference, Reference }, false }},
108 { ocDBVar, {{ Reference, Reference, Reference }, false }},
109 { ocDBVarP, {{ Reference, Reference, Reference }, false }},
110 { ocDevSq, {{ Reference }, true }},
111 { ocDiv, {{ Array, Array }, false }},
112 { ocEqual, {{ Array, Array }, false }},
113 { ocForecast, {{ Value, ForceArray, ForceArray }, false }},
114 { ocFrequency, {{ Reference, Reference }, false }},
115 { ocFTest, {{ ForceArray, ForceArray }, false }},
116 { ocGeoMean, {{ Reference }, true }},
117 { ocGCD, {{ Reference }, true }},
118 { ocGreater, {{ Array, Array }, false }},
119 { ocGreaterEqual, {{ Array, Array }, false }},
120 { ocGrowth, {{ Reference, Reference, Reference, Value }, false }},
121 { ocHarMean, {{ Reference }, true }},
122 { ocHLookup, {{ Value, Reference, Value, Value }, false }},
123 { ocIRR, {{ Reference, Value }, false }},
124 { ocIndex, {{ Reference, Value, Value, Value }, false }},
125 { ocIntercept, {{ ForceArray, ForceArray }, false }},
126 { ocIntersect, {{ Reference, Reference }, false }},
127 { ocIsRef, {{ Reference }, false }},
128 { ocLCM, {{ Reference }, true }},
129 { ocKurt, {{ Reference }, true }},
130 { ocLarge, {{ Reference, Value }, false }},
131 { ocLess, {{ Array, Array }, false }},
132 { ocLessEqual, {{ Array, Array }, false }},
133 { ocLookup, {{ Value, ReferenceOrForceArray, ReferenceOrForceArray }, false }},
134 { ocMatch, {{ Value, Reference, Reference }, false }},
135 { ocMatDet, {{ ForceArray }, false }},
136 { ocMatInv, {{ ForceArray }, false }},
137 { ocMatMult, {{ ForceArray, ForceArray }, false }},
138 { ocMatTrans, {{ Array }, false }}, // strange, but Xcl doesn't force MatTrans array
139 { ocMatValue, {{ Reference, Value, Value }, false }},
140 { ocMax, {{ Reference }, true }},
141 { ocMaxA, {{ Reference }, true }},
142 { ocMedian, {{ Reference }, true }},
143 { ocMin, {{ Reference }, true }},
144 { ocMinA, {{ Reference }, true }},
145 { ocMIRR, {{ Reference, Value, Value }, false }},
146 { ocModalValue, {{ ForceArray }, true }},
147 { ocMul, {{ Array, Array }, false }},
148 { ocMultiArea, {{ Reference }, true }},
149 { ocN, {{ Reference }, false }},
150 { ocNPV, {{ Value, Reference }, true }},
151 { ocNeg, {{ Array }, false }},
152 { ocNegSub, {{ Array }, false }},
153 { ocNot, {{ Array }, false }},
154 { ocNotEqual, {{ Array, Array }, false }},
155 { ocOffset, {{ Reference, Value, Value, Value, Value }, false }},
156 { ocOr, {{ Reference }, true }},
157 { ocPearson, {{ ForceArray, ForceArray }, false }},
158 { ocPercentile, {{ Reference, Value }, false }},
159 { ocPercentrank, {{ Reference, Value }, false }},
160 { ocPow, {{ Array, Array }, false }},
161 { ocPower, {{ Array, Array }, false }},
162 { ocProb, {{ ForceArray, ForceArray, Value, Value }, false }},
163 { ocProduct, {{ Reference }, true }},
164 { ocQuartile, {{ Reference, Value }, false }},
165 { ocRank, {{ Value, Reference, Value }, false }},
166 { ocRGP, {{ Reference, Reference, Value, Value }, false }},
167 { ocRKP, {{ Reference, Reference, Value, Value }, false }},
168 { ocRow, {{ Reference }, false }},
169 { ocRows, {{ Reference }, true }},
170 { ocRSQ, {{ ForceArray, ForceArray }, false }},
171 { ocSchiefe, {{ Reference }, true }},
172 { ocSlope, {{ ForceArray, ForceArray }, false }},
173 { ocSmall, {{ Reference, Value }, false }},
174 { ocStDev, {{ Reference }, true }},
175 { ocStDevA, {{ Reference }, true }},
176 { ocStDevP, {{ Reference }, true }},
177 { ocStDevPA, {{ Reference }, true }},
178 { ocSTEYX, {{ ForceArray, ForceArray }, false }},
179 { ocSub, {{ Array, Array }, false }},
180 { ocSubTotal, {{ Value, Reference }, true }},
181 { ocSum, {{ Reference }, true }},
182 { ocSumIf, {{ Reference, Value, Reference }, false }},
183 { ocSumProduct, {{ ForceArray }, true }},
184 { ocSumSQ, {{ Reference }, true }},
185 { ocSumX2MY2, {{ ForceArray, ForceArray }, false }},
186 { ocSumX2DY2, {{ ForceArray, ForceArray }, false }},
187 { ocSumXMY2, {{ ForceArray, ForceArray }, false }},
188 { ocTable, {{ Reference }, false }},
189 { ocTables, {{ Reference }, true }},
190 { ocTrend, {{ Reference, Reference, Reference, Value }, false }},
191 { ocTrimMean, {{ Reference, Value }, false }},
192 { ocTTest, {{ ForceArray, ForceArray, Value, Value }, false }},
193 { ocVar, {{ Reference }, true }},
194 { ocVarA, {{ Reference }, true }},
195 { ocVarP, {{ Reference }, true }},
196 { ocVarPA, {{ Reference }, true }},
197 { ocVLookup, {{ Value, Reference, Value, Value }, false }},
198 { ocZTest, {{ Reference, Value, Value }, false }},
199 // Excel doubts:
200 // ocT: Excel says (and handles) Reference, error? This means no position
201 // dependent SingleRef if DoubleRef, and no array calculation, just the
202 // upper left corner. We never did that.
203 { ocT, {{ Value }, false }},
204 // The stopper.
205 { ocNone, {{ Bounds }, false } }
208 ScParameterClassification::RunData * ScParameterClassification::pData = NULL;
211 void ScParameterClassification::Init()
213 if ( pData )
214 return;
215 pData = new RunData[ SC_OPCODE_LAST_OPCODE_ID + 1 ];
216 memset( pData, 0, sizeof(RunData) * (SC_OPCODE_LAST_OPCODE_ID + 1));
218 // init from specified static data above
219 for ( size_t i=0; i < sizeof(pRawData) / sizeof(RawData); ++i )
221 const RawData* pRaw = &pRawData[i];
222 if ( pRaw->eOp > SC_OPCODE_LAST_OPCODE_ID )
224 DBG_ASSERT( pRaw->eOp == ocNone, "RawData OpCode error");
226 else
228 RunData* pRun = &pData[ pRaw->eOp ];
229 #ifdef DBG_UTIL
230 if ( pRun->aData.nParam[0] != Unknown )
232 DBG_ERROR1( "already assigned: %d", pRaw->eOp);
234 #endif
235 memcpy( &(pRun->aData), &(pRaw->aData), sizeof(CommonData));
236 // fill 0-initialized fields with real values
237 if ( pRun->aData.bRepeatLast )
239 Type eLast = Unknown;
240 for ( size_t j=0; j < CommonData::nMaxParams; ++j )
242 if ( pRun->aData.nParam[j] )
244 eLast = pRun->aData.nParam[j];
245 pRun->nMinParams = sal::static_int_cast<BYTE>( j+1 );
247 else
248 pRun->aData.nParam[j] = eLast;
251 else
253 for ( size_t j=0; j < CommonData::nMaxParams; ++j )
255 if ( !pRun->aData.nParam[j] )
257 if ( j == 0 || pRun->aData.nParam[j-1] != Bounds )
258 pRun->nMinParams = sal::static_int_cast<BYTE>( j );
259 pRun->aData.nParam[j] = Bounds;
262 if ( !pRun->nMinParams &&
263 pRun->aData.nParam[CommonData::nMaxParams-1] != Bounds)
264 pRun->nMinParams = CommonData::nMaxParams;
266 for ( size_t j=0; j < CommonData::nMaxParams; ++j )
268 if ( pRun->aData.nParam[j] == ForceArray || pRun->aData.nParam[j] == ReferenceOrForceArray )
270 pRun->bHasForceArray = true;
271 break; // for
277 #if OSL_DEBUG_LEVEL > 1
278 GenerateDocumentation();
279 #endif
283 void ScParameterClassification::Exit()
285 delete [] pData;
286 pData = NULL;
290 ScParameterClassification::Type ScParameterClassification::GetParameterType(
291 const formula::FormulaToken* pToken, USHORT nParameter)
293 OpCode eOp = pToken->GetOpCode();
294 switch ( eOp )
296 case ocExternal:
297 return GetExternalParameterType( pToken, nParameter);
298 //break;
299 case ocMacro:
300 return Reference;
301 //break;
302 default:
304 // added to avoid warnings
307 if ( 0 <= (short)eOp && eOp <= SC_OPCODE_LAST_OPCODE_ID )
309 if ( nParameter < CommonData::nMaxParams )
311 Type eT = pData[eOp].aData.nParam[nParameter];
312 return eT == Unknown ? Value : eT;
314 else if ( pData[eOp].aData.bRepeatLast )
315 return pData[eOp].aData.nParam[CommonData::nMaxParams-1];
316 else
317 return Bounds;
319 return Unknown;
323 ScParameterClassification::Type
324 ScParameterClassification::GetExternalParameterType( const formula::FormulaToken* pToken,
325 USHORT nParameter)
327 Type eRet = Unknown;
328 // similar to ScInterpreter::ScExternal()
329 USHORT nIndex;
330 String aUnoName;
331 String aFuncName( ScGlobal::pCharClass->upper( pToken->GetExternal()));
332 if ( ScGlobal::GetFuncCollection()->SearchFunc( aFuncName, nIndex) )
334 FuncData* pFuncData = (FuncData*)ScGlobal::GetFuncCollection()->At(
335 nIndex);
336 if ( nParameter >= pFuncData->GetParamCount() )
337 eRet = Bounds;
338 else
340 switch ( pFuncData->GetParamType( nParameter) )
342 case PTR_DOUBLE:
343 case PTR_STRING:
344 eRet = Value;
345 break;
346 default:
347 eRet = Reference;
348 // also array types are created using an area reference
352 else if ( (aUnoName = ScGlobal::GetAddInCollection()->FindFunction(
353 aFuncName, FALSE)).Len() )
355 // the relevant parts of ScUnoAddInCall without having to create one
356 const ScUnoAddInFuncData* pFuncData =
357 ScGlobal::GetAddInCollection()->GetFuncData( aUnoName, true ); // need fully initialized data
358 if ( pFuncData )
360 long nCount = pFuncData->GetArgumentCount();
361 if ( nCount <= 0 )
362 eRet = Bounds;
363 else
365 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
366 if ( nParameter >= nCount &&
367 pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
368 eRet = Value;
369 // last arg is sequence, optional "any"s, we simply can't
370 // determine the type
371 if ( eRet == Unknown )
373 if ( nParameter >= nCount )
374 eRet = Bounds;
375 else
377 switch ( pArgs[nParameter].eType )
379 case SC_ADDINARG_INTEGER:
380 case SC_ADDINARG_DOUBLE:
381 case SC_ADDINARG_STRING:
382 eRet = Value;
383 break;
384 default:
385 eRet = Reference;
392 return eRet;
395 //-----------------------------------------------------------------------------
397 #if OSL_DEBUG_LEVEL > 1
399 // add remaining functions, all Value parameters
400 void ScParameterClassification::MergeArgumentsFromFunctionResource()
402 ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
403 for ( const ScFuncDesc* pDesc = pFuncList->First(); pDesc;
404 pDesc = pFuncList->Next() )
406 if ( pDesc->nFIndex > SC_OPCODE_LAST_OPCODE_ID ||
407 pData[pDesc->nFIndex].aData.nParam[0] != Unknown )
408 continue; // not an internal opcode or already done
410 RunData* pRun = &pData[ pDesc->nFIndex ];
411 USHORT nArgs = pDesc->GetSuppressedArgCount();
412 if ( nArgs >= VAR_ARGS )
414 nArgs -= VAR_ARGS - 1;
415 pRun->aData.bRepeatLast = true;
417 if ( nArgs > CommonData::nMaxParams )
419 DBG_ERROR2( "ScParameterClassification::Init: too many arguments in listed function: %s: %d",
420 ByteString( *(pDesc->pFuncName),
421 RTL_TEXTENCODING_UTF8).GetBuffer(), nArgs);
422 nArgs = CommonData::nMaxParams;
423 pRun->aData.bRepeatLast = true;
425 pRun->nMinParams = static_cast< BYTE >( nArgs );
426 for ( size_t j=0; j < nArgs; ++j )
428 pRun->aData.nParam[j] = Value;
430 if ( pRun->aData.bRepeatLast )
432 for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j )
434 pRun->aData.nParam[j] = Value;
437 else
439 for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j )
441 pRun->aData.nParam[j] = Bounds;
448 void ScParameterClassification::GenerateDocumentation()
450 static const sal_Char aEnvVarName[] = "OOO_CALC_GENPARCLASSDOC";
451 if ( !getenv( aEnvVarName) )
452 return;
453 MergeArgumentsFromFunctionResource();
454 ScAddress aAddress;
455 ScCompiler aComp(NULL,aAddress);
456 ScCompiler::OpCodeMapPtr xMap( aComp.GetOpCodeMap(::com::sun::star::sheet::FormulaLanguage::ENGLISH));
457 if (!xMap)
458 return;
459 fflush( stderr);
460 size_t nCount = xMap->getSymbolCount();
461 for ( size_t i=0; i<nCount; ++i )
463 OpCode eOp = OpCode(i);
464 if ( xMap->getSymbol(eOp).Len() )
466 fprintf( stdout, "%s: ", aEnvVarName);
467 ByteString aStr( xMap->getSymbol(eOp), RTL_TEXTENCODING_UTF8);
468 aStr += "(";
469 formula::FormulaByteToken aToken( eOp);
470 BYTE nParams = GetMinimumParameters( eOp);
471 // preset parameter count according to opcode value, with some
472 // special handling
473 if ( eOp < SC_OPCODE_STOP_DIV )
475 switch ( eOp )
477 case ocIf:
478 aToken.SetByte(3);
479 break;
480 case ocChose:
481 aToken.SetByte(2);
482 break;
483 case ocPercentSign:
484 aToken.SetByte(1);
485 break;
486 default:;
489 else if ( eOp < SC_OPCODE_STOP_ERRORS )
490 aToken.SetByte(0);
491 else if ( eOp < SC_OPCODE_STOP_BIN_OP )
493 switch ( eOp )
495 case ocAnd:
496 case ocOr:
497 aToken.SetByte(1); // (r1)AND(r2) --> AND( r1, ...)
498 break;
499 default:
500 aToken.SetByte(2);
503 else if ( eOp < SC_OPCODE_STOP_UN_OP )
504 aToken.SetByte(1);
505 else if ( eOp < SC_OPCODE_STOP_NO_PAR )
506 aToken.SetByte(0);
507 else if ( eOp < SC_OPCODE_STOP_1_PAR )
508 aToken.SetByte(1);
509 else
510 aToken.SetByte( nParams);
511 // compare (this is a mere test for opcode order Div, BinOp, UnOp,
512 // NoPar, 1Par, ...) and override parameter count with
513 // classification
514 if ( nParams != aToken.GetByte() )
515 fprintf( stdout, "(parameter count differs, token Byte: %d classification: %d) ",
516 aToken.GetByte(), nParams);
517 aToken.SetByte( nParams);
518 if ( nParams != aToken.GetParamCount() )
519 fprintf( stdout, "(parameter count differs, token ParamCount: %d classification: %d) ",
520 aToken.GetParamCount(), nParams);
521 for ( USHORT j=0; j < nParams; ++j )
523 if ( j > 0 )
524 aStr += ",";
525 Type eType = GetParameterType( &aToken, j);
526 switch ( eType )
528 case Value :
529 aStr += " Value";
530 break;
531 case Reference :
532 aStr += " Reference";
533 break;
534 case Array :
535 aStr += " Array";
536 break;
537 case ForceArray :
538 aStr += " ForceArray";
539 break;
540 case ReferenceOrForceArray :
541 aStr += " ReferenceOrForceArray";
542 break;
543 case Bounds :
544 aStr += " (Bounds, classification error?)";
545 break;
546 default:
547 aStr += " (???, classification error?)";
550 if ( HasRepeatParameters( eOp) )
551 aStr += ", ...";
552 if ( nParams )
553 aStr += " ";
554 aStr += ")";
555 switch ( eOp )
557 case ocZGZ:
558 aStr += " // RRI in English resource, but ZGZ in English-only section";
559 break;
560 case ocMultiArea:
561 aStr += " // e.g. combined first parameter of INDEX() function, not a real function";
562 break;
563 case ocBackSolver:
564 aStr += " // goal seek via menu, not a real function";
565 break;
566 case ocTableOp:
567 aStr += " // MULTIPLE.OPERATIONS in English resource, but TABLE in English-only section";
568 break;
569 case ocNoName:
570 aStr += " // error function, not a real function";
571 break;
572 default:;
574 fprintf( stdout, "%s\n", aStr.GetBuffer());
577 fflush( stdout);
580 #endif // OSL_DEBUG_LEVEL