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