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