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