Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
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/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
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 .
18 : : */
19 : :
20 : :
21 : : #include <cstddef>
22 : : #include <cstdio>
23 : :
24 : : #include <string.h>
25 : : #include <limits.h>
26 : : #include <tools/debug.hxx>
27 : :
28 : : #include "formula/token.hxx"
29 : : #include "formula/tokenarray.hxx"
30 : : #include "formula/FormulaCompiler.hxx"
31 : : #include <formula/compiler.hrc>
32 : : #define MAXJUMPCOUNT 32 /* maximum number of jumps (ocChose) */
33 : :
34 : : namespace formula
35 : : {
36 : : using namespace com::sun::star;
37 : : // ImpTokenIterator wird je Interpreter angelegt, mehrfache auch durch
38 : : // SubCode via FormulaTokenIterator Push/Pop moeglich
39 : 57 : IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator )
40 : :
41 : : // Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2)
42 : :
43 : : // Need a lot of FormulaDoubleToken
44 [ + - ][ + - ]: 8033 : IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaDoubleToken )
45 : : // Need a lot of FormulaByteToken
46 [ + + ][ + + ]: 44509 : IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaByteToken )
47 : : // Need several FormulaStringToken
48 [ + - ][ + - ]: 17166 : IMPL_FIXEDMEMPOOL_NEWDEL_DLL( FormulaStringToken )
49 : :
50 : :
51 : : // --- helpers --------------------------------------------------------------
52 : :
53 : 0 : inline bool lcl_IsReference( OpCode eOp, StackVar eType )
54 : : {
55 : : return
56 : : (eOp == ocPush && (eType == svSingleRef || eType == svDoubleRef))
57 : : || (eOp == ocColRowNameAuto && eType == svDoubleRef)
58 : : || (eOp == ocColRowName && eType == svSingleRef)
59 [ # # ][ # # ]: 0 : || (eOp == ocMatRef && eType == svSingleRef)
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
60 : : ;
61 : : }
62 : :
63 : : // --- class FormulaToken --------------------------------------------------------
64 : 111903 : FormulaToken::~FormulaToken()
65 : : {
66 [ - + ]: 141430 : }
67 : :
68 : 0 : bool FormulaToken::Is3DRef() const
69 : : {
70 : 0 : return false;
71 : : }
72 : :
73 : 0 : bool FormulaToken::IsFunction() const
74 : : {
75 : : return (eOp != ocPush && eOp != ocBad && eOp != ocColRowName &&
76 : : eOp != ocColRowNameAuto && eOp != ocName && eOp != ocDBArea &&
77 : 0 : (GetByte() != 0 // x parameters
78 : : || (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR) // no parameter
79 : : || (ocIf == eOp || ocChose == eOp ) // @ jump commands
80 : : || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) // one parameter
81 : : || (SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR) // x parameters (cByte==0 in
82 : : // FuncAutoPilot)
83 : : || eOp == ocMacro || eOp == ocExternal // macros, AddIns
84 : : || eOp == ocAnd || eOp == ocOr // former binary, now x parameters
85 : : || eOp == ocNot || eOp == ocNeg // unary but function
86 : : || (eOp >= ocInternalBegin && eOp <= ocInternalEnd) // internal
87 [ # # ][ # # ]: 0 : ));
[ # # ][ # # ]
[ # # ]
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
88 : : }
89 : :
90 : :
91 : 3056 : sal_uInt8 FormulaToken::GetParamCount() const
92 : : {
93 [ + + ][ + - ]: 3056 : if ( eOp < SC_OPCODE_STOP_DIV && eOp != ocExternal && eOp != ocMacro &&
[ + - ][ + - ]
[ + - ][ + - ]
94 : : eOp != ocIf && eOp != ocChose && eOp != ocPercentSign )
95 : 190 : return 0; // parameters and specials
96 : : // ocIf and ocChose not for FAP, have cByte then
97 : : //2do: bool parameter whether FAP or not?
98 [ + + ]: 2866 : else if ( GetByte() )
99 : 1802 : return GetByte(); // all functions, also ocExternal and ocMacro
100 [ + - ][ + + ]: 1064 : else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP)
101 : 736 : return 2; // binary
102 [ + - ][ + + ]: 328 : else if ((SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)
[ - + ]
103 : : || eOp == ocPercentSign)
104 : 184 : return 1; // unary
105 [ + - ][ + + ]: 144 : else if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
106 : 117 : return 0; // no parameter
107 [ + - ][ - + ]: 27 : else if (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR)
108 : 0 : return 1; // one parameter
109 [ + - ][ - + ]: 27 : else if ( eOp == ocIf || eOp == ocChose )
110 : 0 : return 1; // only the condition counts as parameter
111 : : else
112 : 3056 : return 0; // all the rest, no Parameter, or
113 : : // if so then it should be in cByte
114 : : }
115 : :
116 : 94157 : bool FormulaToken::IsExternalRef() const
117 : : {
118 : 94157 : bool bRet = false;
119 [ + + ]: 94157 : switch (eType)
120 : : {
121 : : case svExternalSingleRef:
122 : : case svExternalDoubleRef:
123 : : case svExternalName:
124 : 120 : bRet = true;
125 : 120 : break;
126 : : default:
127 : 94037 : bRet = false;
128 : 94037 : break;
129 : : }
130 : 94157 : return bRet;
131 : : }
132 : :
133 : 77 : bool FormulaToken::operator==( const FormulaToken& rToken ) const
134 : : {
135 : : // don't compare reference count!
136 [ + - ][ + - ]: 77 : return eType == rToken.eType && GetOpCode() == rToken.GetOpCode();
137 : : }
138 : :
139 : :
140 : : // --- virtual dummy methods -------------------------------------------------
141 : :
142 : 4681 : sal_uInt8 FormulaToken::GetByte() const
143 : : {
144 : : // ok to be called for any derived class
145 : 4681 : return 0;
146 : : }
147 : :
148 : 0 : void FormulaToken::SetByte( sal_uInt8 )
149 : : {
150 : : SAL_WARN( "formula.core", "FormulaToken::SetByte: virtual dummy called" );
151 : 0 : }
152 : :
153 : 376 : bool FormulaToken::HasForceArray() const
154 : : {
155 : : // ok to be called for any derived class
156 : 376 : return false;
157 : : }
158 : :
159 : 0 : void FormulaToken::SetForceArray( bool )
160 : : {
161 : : SAL_WARN( "formula.core", "FormulaToken::SetForceArray: virtual dummy called" );
162 : 0 : }
163 : :
164 : 0 : double FormulaToken::GetDouble() const
165 : : {
166 : : SAL_WARN( "formula.core", "FormulaToken::GetDouble: virtual dummy called" );
167 : 0 : return 0.0;
168 : : }
169 : :
170 : 0 : double & FormulaToken::GetDoubleAsReference()
171 : : {
172 : : SAL_WARN( "formula.core", "FormulaToken::GetDouble: virtual dummy called" );
173 : : static double fVal = 0.0;
174 : 0 : return fVal;
175 : : }
176 : :
177 : 0 : const String& FormulaToken::GetString() const
178 : : {
179 : : SAL_WARN( "formula.core", "FormulaToken::GetString: virtual dummy called" );
180 [ # # ][ # # ]: 0 : static String aDummyString;
[ # # ][ # # ]
181 : 0 : return aDummyString;
182 : : }
183 : :
184 : 0 : sal_uInt16 FormulaToken::GetIndex() const
185 : : {
186 : : SAL_WARN( "formula.core", "FormulaToken::GetIndex: virtual dummy called" );
187 : 0 : return 0;
188 : : }
189 : :
190 : 0 : void FormulaToken::SetIndex( sal_uInt16 )
191 : : {
192 : : SAL_WARN( "formula.core", "FormulaToken::SetIndex: virtual dummy called" );
193 : 0 : }
194 : :
195 : 0 : bool FormulaToken::IsGlobal() const
196 : : {
197 : : SAL_WARN( "formula.core", "FormulaToken::IsGlobal: virtual dummy called" );
198 : 0 : return true;
199 : : }
200 : :
201 : 0 : void FormulaToken::SetGlobal( bool )
202 : : {
203 : : SAL_WARN( "formula.core", "FormulaToken::SetGlobal: virtual dummy called" );
204 : 0 : }
205 : :
206 : 0 : short* FormulaToken::GetJump() const
207 : : {
208 : : SAL_WARN( "formula.core", "FormulaToken::GetJump: virtual dummy called" );
209 : 0 : return NULL;
210 : : }
211 : :
212 : :
213 : 0 : const String& FormulaToken::GetExternal() const
214 : : {
215 : : SAL_WARN( "formula.core", "FormulaToken::GetExternal: virtual dummy called" );
216 [ # # ][ # # ]: 0 : static String aDummyString;
[ # # ][ # # ]
217 : 0 : return aDummyString;
218 : : }
219 : :
220 : 0 : FormulaToken* FormulaToken::GetFAPOrigToken() const
221 : : {
222 : : SAL_WARN( "formula.core", "FormulaToken::GetFAPOrigToken: virtual dummy called" );
223 : 0 : return NULL;
224 : : }
225 : :
226 : 0 : sal_uInt16 FormulaToken::GetError() const
227 : : {
228 : : SAL_WARN( "formula.core", "FormulaToken::GetError: virtual dummy called" );
229 : 0 : return 0;
230 : : }
231 : :
232 : 0 : void FormulaToken::SetError( sal_uInt16 )
233 : : {
234 : : SAL_WARN( "formula.core", "FormulaToken::SetError: virtual dummy called" );
235 : 0 : }
236 : :
237 : 4 : bool FormulaToken::TextEqual( const FormulaToken& rToken ) const
238 : : {
239 : 4 : return *this == rToken;
240 : : }
241 : : // ==========================================================================
242 : : // real implementations of virtual functions
243 : : // --------------------------------------------------------------------------
244 : :
245 : :
246 : 7387 : sal_uInt8 FormulaByteToken::GetByte() const { return nByte; }
247 : 9568 : void FormulaByteToken::SetByte( sal_uInt8 n ) { nByte = n; }
248 : 31251 : bool FormulaByteToken::HasForceArray() const { return bHasForceArray; }
249 : 0 : void FormulaByteToken::SetForceArray( bool b ) { bHasForceArray = b; }
250 : 67 : bool FormulaByteToken::operator==( const FormulaToken& r ) const
251 : : {
252 : 134 : return FormulaToken::operator==( r ) && nByte == r.GetByte() &&
253 [ + - ]: 134 : bHasForceArray == r.HasForceArray();
[ + - + - ]
254 : : }
255 : :
256 : :
257 : 0 : FormulaToken* FormulaFAPToken::GetFAPOrigToken() const { return pOrigToken.get(); }
258 : 0 : bool FormulaFAPToken::operator==( const FormulaToken& r ) const
259 : : {
260 [ # # ][ # # ]: 0 : return FormulaByteToken::operator==( r ) && pOrigToken == r.GetFAPOrigToken();
261 : : }
262 : 240 : short* FormulaJumpToken::GetJump() const { return pJump; }
263 : 0 : bool FormulaJumpToken::operator==( const FormulaToken& r ) const
264 : : {
265 : 0 : return FormulaToken::operator==( r ) && pJump[0] == r.GetJump()[0] &&
266 [ # # ]: 0 : memcmp( pJump+1, r.GetJump()+1, pJump[0] * sizeof(short) ) == 0;
[ # # # # ]
267 : : }
268 : 39 : FormulaJumpToken::~FormulaJumpToken()
269 : : {
270 [ + - ]: 39 : delete [] pJump;
271 [ - + ]: 78 : }
272 : :
273 : :
274 : 294 : bool FormulaTokenArray::AddFormulaToken(const sheet::FormulaToken& _aToken,ExternalReferenceHelper* /*_pRef*/)
275 : : {
276 : 294 : bool bError = false;
277 : 294 : const OpCode eOpCode = static_cast<OpCode>(_aToken.OpCode); //! assuming equal values for the moment
278 : :
279 : 294 : const uno::TypeClass eClass = _aToken.Data.getValueTypeClass();
280 [ + + + + : 294 : switch ( eClass )
+ ]
281 : : {
282 : : case uno::TypeClass_VOID:
283 : : // empty data -> use AddOpCode (does some special cases)
284 : 111 : AddOpCode( eOpCode );
285 : 111 : break;
286 : : case uno::TypeClass_DOUBLE:
287 : : // double is only used for "push"
288 [ + - ]: 39 : if ( eOpCode == ocPush )
289 : 39 : AddDouble( _aToken.Data.get<double>() );
290 : : else
291 : 0 : bError = true;
292 : 39 : break;
293 : : case uno::TypeClass_LONG:
294 : : {
295 : : // long is svIndex, used for name / database area, or "byte" for spaces
296 : 6 : sal_Int32 nValue = _aToken.Data.get<sal_Int32>();
297 [ - + ]: 6 : if ( eOpCode == ocDBArea )
298 [ # # ]: 0 : AddToken( formula::FormulaIndexToken( eOpCode, static_cast<sal_uInt16>(nValue) ) );
299 [ + - ]: 6 : else if ( eOpCode == ocSpaces )
300 [ + - ]: 6 : AddToken( formula::FormulaByteToken( ocSpaces, static_cast<sal_uInt8>(nValue) ) );
301 : : else
302 : 0 : bError = true;
303 : : }
304 : 6 : break;
305 : : case uno::TypeClass_STRING:
306 : : {
307 [ + - ][ + - ]: 12 : String aStrVal( _aToken.Data.get<rtl::OUString>() );
308 [ - + ]: 12 : if ( eOpCode == ocPush )
309 [ # # ]: 0 : AddString( aStrVal );
310 [ + - ]: 12 : else if ( eOpCode == ocBad )
311 [ + - ]: 12 : AddBad( aStrVal );
312 [ # # ]: 0 : else if ( eOpCode == ocStringXML )
313 [ # # ]: 0 : AddStringXML( aStrVal );
314 [ # # ][ # # ]: 0 : else if ( eOpCode == ocExternal || eOpCode == ocMacro )
315 [ # # ][ # # ]: 0 : AddToken( formula::FormulaExternalToken( eOpCode, aStrVal ) );
[ # # ]
316 : : else
317 [ + - ]: 12 : bError = true; // unexpected string: don't know what to do with it
318 : : }
319 : 12 : break;
320 : : default:
321 : 126 : bError = true;
322 : : } // switch ( eClass )
323 : 294 : return bError;
324 : : }
325 : 138 : bool FormulaTokenArray::Fill(const uno::Sequence< sheet::FormulaToken >& _aSequence,ExternalReferenceHelper* _pRef)
326 : : {
327 : 138 : bool bError = false;
328 : 138 : const sal_Int32 nCount = _aSequence.getLength();
329 [ + + ]: 432 : for (sal_Int32 nPos=0; nPos<nCount; nPos++)
330 : : {
331 : 294 : bError |= AddFormulaToken( _aSequence[nPos] ,_pRef);
332 : : }
333 : 138 : return bError;
334 : : }
335 : 1763 : FormulaToken* FormulaTokenArray::GetNextReference()
336 : : {
337 [ + + ]: 1907 : while( nIndex < nLen )
338 : : {
339 : 1244 : FormulaToken* t = pCode[ nIndex++ ];
340 [ + + ]: 1244 : switch( t->GetType() )
341 : : {
342 : : case svSingleRef:
343 : : case svDoubleRef:
344 : : case svExternalSingleRef:
345 : : case svExternalDoubleRef:
346 : 1100 : return t;
347 : : default:
348 : : {
349 : : // added to avoid warnings
350 : : }
351 : : }
352 : : }
353 : 1763 : return NULL;
354 : : }
355 : :
356 : 104 : FormulaToken* FormulaTokenArray::GetNextColRowName()
357 : : {
358 [ + + ]: 318 : while( nIndex < nLen )
359 : : {
360 : 214 : FormulaToken* t = pCode[ nIndex++ ];
361 [ - + ]: 214 : if ( t->GetOpCode() == ocColRowName )
362 : 0 : return t;
363 : : }
364 : 104 : return NULL;
365 : : }
366 : :
367 : 16496 : FormulaToken* FormulaTokenArray::GetNextReferenceRPN()
368 : : {
369 [ + + ]: 43862 : while( nIndex < nRPN )
370 : : {
371 : 39291 : FormulaToken* t = pRPN[ nIndex++ ];
372 [ + + ]: 39291 : switch( t->GetType() )
373 : : {
374 : : case svSingleRef:
375 : : case svDoubleRef:
376 : : case svExternalSingleRef:
377 : : case svExternalDoubleRef:
378 : 11925 : return t;
379 : : default:
380 : : {
381 : : // added to avoid warnings
382 : : }
383 : : }
384 : : }
385 : 16496 : return NULL;
386 : : }
387 : :
388 : 1137 : FormulaToken* FormulaTokenArray::GetNextReferenceOrName()
389 : : {
390 [ + + ]: 1137 : if( pCode )
391 : : {
392 [ + + ]: 2135 : while ( nIndex < nLen )
393 : : {
394 : 1745 : FormulaToken* t = pCode[ nIndex++ ];
395 [ + + ]: 1745 : switch( t->GetType() )
396 : : {
397 : : case svSingleRef:
398 : : case svDoubleRef:
399 : : case svIndex:
400 : : case svExternalSingleRef:
401 : : case svExternalDoubleRef:
402 : : case svExternalName:
403 : 703 : return t;
404 : : default:
405 : : {
406 : : // added to avoid warnings
407 : : }
408 : : }
409 : : }
410 : : }
411 : 1137 : return NULL;
412 : : }
413 : :
414 : 392 : FormulaToken* FormulaTokenArray::GetNextName()
415 : : {
416 [ + + ]: 392 : if( pCode )
417 : : {
418 [ + + ]: 1847 : while ( nIndex < nLen )
419 : : {
420 : 1547 : FormulaToken* t = pCode[ nIndex++ ];
421 [ + + ]: 1547 : if( t->GetType() == svIndex )
422 : 48 : return t;
423 : : }
424 : : } // if( pCode )
425 : 392 : return NULL;
426 : : }
427 : :
428 : 37 : FormulaToken* FormulaTokenArray::GetNextOpCodeRPN( OpCode eOp )
429 : : {
430 [ - + ]: 37 : while( nIndex < nRPN )
431 : : {
432 : 0 : FormulaToken* t = pRPN[ nIndex++ ];
433 [ # # ]: 0 : if ( t->GetOpCode() == eOp )
434 : 0 : return t;
435 : : }
436 : 37 : return NULL;
437 : : }
438 : :
439 : 75277 : FormulaToken* FormulaTokenArray::Next()
440 : : {
441 [ + - ][ + + ]: 75277 : if( pCode && nIndex < nLen )
442 : 70589 : return pCode[ nIndex++ ];
443 : : else
444 : 75277 : return NULL;
445 : : }
446 : :
447 : 0 : FormulaToken* FormulaTokenArray::NextNoSpaces()
448 : : {
449 [ # # ]: 0 : if( pCode )
450 : : {
451 [ # # ][ # # ]: 0 : while( (nIndex < nLen) && (pCode[ nIndex ]->GetOpCode() == ocSpaces) )
[ # # ]
452 : 0 : ++nIndex;
453 [ # # ]: 0 : if( nIndex < nLen )
454 : 0 : return pCode[ nIndex++ ];
455 : : }
456 : 0 : return NULL;
457 : : }
458 : :
459 : 1310 : FormulaToken* FormulaTokenArray::NextRPN()
460 : : {
461 [ + - ][ + + ]: 1310 : if( pRPN && nIndex < nRPN )
462 : 971 : return pRPN[ nIndex++ ];
463 : : else
464 : 1310 : return NULL;
465 : : }
466 : :
467 : 0 : FormulaToken* FormulaTokenArray::PrevRPN()
468 : : {
469 [ # # ][ # # ]: 0 : if( pRPN && nIndex )
470 : 0 : return pRPN[ --nIndex ];
471 : : else
472 : 0 : return NULL;
473 : : }
474 : :
475 : 9851 : void FormulaTokenArray::DelRPN()
476 : : {
477 [ + + ]: 9851 : if( nRPN )
478 : : {
479 : 3914 : FormulaToken** p = pRPN;
480 [ + + ]: 41108 : for( sal_uInt16 i = 0; i < nRPN; i++ )
481 : : {
482 : 37194 : (*p++)->DecRef();
483 : : }
484 [ + - ]: 3914 : delete [] pRPN;
485 : : }
486 : 9851 : pRPN = NULL;
487 : 9851 : nRPN = nIndex = 0;
488 : 9851 : }
489 : :
490 : 0 : FormulaToken* FormulaTokenArray::PeekPrev( sal_uInt16 & nIdx )
491 : : {
492 [ # # ][ # # ]: 0 : if (0 < nIdx && nIdx <= nLen)
493 : 0 : return pCode[--nIdx];
494 : 0 : return NULL;
495 : : }
496 : :
497 : 0 : FormulaToken* FormulaTokenArray::PeekNext()
498 : : {
499 [ # # ][ # # ]: 0 : if( pCode && nIndex < nLen )
500 : 0 : return pCode[ nIndex ];
501 : : else
502 : 0 : return NULL;
503 : : }
504 : :
505 : 218 : FormulaToken* FormulaTokenArray::PeekNextNoSpaces()
506 : : {
507 [ + - ][ + + ]: 218 : if( pCode && nIndex < nLen )
508 : : {
509 : 84 : sal_uInt16 j = nIndex;
510 [ - + ][ # # ]: 84 : while ( pCode[j]->GetOpCode() == ocSpaces && j < nLen )
[ - + ]
511 : 0 : j++;
512 [ + - ]: 84 : if ( j < nLen )
513 : 84 : return pCode[ j ];
514 : : else
515 : 0 : return NULL;
516 : : }
517 : : else
518 : 218 : return NULL;
519 : : }
520 : :
521 : 218 : FormulaToken* FormulaTokenArray::PeekPrevNoSpaces()
522 : : {
523 [ + - ][ + + ]: 218 : if( pCode && nIndex > 1 )
524 : : {
525 : 75 : sal_uInt16 j = nIndex - 2;
526 [ - + ][ # # ]: 75 : while ( pCode[j]->GetOpCode() == ocSpaces && j > 0 )
[ - + ]
527 : 0 : j--;
528 [ - + ][ # # ]: 75 : if ( j > 0 || pCode[j]->GetOpCode() != ocSpaces )
[ + - ]
529 : 75 : return pCode[ j ];
530 : : else
531 : 0 : return NULL;
532 : : }
533 : : else
534 : 218 : return NULL;
535 : : }
536 : :
537 : 0 : bool FormulaTokenArray::HasExternalRef() const
538 : : {
539 [ # # ]: 0 : for ( sal_uInt16 j=0; j < nLen; j++ )
540 : : {
541 [ # # ]: 0 : if (pCode[j]->IsExternalRef())
542 : 0 : return true;
543 : : }
544 : 0 : return false;
545 : : }
546 : :
547 : 3871 : bool FormulaTokenArray::HasOpCode( OpCode eOp ) const
548 : : {
549 [ + + ]: 70281 : for ( sal_uInt16 j=0; j < nLen; j++ )
550 : : {
551 [ + + ]: 66413 : if ( pCode[j]->GetOpCode() == eOp )
552 : 3 : return true;
553 : : }
554 : 3871 : return false;
555 : : }
556 : :
557 : 1067 : bool FormulaTokenArray::HasOpCodeRPN( OpCode eOp ) const
558 : : {
559 [ + + ]: 3895 : for ( sal_uInt16 j=0; j < nRPN; j++ )
560 : : {
561 [ - + ]: 2828 : if ( pRPN[j]->GetOpCode() == eOp )
562 : 0 : return true;
563 : : }
564 : 1067 : return false;
565 : : }
566 : :
567 : 0 : bool FormulaTokenArray::HasNameOrColRowName() const
568 : : {
569 [ # # ]: 0 : for ( sal_uInt16 j=0; j < nLen; j++ )
570 : : {
571 [ # # ][ # # ]: 0 : if( pCode[j]->GetType() == svIndex || pCode[j]->GetOpCode() == ocColRowName )
[ # # ]
572 : 0 : return true;
573 : : }
574 : 0 : return false;
575 : : }
576 : :
577 : :
578 : 7440 : FormulaTokenArray::FormulaTokenArray()
579 : : {
580 : 7440 : pCode = NULL; pRPN = NULL;
581 : 7440 : nError = nLen = nIndex = nRPN = nRefs = 0;
582 : 7440 : bHyperLink = false;
583 : 7440 : ClearRecalcMode();
584 : 7440 : }
585 : :
586 : 7536 : FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray& rArr )
587 : : {
588 : 7536 : Assign( rArr );
589 : 7536 : }
590 : :
591 : 14386 : FormulaTokenArray::~FormulaTokenArray()
592 : : {
593 : 14386 : Clear();
594 [ - + ]: 14386 : }
595 : :
596 : 7536 : void FormulaTokenArray::Assign( const FormulaTokenArray& r )
597 : : {
598 : 7536 : nLen = r.nLen;
599 : 7536 : nRPN = r.nRPN;
600 : 7536 : nIndex = r.nIndex;
601 : 7536 : nError = r.nError;
602 : 7536 : nRefs = r.nRefs;
603 : 7536 : nMode = r.nMode;
604 : 7536 : bHyperLink = r.bHyperLink;
605 : 7536 : pCode = NULL;
606 : 7536 : pRPN = NULL;
607 : : FormulaToken** pp;
608 [ + - ]: 7536 : if( nLen )
609 : : {
610 : 7536 : pp = pCode = new FormulaToken*[ nLen ];
611 : 7536 : memcpy( pp, r.pCode, nLen * sizeof( FormulaToken* ) );
612 [ + + ]: 77493 : for( sal_uInt16 i = 0; i < nLen; i++ )
613 : 69957 : (*pp++)->IncRef();
614 : : }
615 [ - + ]: 7536 : if( nRPN )
616 : : {
617 : 0 : pp = pRPN = new FormulaToken*[ nRPN ];
618 : 0 : memcpy( pp, r.pRPN, nRPN * sizeof( FormulaToken* ) );
619 [ # # ]: 0 : for( sal_uInt16 i = 0; i < nRPN; i++ )
620 : 0 : (*pp++)->IncRef();
621 : : }
622 : 7536 : }
623 : :
624 : 0 : FormulaTokenArray& FormulaTokenArray::operator=( const FormulaTokenArray& rArr )
625 : : {
626 : 0 : Clear();
627 : 0 : Assign( rArr );
628 : 0 : return *this;
629 : : }
630 : :
631 : 0 : FormulaTokenArray* FormulaTokenArray::Clone() const
632 : : {
633 [ # # ]: 0 : FormulaTokenArray* p = new FormulaTokenArray;
634 : 0 : p->nLen = nLen;
635 : 0 : p->nRPN = nRPN;
636 : 0 : p->nRefs = nRefs;
637 : 0 : p->nMode = nMode;
638 : 0 : p->nError = nError;
639 : 0 : p->bHyperLink = bHyperLink;
640 : : FormulaToken** pp;
641 [ # # ]: 0 : if( nLen )
642 : : {
643 : 0 : pp = p->pCode = new FormulaToken*[ nLen ];
644 : 0 : memcpy( pp, pCode, nLen * sizeof( FormulaToken* ) );
645 [ # # ]: 0 : for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
646 : : {
647 : 0 : *pp = (*pp)->Clone();
648 : 0 : (*pp)->IncRef();
649 : : }
650 : : }
651 [ # # ]: 0 : if( nRPN )
652 : : {
653 : 0 : pp = p->pRPN = new FormulaToken*[ nRPN ];
654 : 0 : memcpy( pp, pRPN, nRPN * sizeof( FormulaToken* ) );
655 [ # # ]: 0 : for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
656 : : {
657 : 0 : FormulaToken* t = *pp;
658 [ # # ]: 0 : if( t->GetRef() > 1 )
659 : : {
660 : 0 : FormulaToken** p2 = pCode;
661 : 0 : sal_uInt16 nIdx = 0xFFFF;
662 [ # # ]: 0 : for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
663 : : {
664 [ # # ]: 0 : if( *p2 == t )
665 : : {
666 : 0 : nIdx = j; break;
667 : : }
668 : : }
669 [ # # ]: 0 : if( nIdx == 0xFFFF )
670 : 0 : *pp = t->Clone();
671 : : else
672 : 0 : *pp = p->pCode[ nIdx ];
673 : : }
674 : : else
675 : 0 : *pp = t->Clone();
676 : 0 : (*pp)->IncRef();
677 : : }
678 : : }
679 : 0 : return p;
680 : : }
681 : :
682 : 17271 : void FormulaTokenArray::Clear()
683 : : {
684 [ + + ]: 17271 : if( nRPN ) DelRPN();
685 [ + + ]: 17271 : if( pCode )
686 : : {
687 : 16010 : FormulaToken** p = pCode;
688 [ + + ]: 157253 : for( sal_uInt16 i = 0; i < nLen; i++ )
689 : : {
690 : 141243 : (*p++)->DecRef();
691 : : }
692 [ + - ]: 16010 : delete [] pCode;
693 : : }
694 : 17271 : pCode = NULL; pRPN = NULL;
695 : 17271 : nError = nLen = nIndex = nRPN = nRefs = 0;
696 : 17271 : bHyperLink = false;
697 : 17271 : ClearRecalcMode();
698 : 17271 : }
699 : :
700 : 35 : FormulaToken* FormulaTokenArray::AddToken( const FormulaToken& r )
701 : : {
702 : 35 : return Add( r.Clone() );
703 : : }
704 : :
705 : 0 : FormulaToken* FormulaTokenArray::MergeArray( )
706 : : {
707 : 0 : return NULL;
708 : : }
709 : :
710 : 69821 : FormulaToken* FormulaTokenArray::Add( FormulaToken* t )
711 : : {
712 [ + + ]: 69821 : if( !pCode )
713 : 7579 : pCode = new FormulaToken*[ MAXCODE ];
714 [ + - ]: 69821 : if( nLen < MAXCODE-1 )
715 : : {
716 : 69821 : pCode[ nLen++ ] = t;
717 [ + + + + : 108740 : if( t->GetOpCode() == ocPush
+ + ][ + + ]
718 : 38919 : && ( t->GetType() == svSingleRef || t->GetType() == svDoubleRef ) )
719 : 12264 : nRefs++;
720 : 69821 : t->IncRef();
721 [ + + ]: 69821 : if( t->GetOpCode() == ocArrayClose )
722 : 15 : return MergeArray();
723 : 69806 : return t;
724 : : }
725 : : else
726 : : {
727 : 0 : t->Delete();
728 [ # # ]: 0 : if ( nLen == MAXCODE-1 )
729 : : {
730 [ # # ]: 0 : t = new FormulaByteToken( ocStop );
731 : 0 : pCode[ nLen++ ] = t;
732 : 0 : t->IncRef();
733 : : }
734 : 69821 : return NULL;
735 : : }
736 : : }
737 : :
738 : 0 : FormulaToken* FormulaTokenArray::AddString( const sal_Unicode* pStr )
739 : : {
740 [ # # ][ # # ]: 0 : return AddString( rtl::OUString( pStr ) );
[ # # ]
741 : : }
742 : :
743 : 8070 : FormulaToken* FormulaTokenArray::AddString( const String& rStr )
744 : : {
745 [ + - ]: 8070 : return Add( new FormulaStringToken( rStr ) );
746 : : }
747 : :
748 : 101 : FormulaToken* FormulaTokenArray::AddDouble( double fVal )
749 : : {
750 [ + - ]: 101 : return Add( new FormulaDoubleToken( fVal ) );
751 : : }
752 : :
753 : 0 : FormulaToken* FormulaTokenArray::AddExternal( const sal_Unicode* pStr )
754 : : {
755 [ # # ][ # # ]: 0 : return AddExternal( rtl::OUString( pStr ) );
[ # # ]
756 : : }
757 : :
758 : 3 : FormulaToken* FormulaTokenArray::AddExternal( const String& rStr,
759 : : OpCode eOp /* = ocExternal */ )
760 : : {
761 [ + - ]: 3 : return Add( new FormulaExternalToken( eOp, rStr ) );
762 : : }
763 : :
764 : 12 : FormulaToken* FormulaTokenArray::AddBad( const String& rStr )
765 : : {
766 [ + - ]: 12 : return Add( new FormulaStringOpToken( ocBad, rStr ) );
767 : : }
768 : :
769 : 1223 : FormulaToken* FormulaTokenArray::AddStringXML( const String& rStr )
770 : : {
771 [ + - ]: 1223 : return Add( new FormulaStringOpToken( ocStringXML, rStr ) );
772 : : }
773 : :
774 : :
775 : :
776 : 48 : void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits )
777 : : {
778 : : //! Reihenfolge ist wichtig
779 [ - + ]: 48 : if ( nBits & RECALCMODE_ALWAYS )
780 : 0 : SetRecalcModeAlways();
781 [ + - ]: 48 : else if ( !IsRecalcModeAlways() )
782 : : {
783 [ - + ]: 48 : if ( nBits & RECALCMODE_ONLOAD )
784 : 0 : SetRecalcModeOnLoad();
785 [ - + ][ # # ]: 48 : else if ( nBits & RECALCMODE_ONLOAD_ONCE && !IsRecalcModeOnLoad() )
[ - + ]
786 : 0 : SetRecalcModeOnLoadOnce();
787 : : }
788 : 48 : SetCombinedBitsRecalcMode( nBits );
789 : 48 : }
790 : :
791 : :
792 : 0 : bool FormulaTokenArray::HasMatrixDoubleRefOps()
793 : : {
794 [ # # ][ # # ]: 0 : if ( pRPN && nRPN )
795 : : {
796 : : // RPN-Interpreter Simulation
797 : : // als Ergebnis jeder Funktion wird einfach ein Double angenommen
798 : 0 : FormulaToken** pStack = new FormulaToken* [nRPN];
799 [ # # ]: 0 : FormulaToken* pResult = new FormulaDoubleToken( 0.0 );
800 : 0 : short sp = 0;
801 [ # # ]: 0 : for ( sal_uInt16 j = 0; j < nRPN; j++ )
802 : : {
803 : 0 : FormulaToken* t = pRPN[j];
804 : 0 : OpCode eOp = t->GetOpCode();
805 : 0 : sal_uInt8 nParams = t->GetParamCount();
806 [ # # ]: 0 : switch ( eOp )
807 : : {
808 : : case ocAdd :
809 : : case ocSub :
810 : : case ocMul :
811 : : case ocDiv :
812 : : case ocPow :
813 : : case ocPower :
814 : : case ocAmpersand :
815 : : case ocEqual :
816 : : case ocNotEqual :
817 : : case ocLess :
818 : : case ocGreater :
819 : : case ocLessEqual :
820 : : case ocGreaterEqual :
821 : : {
822 [ # # ]: 0 : for ( sal_uInt8 k = nParams; k; k-- )
823 : : {
824 [ # # ][ # # ]: 0 : if ( sp >= k && pStack[sp-k]->GetType() == svDoubleRef )
[ # # ]
825 : : {
826 : 0 : pResult->Delete();
827 [ # # ]: 0 : delete [] pStack;
828 : 0 : return true;
829 : : }
830 : : }
831 : : }
832 : 0 : break;
833 : : default:
834 : : {
835 : : // added to avoid warnings
836 : : }
837 : : }
838 [ # # ][ # # ]: 0 : if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() ) )
[ # # ]
839 : 0 : pStack[sp++] = t;
840 [ # # ][ # # ]: 0 : else if ( eOp == ocIf || eOp == ocChose )
841 : : { // Jumps ignorieren, vorheriges Result (Condition) poppen
842 [ # # ]: 0 : if ( sp )
843 : 0 : --sp;
844 : : }
845 : : else
846 : : { // pop parameters, push result
847 : 0 : sp = sal::static_int_cast<short>( sp - nParams );
848 [ # # ]: 0 : if ( sp < 0 )
849 : : {
850 : : OSL_FAIL( "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
851 : 0 : sp = 0;
852 : : }
853 : 0 : pStack[sp++] = pResult;
854 : : }
855 : : }
856 : 0 : pResult->Delete();
857 [ # # ]: 0 : delete [] pStack;
858 : : }
859 : :
860 : 0 : return false;
861 : : }
862 : :
863 : :
864 : :
865 : : // --- POF (plain old formula) rewrite of a token array ---------------------
866 : :
867 : 170 : inline bool MissingConvention::isRewriteNeeded( OpCode eOp ) const
868 : : {
869 [ - - + ]: 170 : switch (eOp)
870 : : {
871 : : case ocGammaDist:
872 : : case ocPoissonDist:
873 : : case ocAddress:
874 : : case ocLogNormDist:
875 : : case ocNormDist:
876 : 0 : return true;
877 : : case ocMissing:
878 : : case ocLog:
879 : 0 : return !isODFF(); // rewrite only for PODF
880 : : default:
881 : 170 : return false;
882 : : }
883 : : }
884 : :
885 : : class FormulaMissingContext
886 : : {
887 : : public:
888 : : const FormulaToken* mpFunc;
889 : : int mnCurArg;
890 : :
891 : 0 : void Clear() { mpFunc = NULL; mnCurArg = 0; }
892 : : inline bool AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const;
893 : : bool AddMissingExternal( FormulaTokenArray* pNewArr ) const;
894 : : bool AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
895 : : void AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
896 : : };
897 : :
898 : 0 : void FormulaMissingContext::AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
899 : : {
900 [ # # ]: 0 : if ( !mpFunc )
901 : 0 : return;
902 : :
903 [ # # # # : 0 : switch (mpFunc->GetOpCode())
# # ]
904 : : {
905 : : case ocGammaDist:
906 [ # # ]: 0 : if (mnCurArg == 2)
907 : : {
908 : 0 : pNewArr->AddOpCode( ocSep );
909 : 0 : pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
910 : : }
911 : 0 : break;
912 : : case ocPoissonDist:
913 [ # # ]: 0 : if (mnCurArg == 1)
914 : : {
915 : 0 : pNewArr->AddOpCode( ocSep );
916 : 0 : pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true()
917 : : }
918 : 0 : break;
919 : : case ocNormDist:
920 [ # # ]: 0 : if ( mnCurArg == 2 )
921 : : {
922 : 0 : pNewArr->AddOpCode( ocSep );
923 : 0 : pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
924 : : }
925 : 0 : break;
926 : : case ocLogNormDist:
927 [ # # ]: 0 : if ( mnCurArg == 0 )
928 : : {
929 : 0 : pNewArr->AddOpCode( ocSep );
930 : 0 : pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0
931 : : }
932 [ # # ]: 0 : if ( mnCurArg <= 1 )
933 : : {
934 : 0 : pNewArr->AddOpCode( ocSep );
935 : 0 : pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
936 : : }
937 : 0 : break;
938 : : case ocLog:
939 [ # # ][ # # ]: 0 : if ( !rConv.isODFF() && mnCurArg == 0 )
[ # # ]
940 : : {
941 : 0 : pNewArr->AddOpCode( ocSep );
942 : 0 : pNewArr->AddDouble( 10.0 ); // 2nd, basis 10
943 : : }
944 : 0 : break;
945 : : default:
946 : 0 : break;
947 : : }
948 : : }
949 : :
950 : 0 : inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const
951 : : {
952 [ # # ]: 0 : if (mnCurArg == nArg)
953 : : {
954 : 0 : pNewArr->AddDouble( f );
955 : 0 : return true;
956 : : }
957 : 0 : return false;
958 : : }
959 : :
960 : 0 : bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray *pNewArr ) const
961 : : {
962 : : // Only called for PODF, not ODFF. No need to distinguish.
963 : :
964 : 0 : const String &rName = mpFunc->GetExternal();
965 : :
966 : : // initial (fast) check:
967 : 0 : sal_Unicode nLastChar = rName.GetChar( rName.Len() - 1);
968 [ # # ][ # # ]: 0 : if ( nLastChar != 't' && nLastChar != 'm' )
969 : 0 : return false;
970 : :
971 [ # # ]: 0 : if (rName.EqualsIgnoreCaseAscii(
972 : 0 : "com.sun.star.sheet.addin.Analysis.getAccrint" ))
973 : : {
974 : 0 : return AddDefaultArg( pNewArr, 4, 1000.0 );
975 : : }
976 [ # # ]: 0 : if (rName.EqualsIgnoreCaseAscii(
977 : 0 : "com.sun.star.sheet.addin.Analysis.getAccrintm" ))
978 : : {
979 : 0 : return AddDefaultArg( pNewArr, 3, 1000.0 );
980 : : }
981 : 0 : return false;
982 : : }
983 : :
984 : 0 : bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
985 : : {
986 [ # # ]: 0 : if ( !mpFunc )
987 : 0 : return false;
988 : :
989 : 0 : bool bRet = false;
990 : 0 : const OpCode eOp = mpFunc->GetOpCode();
991 : :
992 : : // Add for both, PODF and ODFF
993 [ # # ]: 0 : switch (eOp)
994 : : {
995 : : case ocAddress:
996 : 0 : return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
997 : : default:
998 : 0 : break;
999 : : }
1000 : :
1001 [ # # ]: 0 : if (rConv.isODFF())
1002 : : {
1003 : : // Add for ODFF
1004 : : }
1005 : : else
1006 : : {
1007 : : // Add for PODF
1008 [ # # # # : 0 : switch (eOp)
# # # # ]
1009 : : {
1010 : : case ocFixed:
1011 : 0 : return AddDefaultArg( pNewArr, 1, 2.0 );
1012 : : case ocBetaDist:
1013 : : case ocBetaInv:
1014 : : case ocRMZ: // PMT
1015 : 0 : return AddDefaultArg( pNewArr, 3, 0.0 );
1016 : : case ocZinsZ: // IPMT
1017 : : case ocKapz: // PPMT
1018 : 0 : return AddDefaultArg( pNewArr, 4, 0.0 );
1019 : : case ocBW: // PV
1020 : : case ocZW: // FV
1021 : 0 : bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt
1022 : 0 : bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v
1023 : 0 : break;
1024 : : case ocZins: // RATE
1025 : 0 : bRet |= AddDefaultArg( pNewArr, 1, 0.0 ); // pmt
1026 : 0 : bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // fv
1027 : 0 : bRet |= AddDefaultArg( pNewArr, 4, 0.0 ); // type
1028 : 0 : break;
1029 : : case ocExternal:
1030 : 0 : return AddMissingExternal( pNewArr );
1031 : :
1032 : : // --- more complex cases ---
1033 : :
1034 : : case ocOffset:
1035 : : // FIXME: rather tough.
1036 : : // if arg 3 (height) ommitted, export arg1 (rows)
1037 : 0 : break;
1038 : : default:
1039 : 0 : break;
1040 : : }
1041 : : }
1042 : :
1043 : 0 : return bRet;
1044 : : }
1045 : :
1046 : 146 : bool FormulaTokenArray::NeedsPofRewrite( const MissingConvention & rConv )
1047 : : {
1048 [ + + ]: 316 : for ( FormulaToken *pCur = First(); pCur; pCur = Next() )
1049 : : {
1050 [ - + ]: 170 : if ( rConv.isRewriteNeeded( pCur->GetOpCode()))
1051 : 0 : return true;
1052 : : }
1053 : 146 : return false;
1054 : : }
1055 : :
1056 : :
1057 : 0 : FormulaTokenArray * FormulaTokenArray::RewriteMissingToPof( const MissingConvention & rConv )
1058 : : {
1059 : 0 : const size_t nAlloc = 256;
1060 : : FormulaMissingContext aCtx[ nAlloc ];
1061 : : int aOpCodeAddressStack[ nAlloc ]; // use of ADDRESS() function
1062 : 0 : const int nOmitAddressArg = 3; // ADDRESS() 4th parameter A1/R1C1
1063 : 0 : sal_uInt16 nTokens = GetLen() + 1;
1064 [ # # ][ # # ]: 0 : FormulaMissingContext* pCtx = (nAlloc < nTokens ? new FormulaMissingContext[nTokens] : &aCtx[0]);
1065 [ # # ][ # # ]: 0 : int* pOcas = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeAddressStack[0]);
1066 : : // Never go below 0, never use 0, mpFunc always NULL.
1067 : 0 : pCtx[0].Clear();
1068 : 0 : int nFn = 0;
1069 : 0 : int nOcas = 0;
1070 : :
1071 [ # # ][ # # ]: 0 : FormulaTokenArray *pNewArr = new FormulaTokenArray;
1072 : : // At least RECALCMODE_ALWAYS needs to be set.
1073 [ # # ]: 0 : pNewArr->AddRecalcMode( GetRecalcMode());
1074 : :
1075 [ # # ][ # # ]: 0 : for ( FormulaToken *pCur = First(); pCur; pCur = Next() )
[ # # ]
1076 : : {
1077 : 0 : bool bAdd = true;
1078 : : // Don't write the expression of the new inserted ADDRESS() parameter.
1079 : : // Do NOT omit the new second parameter of INDIRECT() though. If that
1080 : : // was done for both, INDIRECT() actually could calculate different and
1081 : : // valid (but wrong) results with the then changed return value of
1082 : : // ADDRESS(). Better let it generate an error instead.
1083 [ # # ][ # # ]: 0 : for (int i = nOcas; i-- > 0 && bAdd; )
[ # # ]
1084 : : {
1085 [ # # ]: 0 : if (pCtx[ pOcas[ i ] ].mnCurArg == nOmitAddressArg)
1086 : : {
1087 : : // Omit erverything except a trailing separator, the leading
1088 : : // separator is omitted below. The other way around would leave
1089 : : // an extraneous separator if no parameter followed.
1090 [ # # ][ # # ]: 0 : if (!(pOcas[ i ] == nFn && pCur->GetOpCode() == ocSep))
[ # # ]
1091 : 0 : bAdd = false;
1092 : : }
1093 : : }
1094 [ # # # # : 0 : switch ( pCur->GetOpCode() )
# ]
1095 : : {
1096 : : case ocOpen:
1097 : 0 : ++nFn; // all following operations on _that_ function
1098 [ # # ]: 0 : pCtx[ nFn ].mpFunc = PeekPrevNoSpaces();
1099 : 0 : pCtx[ nFn ].mnCurArg = 0;
1100 [ # # ][ # # ]: 0 : if (pCtx[ nFn ].mpFunc && pCtx[ nFn ].mpFunc->GetOpCode() == ocAddress && !rConv.isODFF())
[ # # ][ # # ]
1101 : 0 : pOcas[ nOcas++ ] = nFn; // entering ADDRESS() if PODF
1102 : 0 : break;
1103 : : case ocClose:
1104 [ # # ]: 0 : pCtx[ nFn ].AddMoreArgs( pNewArr, rConv );
1105 : : DBG_ASSERT( nFn > 0, "FormulaTokenArray::RewriteMissingToPof: underflow");
1106 [ # # ][ # # ]: 0 : if (nOcas > 0 && pOcas[ nOcas-1 ] == nFn)
1107 : 0 : --nOcas; // leaving ADDRESS()
1108 [ # # ]: 0 : if (nFn > 0)
1109 : 0 : --nFn;
1110 : 0 : break;
1111 : : case ocSep:
1112 : 0 : pCtx[ nFn ].mnCurArg++;
1113 : : // Omit leading separator of ADDRESS() parameter.
1114 [ # # ][ # # ]: 0 : if (nOcas && pOcas[ nOcas-1 ] == nFn && pCtx[ nFn ].mnCurArg == nOmitAddressArg)
[ # # ]
1115 : : {
1116 : 0 : bAdd = false;
1117 : : }
1118 : 0 : break;
1119 : : case ocMissing:
1120 [ # # ]: 0 : if (bAdd)
1121 [ # # ]: 0 : bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv );
1122 : 0 : break;
1123 : : default:
1124 : 0 : break;
1125 : : }
1126 [ # # ]: 0 : if (bAdd)
1127 [ # # ]: 0 : pNewArr->AddToken( *pCur );
1128 : : }
1129 : :
1130 [ # # ]: 0 : if (pOcas != &aOpCodeAddressStack[0])
1131 [ # # ]: 0 : delete [] pOcas;
1132 [ # # ]: 0 : if (pCtx != &aCtx[0])
1133 [ # # ]: 0 : delete [] pCtx;
1134 : :
1135 : 0 : return pNewArr;
1136 : : }
1137 : :
1138 : 0 : bool FormulaTokenArray::MayReferenceFollow()
1139 : : {
1140 [ # # ][ # # ]: 0 : if ( pCode && nLen > 0 )
1141 : : {
1142 : : // ignore trailing spaces
1143 : 0 : sal_uInt16 i = nLen - 1;
1144 [ # # ][ # # ]: 0 : while ( i > 0 && pCode[i]->GetOpCode() == SC_OPCODE_SPACES )
[ # # ]
1145 : : {
1146 : 0 : --i;
1147 : : }
1148 [ # # ][ # # ]: 0 : if ( i > 0 || pCode[i]->GetOpCode() != SC_OPCODE_SPACES )
[ # # ]
1149 : : {
1150 : 0 : OpCode eOp = pCode[i]->GetOpCode();
1151 [ # # ][ # # ]: 0 : if ( (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP ) ||
[ # # ][ # # ]
[ # # ][ # # ]
1152 : : (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP ) ||
1153 : : eOp == SC_OPCODE_OPEN || eOp == SC_OPCODE_SEP )
1154 : : {
1155 : 0 : return true;
1156 : : }
1157 : : }
1158 : : }
1159 : 0 : return false;
1160 : : }
1161 : 0 : FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp )
1162 : : {
1163 : 0 : FormulaToken* pRet = NULL;
1164 [ # # # ]: 0 : switch ( eOp )
1165 : : {
1166 : : case ocOpen:
1167 : : case ocClose:
1168 : : case ocSep:
1169 : : case ocArrayOpen:
1170 : : case ocArrayClose:
1171 : : case ocArrayRowSep:
1172 : : case ocArrayColSep:
1173 : 0 : pRet = new FormulaToken( svSep,eOp );
1174 : 0 : break;
1175 : : case ocIf:
1176 : : case ocChose:
1177 : : {
1178 : : short nJump[MAXJUMPCOUNT + 1];
1179 [ # # ]: 0 : nJump[ 0 ] = ocIf == eOp ? 3 : MAXJUMPCOUNT+1;
1180 [ # # ][ # # ]: 0 : pRet = new FormulaJumpToken( eOp, (short*)nJump );
1181 : : }
1182 : 0 : break;
1183 : : default:
1184 [ # # ]: 0 : pRet = new FormulaByteToken( eOp, 0, false );
1185 : 0 : break;
1186 : : }
1187 : 0 : return AddToken( *pRet );
1188 : : }
1189 : :
1190 : :
1191 : : /*----------------------------------------------------------------------*/
1192 : :
1193 : 2619 : FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray& rArr )
1194 : : {
1195 : 2619 : pCur = NULL;
1196 : 2619 : Push( &rArr );
1197 : 2619 : }
1198 : :
1199 : 2619 : FormulaTokenIterator::~FormulaTokenIterator()
1200 : : {
1201 [ + + ]: 5238 : while( pCur )
1202 : 2619 : Pop();
1203 : 2619 : }
1204 : :
1205 : 2664 : void FormulaTokenIterator::Push( const FormulaTokenArray* pArr )
1206 : : {
1207 : 2664 : ImpTokenIterator* p = new ImpTokenIterator;
1208 : 2664 : p->pArr = pArr;
1209 : 2664 : p->nPC = -1;
1210 : 2664 : p->nStop = SHRT_MAX;
1211 : 2664 : p->pNext = pCur;
1212 : 2664 : pCur = p;
1213 : 2664 : }
1214 : :
1215 : 2664 : void FormulaTokenIterator::Pop()
1216 : : {
1217 : 2664 : ImpTokenIterator* p = pCur;
1218 [ + - ]: 2664 : if( p )
1219 : : {
1220 : 2664 : pCur = p->pNext;
1221 : 2664 : delete p;
1222 : : }
1223 : 2664 : }
1224 : :
1225 : 2619 : void FormulaTokenIterator::Reset()
1226 : : {
1227 [ - + ]: 2619 : while( pCur->pNext )
1228 : 0 : Pop();
1229 : 2619 : pCur->nPC = -1;
1230 : 2619 : }
1231 : :
1232 : 0 : const FormulaToken* FormulaTokenIterator::First()
1233 : : {
1234 : 0 : Reset();
1235 : 0 : return Next();
1236 : : }
1237 : :
1238 : 9983 : const FormulaToken* FormulaTokenIterator::Next()
1239 : : {
1240 : 9983 : const FormulaToken* t = GetNonEndOfPathToken( ++pCur->nPC );
1241 [ + + ][ + + ]: 9983 : if( !t && pCur->pNext )
1242 : : {
1243 : 45 : Pop();
1244 : 45 : t = Next();
1245 : : }
1246 : 9983 : return t;
1247 : : }
1248 : :
1249 : 0 : const FormulaToken* FormulaTokenIterator::PeekNextOperator()
1250 : : {
1251 : 0 : const FormulaToken* t = NULL;
1252 : 0 : short nIdx = pCur->nPC;
1253 [ # # ][ # # ]: 0 : while (!t && ((t = GetNonEndOfPathToken( ++nIdx)) != NULL))
[ # # ]
1254 : : {
1255 [ # # ]: 0 : if (t->GetOpCode() == ocPush)
1256 : 0 : t = NULL; // ignore operands
1257 : : }
1258 [ # # ][ # # ]: 0 : if (!t && pCur->pNext)
1259 : : {
1260 : 0 : ImpTokenIterator* pHere = pCur;
1261 : 0 : pCur = pCur->pNext;
1262 : 0 : t = PeekNextOperator();
1263 : 0 : pCur = pHere;
1264 : : }
1265 : 0 : return t;
1266 : : }
1267 : :
1268 : : //! The nPC counts after a Push() are -1
1269 : :
1270 : 66 : void FormulaTokenIterator::Jump( short nStart, short nNext, short nStop )
1271 : : {
1272 : 66 : pCur->nPC = nNext;
1273 [ + + ]: 66 : if( nStart != nNext )
1274 : : {
1275 : 45 : Push( pCur->pArr );
1276 : 45 : pCur->nPC = nStart;
1277 : 45 : pCur->nStop = nStop;
1278 : : }
1279 : 66 : }
1280 : :
1281 : 9983 : const FormulaToken* FormulaTokenIterator::GetNonEndOfPathToken( short nIdx ) const
1282 : : {
1283 [ + + ][ + - ]: 9983 : if (nIdx < pCur->pArr->nRPN && nIdx < pCur->nStop)
1284 : : {
1285 : 7370 : const FormulaToken* t = pCur->pArr->pRPN[ nIdx ];
1286 : : // such an OpCode ends an IF() or CHOOSE() path
1287 [ + + ][ + + ]: 7370 : return (t->GetOpCode() == ocSep || t->GetOpCode() == ocClose) ? NULL : t;
1288 : : }
1289 : 9983 : return NULL;
1290 : : }
1291 : :
1292 : 0 : bool FormulaTokenIterator::IsEndOfPath() const
1293 : : {
1294 : 0 : return GetNonEndOfPathToken( pCur->nPC + 1) == NULL;
1295 : : }
1296 : :
1297 : : // -----------------------------------------------------------------------------
1298 : : // ==========================================================================
1299 : : // real implementations of virtual functions
1300 : : // --------------------------------------------------------------------------
1301 : :
1302 : 4010 : double FormulaDoubleToken::GetDouble() const { return fDouble; }
1303 : 0 : double & FormulaDoubleToken::GetDoubleAsReference() { return fDouble; }
1304 : 0 : bool FormulaDoubleToken::operator==( const FormulaToken& r ) const
1305 : : {
1306 [ # # ][ # # ]: 0 : return FormulaToken::operator==( r ) && fDouble == r.GetDouble();
1307 : : }
1308 : :
1309 : :
1310 : 640 : const String& FormulaStringToken::GetString() const { return aString; }
1311 : 0 : bool FormulaStringToken::operator==( const FormulaToken& r ) const
1312 : : {
1313 [ # # ][ # # ]: 0 : return FormulaToken::operator==( r ) && aString == r.GetString();
1314 : : }
1315 : :
1316 : :
1317 : 1241 : const String& FormulaStringOpToken::GetString() const { return aString; }
1318 : 63 : bool FormulaStringOpToken::operator==( const FormulaToken& r ) const
1319 : : {
1320 [ + - ][ + - ]: 63 : return FormulaByteToken::operator==( r ) && aString == r.GetString();
1321 : : }
1322 : :
1323 : 386 : sal_uInt16 FormulaIndexToken::GetIndex() const { return nIndex; }
1324 : 34 : void FormulaIndexToken::SetIndex( sal_uInt16 n ) { nIndex = n; }
1325 : 343 : bool FormulaIndexToken::IsGlobal() const { return mbGlobal; }
1326 : 34 : void FormulaIndexToken::SetGlobal( bool b ) { mbGlobal = b; }
1327 : 0 : bool FormulaIndexToken::operator==( const FormulaToken& r ) const
1328 : : {
1329 : 0 : return FormulaToken::operator==( r ) && nIndex == r.GetIndex() &&
1330 [ # # ]: 0 : mbGlobal == r.IsGlobal();
[ # # # # ]
1331 : : }
1332 : 0 : const String& FormulaExternalToken::GetExternal() const { return aExternal; }
1333 : 0 : sal_uInt8 FormulaExternalToken::GetByte() const { return nByte; }
1334 : 3 : void FormulaExternalToken::SetByte( sal_uInt8 n ) { nByte = n; }
1335 : 0 : bool FormulaExternalToken::operator==( const FormulaToken& r ) const
1336 : : {
1337 : 0 : return FormulaToken::operator==( r ) && nByte == r.GetByte() &&
1338 [ # # ]: 0 : aExternal == r.GetExternal();
[ # # # # ]
1339 : : }
1340 : :
1341 : :
1342 : 960 : sal_uInt16 FormulaErrorToken::GetError() const { return nError; }
1343 : 0 : void FormulaErrorToken::SetError( sal_uInt16 nErr ) { nError = nErr; }
1344 : 0 : bool FormulaErrorToken::operator==( const FormulaToken& r ) const
1345 : : {
1346 : 0 : return FormulaToken::operator==( r ) &&
1347 [ # # ][ # # ]: 0 : nError == static_cast< const FormulaErrorToken & >(r).GetError();
1348 : : }
1349 : 0 : double FormulaMissingToken::GetDouble() const { return 0.0; }
1350 : 0 : const String& FormulaMissingToken::GetString() const
1351 : : {
1352 [ # # ][ # # ]: 0 : static String aDummyString;
[ # # ][ # # ]
1353 : 0 : return aDummyString;
1354 : : }
1355 : 0 : bool FormulaMissingToken::operator==( const FormulaToken& r ) const
1356 : : {
1357 : 0 : return FormulaToken::operator==( r );
1358 : : }
1359 : :
1360 : :
1361 : 0 : FormulaSubroutineToken::FormulaSubroutineToken( const FormulaSubroutineToken& r ) :
1362 : : FormulaToken( r ),
1363 [ # # ]: 0 : mpArray( r.mpArray->Clone())
1364 : : {
1365 : 0 : }
1366 : 0 : FormulaSubroutineToken::~FormulaSubroutineToken()
1367 : : {
1368 [ # # ][ # # ]: 0 : delete mpArray;
1369 [ # # ]: 0 : }
1370 : 0 : bool FormulaSubroutineToken::operator==( const FormulaToken& r ) const
1371 : : {
1372 : : // Arrays don't equal..
1373 : 0 : return FormulaToken::operator==( r ) &&
1374 [ # # ][ # # ]: 0 : (mpArray == static_cast<const FormulaSubroutineToken&>(r).mpArray);
1375 : : }
1376 : :
1377 : :
1378 : 0 : bool FormulaUnknownToken::operator==( const FormulaToken& r ) const
1379 : : {
1380 : 0 : return FormulaToken::operator==( r );
1381 : : }
1382 : :
1383 : : // -----------------------------------------------------------------------------
1384 [ + - ][ + - ]: 171 : } // formula
1385 : : // -----------------------------------------------------------------------------
1386 : :
1387 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|