1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "parclass.hxx"
23 #include "callform.hxx"
24 #include "addincol.hxx"
25 #include "funcdesc.hxx"
26 #include <unotools/charclass.hxx>
27 #include <osl/diagnose.h>
28 #include <sal/macros.h>
31 #if OSL_DEBUG_LEVEL > 1
32 // the documentation thingy
34 #include <com/sun/star/sheet/FormulaLanguage.hpp>
35 #include <rtl/strbuf.hxx>
36 #include "compiler.hxx"
40 /* Following assumptions are made:
41 * - OpCodes not specified at all will have at least one and only parameters of
42 * type Value, no check is done on the count of parameters => no Bounds type
44 * - For OpCodes with a variable number of parameters the type(s) of the last
45 * repeated parameter(s) specified determine(s) the type(s) of all following
49 const ScParameterClassification::RawData
ScParameterClassification::pRawData
[] =
51 // { OpCode, {{ Type, ... }, nRepeatLast }},
53 // IF() and CHOOSE() are somewhat special, since the ScJumpMatrix is
54 // created inside those functions and ConvertMatrixParameters() is not
56 { ocIf
, {{ Array
, Reference
, Reference
}, 0 }},
57 { ocIfError
, {{ Array
, Reference
}, 0 }},
58 { ocIfNA
, {{ Array
, Reference
}, 0 }},
59 { ocChoose
, {{ Array
, Reference
}, 1 }},
61 { ocOpen
, {{ Bounds
}, 0 }},
62 { ocClose
, {{ Bounds
}, 0 }},
63 { ocSep
, {{ Bounds
}, 0 }},
64 { ocNoName
, {{ Bounds
}, 0 }},
65 { ocStop
, {{ Bounds
}, 0 }},
66 { ocUnion
, {{ Reference
, Reference
}, 0 }},
67 { ocRange
, {{ Reference
, Reference
}, 0 }},
68 // Functions with Value parameters only but not in resource.
69 { ocBackSolver
, {{ Value
, Value
, Value
}, 0 }},
70 { ocTableOp
, {{ Value
, Value
, Value
, Value
, Value
}, 0 }},
71 // Operators and functions.
72 { ocAdd
, {{ Array
, Array
}, 0 }},
73 { ocAmpersand
, {{ Array
, Array
}, 0 }},
74 { ocAnd
, {{ Reference
}, 1 }},
75 { ocAreas
, {{ Reference
}, 0 }},
76 { ocAveDev
, {{ Reference
}, 1 }},
77 { ocAverage
, {{ Reference
}, 1 }},
78 { ocAverageA
, {{ Reference
}, 1 }},
79 { ocAverageIf
, {{ Reference
, Value
, Reference
}, 0 }},
80 { ocAverageIfs
, {{ Reference
, Reference
, Value
}, 2 }},
81 { ocCell
, {{ Value
, Reference
}, 0 }},
82 { ocColumn
, {{ Reference
}, 0 }},
83 { ocColumns
, {{ Reference
}, 1 }},
84 { ocCorrel
, {{ ForceArray
, ForceArray
}, 0 }},
85 { ocCount
, {{ Reference
}, 1 }},
86 { ocCount2
, {{ Reference
}, 1 }},
87 { ocCountEmptyCells
, {{ Reference
}, 0 }},
88 { ocCountIf
, {{ Reference
, Value
}, 0 }},
89 { ocCountIfs
, {{ Reference
, Value
}, 2 }},
90 { ocCovar
, {{ ForceArray
, ForceArray
}, 0 }},
91 { ocCovarianceP
, {{ ForceArray
, ForceArray
}, 0 }},
92 { ocCovarianceS
, {{ ForceArray
, ForceArray
}, 0 }},
93 { ocDBAverage
, {{ Reference
, Reference
, Reference
}, 0 }},
94 { ocDBCount
, {{ Reference
, Reference
, Reference
}, 0 }},
95 { ocDBCount2
, {{ Reference
, Reference
, Reference
}, 0 }},
96 { ocDBGet
, {{ Reference
, Reference
, Reference
}, 0 }},
97 { ocDBMax
, {{ Reference
, Reference
, Reference
}, 0 }},
98 { ocDBMin
, {{ Reference
, Reference
, Reference
}, 0 }},
99 { ocDBProduct
, {{ Reference
, Reference
, Reference
}, 0 }},
100 { ocDBStdDev
, {{ Reference
, Reference
, Reference
}, 0 }},
101 { ocDBStdDevP
, {{ Reference
, Reference
, Reference
}, 0 }},
102 { ocDBSum
, {{ Reference
, Reference
, Reference
}, 0 }},
103 { ocDBVar
, {{ Reference
, Reference
, Reference
}, 0 }},
104 { ocDBVarP
, {{ Reference
, Reference
, Reference
}, 0 }},
105 { ocDevSq
, {{ Reference
}, 1 }},
106 { ocDiv
, {{ Array
, Array
}, 0 }},
107 { ocEqual
, {{ Array
, Array
}, 0 }},
108 { ocForecast
, {{ Value
, ForceArray
, ForceArray
}, 0 }},
109 { ocFrequency
, {{ Reference
, Reference
}, 0 }},
110 { ocFTest
, {{ ForceArray
, ForceArray
}, 0 }},
111 { ocGeoMean
, {{ Reference
}, 1 }},
112 { ocGCD
, {{ Reference
}, 1 }},
113 { ocGreater
, {{ Array
, Array
}, 0 }},
114 { ocGreaterEqual
, {{ Array
, Array
}, 0 }},
115 { ocGrowth
, {{ Reference
, Reference
, Reference
, Value
}, 0 }},
116 { ocHarMean
, {{ Reference
}, 1 }},
117 { ocHLookup
, {{ Value
, ReferenceOrForceArray
, Value
, Value
}, 0 }},
118 { ocIRR
, {{ Reference
, Value
}, 0 }},
119 { ocIndex
, {{ Reference
, Value
, Value
, Value
}, 0 }},
120 { ocIntercept
, {{ ForceArray
, ForceArray
}, 0 }},
121 { ocIntersect
, {{ Reference
, Reference
}, 0 }},
122 { ocIsRef
, {{ Reference
}, 0 }},
123 { ocLCM
, {{ Reference
}, 1 }},
124 { ocKurt
, {{ Reference
}, 1 }},
125 { ocLarge
, {{ Reference
, Value
}, 0 }},
126 { ocLess
, {{ Array
, Array
}, 0 }},
127 { ocLessEqual
, {{ Array
, Array
}, 0 }},
128 { ocLookup
, {{ Value
, ReferenceOrForceArray
, ReferenceOrForceArray
}, 0 }},
129 { ocMatch
, {{ Value
, ReferenceOrForceArray
, Value
}, 0 }},
130 { ocMatDet
, {{ ForceArray
}, 0 }},
131 { ocMatInv
, {{ ForceArray
}, 0 }},
132 { ocMatMult
, {{ ForceArray
, ForceArray
}, 0 }},
133 { ocMatTrans
, {{ Array
}, 0 }}, // strange, but Xcl doesn't force MatTrans array
134 { ocMatValue
, {{ Reference
, Value
, Value
}, 0 }},
135 { ocMax
, {{ Reference
}, 1 }},
136 { ocMaxA
, {{ Reference
}, 1 }},
137 { ocMedian
, {{ Reference
}, 1 }},
138 { ocMin
, {{ Reference
}, 1 }},
139 { ocMinA
, {{ Reference
}, 1 }},
140 { ocMIRR
, {{ Reference
, Value
, Value
}, 0 }},
141 { ocModalValue
, {{ ForceArray
}, 1 }},
142 { ocModalValue_MS
, {{ ForceArray
}, 1 }},
143 { ocModalValue_Multi
,{{ ForceArray
}, 1 }},
144 { ocMul
, {{ Array
, Array
}, 0 }},
145 { ocMultiArea
, {{ Reference
}, 1 }},
146 { ocNPV
, {{ Value
, Reference
}, 1 }},
147 { ocNeg
, {{ Array
}, 0 }},
148 { ocNegSub
, {{ Array
}, 0 }},
149 { ocNot
, {{ Array
}, 0 }},
150 { ocNotEqual
, {{ Array
, Array
}, 0 }},
151 { ocOffset
, {{ Reference
, Value
, Value
, Value
, Value
}, 0 }},
152 { ocOr
, {{ Reference
}, 1 }},
153 { ocPearson
, {{ ForceArray
, ForceArray
}, 0 }},
154 { ocPercentile
, {{ Reference
, Value
}, 0 }},
155 { ocPercentile_Exc
, {{ Reference
, Value
}, 0 }},
156 { ocPercentile_Inc
, {{ Reference
, Value
}, 0 }},
157 { ocPercentrank
, {{ Reference
, Value
, Value
}, 0 }},
158 { ocPercentrank_Exc
, {{ Reference
, Value
, Value
}, 0 }},
159 { ocPercentrank_Inc
, {{ Reference
, Value
, Value
}, 0 }},
160 { ocPow
, {{ Array
, Array
}, 0 }},
161 { ocPower
, {{ Array
, Array
}, 0 }},
162 { ocProb
, {{ ForceArray
, ForceArray
, Value
, Value
}, 0 }},
163 { ocProduct
, {{ Reference
}, 1 }},
164 { ocQuartile
, {{ Reference
, Value
}, 0 }},
165 { ocQuartile_Exc
, {{ Reference
, Value
}, 0 }},
166 { ocQuartile_Inc
, {{ Reference
, Value
}, 0 }},
167 { ocRank
, {{ Value
, Reference
, Value
}, 0 }},
168 { ocRank_Avg
, {{ Value
, Reference
, Value
}, 0 }},
169 { ocRank_Eq
, {{ Value
, Reference
, Value
}, 0 }},
170 { ocLinest
, {{ ForceArray
, ForceArray
, Value
, Value
}, 0 }},
171 { ocLogest
, {{ ForceArray
, ForceArray
, Value
, Value
}, 0 }},
172 { ocRow
, {{ Reference
}, 0 }},
173 { ocRows
, {{ Reference
}, 1 }},
174 { ocRSQ
, {{ ForceArray
, ForceArray
}, 0 }},
175 { ocSkew
, {{ Reference
}, 1 }},
176 { ocSkewp
, {{ Reference
}, 1 }},
177 { ocSlope
, {{ ForceArray
, ForceArray
}, 0 }},
178 { ocSmall
, {{ Reference
, Value
}, 0 }},
179 { ocStDev
, {{ Reference
}, 1 }},
180 { ocStDevA
, {{ Reference
}, 1 }},
181 { ocStDevP
, {{ Reference
}, 1 }},
182 { ocStDevPA
, {{ Reference
}, 1 }},
183 { ocStDevP_MS
, {{ Reference
}, 1 }},
184 { ocStDevS
, {{ Reference
}, 1 }},
185 { ocSTEYX
, {{ ForceArray
, ForceArray
}, 0 }},
186 { ocSub
, {{ Array
, Array
}, 0 }},
187 { ocSubTotal
, {{ Value
, Reference
}, 1 }},
188 { ocSum
, {{ Reference
}, 1 }},
189 { ocSumIf
, {{ Reference
, Value
, Reference
}, 0 }},
190 { ocSumIfs
, {{ Reference
, Reference
, Value
}, 2 }},
191 { ocSumProduct
, {{ ForceArray
}, 1 }},
192 { ocSumSQ
, {{ Reference
}, 1 }},
193 { ocSumX2MY2
, {{ ForceArray
, ForceArray
}, 0 }},
194 { ocSumX2DY2
, {{ ForceArray
, ForceArray
}, 0 }},
195 { ocSumXMY2
, {{ ForceArray
, ForceArray
}, 0 }},
196 { ocSheet
, {{ Reference
}, 0 }},
197 { ocSheets
, {{ Reference
}, 1 }},
198 { ocTrend
, {{ Reference
, Reference
, Reference
, Value
}, 0 }},
199 { ocTrimMean
, {{ Reference
, Value
}, 0 }},
200 { ocTTest
, {{ ForceArray
, ForceArray
, Value
, Value
}, 0 }},
201 { ocVar
, {{ Reference
}, 1 }},
202 { ocVarA
, {{ Reference
}, 1 }},
203 { ocVarP
, {{ Reference
}, 1 }},
204 { ocVarPA
, {{ Reference
}, 1 }},
205 { ocVarP_MS
, {{ Reference
}, 1 }},
206 { ocVarS
, {{ Reference
}, 1 }},
207 { ocVLookup
, {{ Value
, ReferenceOrForceArray
, Value
, Value
}, 0 }},
208 { ocXor
, {{ Reference
}, 1 }},
209 { ocZTest
, {{ Reference
, Value
, Value
}, 0 }},
210 { ocZTest_MS
, {{ Reference
, Value
, Value
}, 0 }},
211 { ocNetWorkdays
, {{ Value
, Value
, Reference
, Reference
}, 0 }},
212 { ocNetWorkdays_MS
, {{ Value
, Value
, Value
, Reference
}, 0 }},
213 { ocWorkday_MS
, {{ Value
, Value
, Value
, Reference
}, 0 }},
214 { ocAggregate
, {{ Value
, Value
, Reference
}, 1 }},
216 // ocN, ocT: Excel says (and handles) Reference, error? This means no
217 // position dependent SingleRef if DoubleRef, and no array calculation,
218 // just the upper left corner. We never did that for ocT and now also not
219 // for ocN (position dependent intersection worked before but array
220 // didn't). No specifics in ODFF, so the general rule applies. Gnumeric
222 { ocN
, {{ Value
}, 0 }},
223 { ocT
, {{ Value
}, 0 }},
225 { ocNone
, {{ Bounds
}, 0 } }
228 ScParameterClassification::RunData
* ScParameterClassification::pData
= NULL
;
230 void ScParameterClassification::Init()
234 pData
= new RunData
[ SC_OPCODE_LAST_OPCODE_ID
+ 1 ];
235 memset( pData
, 0, sizeof(RunData
) * (SC_OPCODE_LAST_OPCODE_ID
+ 1));
237 // init from specified static data above
238 for ( size_t i
=0; i
< SAL_N_ELEMENTS(pRawData
); ++i
)
240 const RawData
* pRaw
= &pRawData
[i
];
241 if ( pRaw
->eOp
> SC_OPCODE_LAST_OPCODE_ID
)
243 OSL_ENSURE( pRaw
->eOp
== ocNone
, "RawData OpCode error");
247 RunData
* pRun
= &pData
[ pRaw
->eOp
];
248 #if OSL_DEBUG_LEVEL > 1
249 if ( pRun
->aData
.nParam
[0] != Unknown
)
251 OSL_TRACE( "already assigned: %d", pRaw
->eOp
);
254 memcpy( &(pRun
->aData
), &(pRaw
->aData
), sizeof(CommonData
));
255 // fill 0-initialized fields with real values
256 if ( pRun
->aData
.nRepeatLast
)
258 for ( sal_Int32 j
=0; j
< CommonData::nMaxParams
; ++j
)
260 if ( pRun
->aData
.nParam
[j
] )
261 pRun
->nMinParams
= sal::static_int_cast
<sal_uInt8
>( j
+1 );
262 else if (j
>= pRun
->aData
.nRepeatLast
)
263 pRun
->aData
.nParam
[j
] = pRun
->aData
.nParam
[j
- pRun
->aData
.nRepeatLast
];
268 "bad classification: eOp " << +pRaw
->eOp
269 << ", repeated param " << j
270 << " negative offset");
271 pRun
->aData
.nParam
[j
] = Unknown
;
277 for ( sal_Int32 j
=0; j
< CommonData::nMaxParams
; ++j
)
279 if ( !pRun
->aData
.nParam
[j
] )
281 if ( j
== 0 || pRun
->aData
.nParam
[j
-1] != Bounds
)
282 pRun
->nMinParams
= sal::static_int_cast
<sal_uInt8
>( j
);
283 pRun
->aData
.nParam
[j
] = Bounds
;
286 if ( !pRun
->nMinParams
&&
287 pRun
->aData
.nParam
[CommonData::nMaxParams
-1] != Bounds
)
288 pRun
->nMinParams
= CommonData::nMaxParams
;
290 for ( sal_Int32 j
=0; j
< CommonData::nMaxParams
; ++j
)
292 if ( pRun
->aData
.nParam
[j
] == ForceArray
|| pRun
->aData
.nParam
[j
] == ReferenceOrForceArray
)
294 pRun
->bHasForceArray
= true;
301 #if OSL_DEBUG_LEVEL > 1
302 GenerateDocumentation();
306 void ScParameterClassification::Exit()
312 ScParameterClassification::Type
ScParameterClassification::GetParameterType(
313 const formula::FormulaToken
* pToken
, sal_uInt16 nParameter
)
315 OpCode eOp
= pToken
->GetOpCode();
319 return GetExternalParameterType( pToken
, nParameter
);
324 // added to avoid warnings
327 if ( 0 <= (short)eOp
&& eOp
<= SC_OPCODE_LAST_OPCODE_ID
)
331 if ( nParameter
< CommonData::nMaxParams
)
332 eType
= pData
[eOp
].aData
.nParam
[nParameter
];
333 else if ( (nRepeat
= pData
[eOp
].aData
.nRepeatLast
) > 0 )
335 // The usual case is 1 repeated parameter, we don't need to
336 // calculate that on each call.
337 sal_uInt16 nParam
= (nRepeat
> 1 ?
338 (pData
[eOp
].nMinParams
-
339 ((nParameter
- pData
[eOp
].nMinParams
) % nRepeat
)) :
340 pData
[eOp
].nMinParams
);
341 return pData
[eOp
].aData
.nParam
[nParam
];
345 return eType
== Unknown
? Value
: eType
;
350 ScParameterClassification::Type
351 ScParameterClassification::GetExternalParameterType( const formula::FormulaToken
* pToken
,
352 sal_uInt16 nParameter
)
355 // similar to ScInterpreter::ScExternal()
356 OUString aFuncName
= ScGlobal::pCharClass
->uppercase( pToken
->GetExternal());
358 const FuncData
* pFuncData
= ScGlobal::GetFuncCollection()->findByName(aFuncName
);
361 if ( nParameter
>= pFuncData
->GetParamCount() )
365 switch ( pFuncData
->GetParamType( nParameter
) )
367 case ParamType::PTR_DOUBLE
:
368 case ParamType::PTR_STRING
:
373 // also array types are created using an area reference
381 ScGlobal::GetAddInCollection()->FindFunction(aFuncName
, false);
383 if (!aUnoName
.isEmpty())
385 // the relevant parts of ScUnoAddInCall without having to create one
386 const ScUnoAddInFuncData
* pFuncData
=
387 ScGlobal::GetAddInCollection()->GetFuncData( aUnoName
, true ); // need fully initialized data
390 long nCount
= pFuncData
->GetArgumentCount();
395 const ScAddInArgDesc
* pArgs
= pFuncData
->GetArguments();
396 if ( nParameter
>= nCount
&&
397 pArgs
[nCount
-1].eType
== SC_ADDINARG_VARARGS
)
399 // last arg is sequence, optional "any"s, we simply can't
400 // determine the type
401 if ( eRet
== Unknown
)
403 if ( nParameter
>= nCount
)
407 switch ( pArgs
[nParameter
].eType
)
409 case SC_ADDINARG_INTEGER
:
410 case SC_ADDINARG_DOUBLE
:
411 case SC_ADDINARG_STRING
:
425 #if OSL_DEBUG_LEVEL > 1
427 // add remaining functions, all Value parameters
428 void ScParameterClassification::MergeArgumentsFromFunctionResource()
430 ScFunctionList
* pFuncList
= ScGlobal::GetStarCalcFunctionList();
431 for ( const ScFuncDesc
* pDesc
= pFuncList
->First(); pDesc
;
432 pDesc
= pFuncList
->Next() )
434 if ( pDesc
->nFIndex
> SC_OPCODE_LAST_OPCODE_ID
||
435 pData
[pDesc
->nFIndex
].aData
.nParam
[0] != Unknown
)
436 continue; // not an internal opcode or already done
438 RunData
* pRun
= &pData
[ pDesc
->nFIndex
];
439 sal_uInt16 nArgs
= pDesc
->GetSuppressedArgCount();
440 if ( nArgs
>= PAIRED_VAR_ARGS
)
442 nArgs
-= PAIRED_VAR_ARGS
- 2;
443 pRun
->aData
.nRepeatLast
= 2;
445 else if ( nArgs
>= VAR_ARGS
)
447 nArgs
-= VAR_ARGS
- 1;
448 pRun
->aData
.nRepeatLast
= 1;
450 if ( nArgs
> CommonData::nMaxParams
)
453 aBuf
.append("ScParameterClassification::Init: too many arguments in listed function: ");
454 aBuf
.append(OUStringToOString(*(pDesc
->pFuncName
), RTL_TEXTENCODING_UTF8
));
456 aBuf
.append(sal_Int32(nArgs
));
457 OSL_FAIL( aBuf
.getStr());
458 nArgs
= CommonData::nMaxParams
- 1;
459 pRun
->aData
.nRepeatLast
= 1;
461 pRun
->nMinParams
= static_cast< sal_uInt8
>( nArgs
);
462 for ( sal_Int32 j
=0; j
< nArgs
; ++j
)
464 pRun
->aData
.nParam
[j
] = Value
;
466 if ( pRun
->aData
.nRepeatLast
)
468 for ( sal_Int32 j
= nArgs
; j
< CommonData::nMaxParams
; ++j
)
470 pRun
->aData
.nParam
[j
] = Value
;
475 for ( sal_Int32 j
= nArgs
; j
< CommonData::nMaxParams
; ++j
)
477 pRun
->aData
.nParam
[j
] = Bounds
;
483 void ScParameterClassification::GenerateDocumentation()
485 static const sal_Char aEnvVarName
[] = "OOO_CALC_GENPARCLASSDOC";
486 if ( !getenv( aEnvVarName
) )
488 MergeArgumentsFromFunctionResource();
490 ScCompiler
aComp(NULL
,aAddress
);
491 ScCompiler::OpCodeMapPtr
xMap( aComp
.GetOpCodeMap(::com::sun::star::sheet::FormulaLanguage::ENGLISH
));
495 size_t nCount
= xMap
->getSymbolCount();
496 for ( size_t i
=0; i
<nCount
; ++i
)
498 OpCode eOp
= OpCode(i
);
499 if ( !xMap
->getSymbol(eOp
).isEmpty() )
501 fprintf( stdout
, "%s: ", aEnvVarName
);
502 OStringBuffer
aStr(OUStringToOString(xMap
->getSymbol(eOp
), RTL_TEXTENCODING_UTF8
));
504 formula::FormulaByteToken
aToken( eOp
);
505 sal_uInt8 nParams
= GetMinimumParameters( eOp
);
506 // preset parameter count according to opcode value, with some
508 if ( eOp
< SC_OPCODE_STOP_DIV
)
526 else if ( eOp
< SC_OPCODE_STOP_ERRORS
)
528 else if ( eOp
< SC_OPCODE_STOP_BIN_OP
)
534 aToken
.SetByte(1); // (r1)AND(r2) --> AND( r1, ...)
540 else if ( eOp
< SC_OPCODE_STOP_UN_OP
)
542 else if ( eOp
< SC_OPCODE_STOP_NO_PAR
)
544 else if ( eOp
< SC_OPCODE_STOP_1_PAR
)
547 aToken
.SetByte( nParams
);
548 // compare (this is a mere test for opcode order Div, BinOp, UnOp,
549 // NoPar, 1Par, ...) and override parameter count with
551 if ( nParams
!= aToken
.GetByte() )
552 fprintf( stdout
, "(parameter count differs, token Byte: %d classification: %d) ",
553 aToken
.GetByte(), nParams
);
554 aToken
.SetByte( nParams
);
555 if ( nParams
!= aToken
.GetParamCount() )
556 fprintf( stdout
, "(parameter count differs, token ParamCount: %d classification: %d) ",
557 aToken
.GetParamCount(), nParams
);
558 for ( sal_uInt16 j
=0; j
< nParams
; ++j
)
562 Type eType
= GetParameterType( &aToken
, j
);
566 aStr
.append(" Value");
569 aStr
.append(" Reference");
572 aStr
.append(" Array");
575 aStr
.append(" ForceArray");
577 case ReferenceOrForceArray
:
578 aStr
.append(" ReferenceOrForceArray");
581 aStr
.append(" (Bounds, classification error?)");
584 aStr
.append(" (???, classification error?)");
587 if ( HasRepeatParameters( eOp
) )
588 aStr
.append(", ...");
595 aStr
.append(" // RRI in English resource, but ZGZ in English-only section");
598 aStr
.append(" // e.g. combined first parameter of INDEX() function, not a real function");
601 aStr
.append(" // goal seek via menu, not a real function");
604 aStr
.append(" // MULTIPLE.OPERATIONS in English resource, but TABLE in English-only section");
607 aStr
.append(" // error function, not a real function");
611 fprintf( stdout
, "%s\n", aStr
.getStr());
617 #endif // OSL_DEBUG_LEVEL
619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */