1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
38 #include "callform.hxx"
39 #include "addincol.hxx"
40 #include "funcdesc.hxx"
41 #include <unotools/charclass.hxx>
42 #include <tools/debug.hxx>
45 #if OSL_DEBUG_LEVEL > 1
46 // the documentation thingy
48 #include <com/sun/star/sheet/FormulaLanguage.hpp>
49 #include "compiler.hxx"
50 #include "sc.hrc" // VAR_ARGS
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
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
67 { ocIf
, {{ Array
, Reference
, Reference
}, false }},
68 { ocChose
, {{ Array
, Reference
}, true }},
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 }},
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 }},
205 { ocNone
, {{ Bounds
}, false } }
208 ScParameterClassification::RunData
* ScParameterClassification::pData
= NULL
;
211 void ScParameterClassification::Init()
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");
228 RunData
* pRun
= &pData
[ pRaw
->eOp
];
230 if ( pRun
->aData
.nParam
[0] != Unknown
)
232 DBG_ERROR1( "already assigned: %d", pRaw
->eOp
);
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 );
248 pRun
->aData
.nParam
[j
] = eLast
;
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;
277 #if OSL_DEBUG_LEVEL > 1
278 GenerateDocumentation();
283 void ScParameterClassification::Exit()
290 ScParameterClassification::Type
ScParameterClassification::GetParameterType(
291 const formula::FormulaToken
* pToken
, USHORT nParameter
)
293 OpCode eOp
= pToken
->GetOpCode();
297 return GetExternalParameterType( pToken
, nParameter
);
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];
323 ScParameterClassification::Type
324 ScParameterClassification::GetExternalParameterType( const formula::FormulaToken
* pToken
,
328 // similar to ScInterpreter::ScExternal()
331 String
aFuncName( ScGlobal::pCharClass
->upper( pToken
->GetExternal()));
332 if ( ScGlobal::GetFuncCollection()->SearchFunc( aFuncName
, nIndex
) )
334 FuncData
* pFuncData
= (FuncData
*)ScGlobal::GetFuncCollection()->At(
336 if ( nParameter
>= pFuncData
->GetParamCount() )
340 switch ( pFuncData
->GetParamType( nParameter
) )
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
360 long nCount
= pFuncData
->GetArgumentCount();
365 const ScAddInArgDesc
* pArgs
= pFuncData
->GetArguments();
366 if ( nParameter
>= nCount
&&
367 pArgs
[nCount
-1].eType
== SC_ADDINARG_VARARGS
)
369 // last arg is sequence, optional "any"s, we simply can't
370 // determine the type
371 if ( eRet
== Unknown
)
373 if ( nParameter
>= nCount
)
377 switch ( pArgs
[nParameter
].eType
)
379 case SC_ADDINARG_INTEGER
:
380 case SC_ADDINARG_DOUBLE
:
381 case SC_ADDINARG_STRING
:
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
;
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
) )
453 MergeArgumentsFromFunctionResource();
455 ScCompiler
aComp(NULL
,aAddress
);
456 ScCompiler::OpCodeMapPtr
xMap( aComp
.GetOpCodeMap(::com::sun::star::sheet::FormulaLanguage::ENGLISH
));
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
);
469 formula::FormulaByteToken
aToken( eOp
);
470 BYTE nParams
= GetMinimumParameters( eOp
);
471 // preset parameter count according to opcode value, with some
473 if ( eOp
< SC_OPCODE_STOP_DIV
)
489 else if ( eOp
< SC_OPCODE_STOP_ERRORS
)
491 else if ( eOp
< SC_OPCODE_STOP_BIN_OP
)
497 aToken
.SetByte(1); // (r1)AND(r2) --> AND( r1, ...)
503 else if ( eOp
< SC_OPCODE_STOP_UN_OP
)
505 else if ( eOp
< SC_OPCODE_STOP_NO_PAR
)
507 else if ( eOp
< SC_OPCODE_STOP_1_PAR
)
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
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
)
525 Type eType
= GetParameterType( &aToken
, j
);
532 aStr
+= " Reference";
538 aStr
+= " ForceArray";
540 case ReferenceOrForceArray
:
541 aStr
+= " ReferenceOrForceArray";
544 aStr
+= " (Bounds, classification error?)";
547 aStr
+= " (???, classification error?)";
550 if ( HasRepeatParameters( eOp
) )
558 aStr
+= " // RRI in English resource, but ZGZ in English-only section";
561 aStr
+= " // e.g. combined first parameter of INDEX() function, not a real function";
564 aStr
+= " // goal seek via menu, not a real function";
567 aStr
+= " // MULTIPLE.OPERATIONS in English resource, but TABLE in English-only section";
570 aStr
+= " // error function, not a real function";
574 fprintf( stdout
, "%s\n", aStr
.GetBuffer());
580 #endif // OSL_DEBUG_LEVEL