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 : #include <sal/macros.h>
20 : #include "formula/FormulaCompiler.hxx"
21 : #include "formula/errorcodes.hxx"
22 : #include "formula/token.hxx"
23 : #include "formula/tokenarray.hxx"
24 : #include "core_resource.hxx"
25 : #include "core_resource.hrc"
26 :
27 : #include "osl/mutex.hxx"
28 :
29 : #include <svl/zforlist.hxx>
30 : #include <tools/rc.hxx>
31 : #include <tools/rcid.h>
32 : #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
33 : #include <com/sun/star/sheet/FormulaMapGroup.hpp>
34 : #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
35 : #include <rtl/strbuf.hxx>
36 : #include <stdio.h>
37 :
38 : namespace formula
39 : {
40 : using namespace ::com::sun::star;
41 :
42 : static const sal_Char* pInternal[2] = { "TTT", "__DEBUG_VAR" };
43 :
44 : namespace {
45 :
46 : class FormulaCompilerRecursionGuard
47 : {
48 : private:
49 : short& rRecursion;
50 : public:
51 169540 : FormulaCompilerRecursionGuard( short& rRec )
52 169540 : : rRecursion( rRec ) { ++rRecursion; }
53 169540 : ~FormulaCompilerRecursionGuard() { --rRecursion; }
54 : };
55 :
56 8384 : short lcl_GetRetFormat( OpCode eOpCode )
57 : {
58 8384 : switch (eOpCode)
59 : {
60 : case ocEqual:
61 : case ocNotEqual:
62 : case ocLess:
63 : case ocGreater:
64 : case ocLessEqual:
65 : case ocGreaterEqual:
66 : case ocAnd:
67 : case ocOr:
68 : case ocXor:
69 : case ocNot:
70 : case ocTrue:
71 : case ocFalse:
72 : case ocIsEmpty:
73 : case ocIsString:
74 : case ocIsNonString:
75 : case ocIsLogical:
76 : case ocIsRef:
77 : case ocIsValue:
78 : case ocIsFormula:
79 : case ocIsNA:
80 : case ocIsErr:
81 : case ocIsError:
82 : case ocIsEven:
83 : case ocIsOdd:
84 : case ocExact:
85 324 : return NUMBERFORMAT_LOGICAL;
86 : case ocGetActDate:
87 : case ocGetDate:
88 : case ocEasterSunday :
89 8 : return NUMBERFORMAT_DATE;
90 : case ocGetActTime:
91 6 : return NUMBERFORMAT_DATETIME;
92 : case ocGetTime:
93 0 : return NUMBERFORMAT_TIME;
94 : case ocNPV:
95 : case ocBW:
96 : case ocDIA:
97 : case ocGDA:
98 : case ocGDA2:
99 : case ocVBD:
100 : case ocLIA:
101 : case ocRMZ:
102 : case ocZW:
103 : case ocZinsZ:
104 : case ocKapz:
105 : case ocKumZinsZ:
106 : case ocKumKapZ:
107 72 : return NUMBERFORMAT_CURRENCY;
108 : case ocZins:
109 : case ocIRR:
110 : case ocMIRR:
111 : case ocZGZ:
112 : case ocEffektiv:
113 : case ocNominal:
114 : case ocPercentSign:
115 32 : return NUMBERFORMAT_PERCENT;
116 : default:
117 7942 : return NUMBERFORMAT_NUMBER;
118 : }
119 : }
120 :
121 168696 : inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
122 : const OUString* pTable, sal_uInt16 nOpCode )
123 : {
124 168696 : sheet::FormulaOpCodeMapEntry aEntry;
125 168696 : aEntry.Token.OpCode = nOpCode;
126 168696 : aEntry.Name = pTable[nOpCode];
127 168696 : rVec.push_back( aEntry);
128 168696 : }
129 :
130 852 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
131 : const OUString* pTable, sal_uInt16 nOpCodeBeg, sal_uInt16 nOpCodeEnd )
132 : {
133 40470 : for (sal_uInt16 nOpCode = nOpCodeBeg; nOpCode < nOpCodeEnd; ++nOpCode)
134 39618 : lclPushOpCodeMapEntry( rVec, pTable, nOpCode );
135 852 : }
136 :
137 1278 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
138 : const OUString* pTable, const sal_uInt16* pnOpCodes, size_t nCount )
139 : {
140 7668 : for (const sal_uInt16* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes)
141 6390 : lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes );
142 1278 : }
143 :
144 154 : class OpCodeList : public Resource // temp object for resource
145 : {
146 : public:
147 :
148 : OpCodeList( sal_uInt16, FormulaCompiler::NonConstOpCodeMapPtr,
149 : FormulaCompiler::SeparatorType = FormulaCompiler::SEMICOLON_BASE );
150 :
151 : private:
152 : bool getOpCodeString( OUString& rStr, sal_uInt16 nOp );
153 : void putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp );
154 :
155 : private:
156 : FormulaCompiler::SeparatorType meSepType;
157 : };
158 :
159 154 : OpCodeList::OpCodeList( sal_uInt16 nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap,
160 : FormulaCompiler::SeparatorType eSepType ) :
161 154 : Resource( ResId( nRID, *ResourceManager::getResManager()))
162 154 : , meSepType( eSepType)
163 : {
164 154 : if (meSepType == FormulaCompiler::RESOURCE_BASE)
165 : {
166 33110 : for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
167 : {
168 33040 : putDefaultOpCode( xMap, i);
169 : }
170 : }
171 : else
172 : {
173 39732 : for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
174 : {
175 39648 : OUString aOpStr;
176 39648 : if ( getOpCodeString( aOpStr, i) )
177 252 : xMap->putOpCode( aOpStr, OpCode(i));
178 : else
179 39396 : putDefaultOpCode( xMap, i);
180 39648 : }
181 : }
182 :
183 154 : FreeResource();
184 154 : }
185 :
186 39648 : bool OpCodeList::getOpCodeString( OUString& rStr, sal_uInt16 nOp )
187 : {
188 39648 : switch (nOp)
189 : {
190 : case SC_OPCODE_SEP:
191 : {
192 84 : if (meSepType == FormulaCompiler::COMMA_BASE)
193 : {
194 0 : rStr = ",";
195 0 : return true;
196 : }
197 84 : else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
198 : {
199 84 : rStr = ";";
200 84 : return true;
201 : }
202 : }
203 0 : break;
204 : case SC_OPCODE_ARRAY_COL_SEP:
205 : {
206 84 : if (meSepType == FormulaCompiler::COMMA_BASE)
207 : {
208 0 : rStr = ",";
209 0 : return true;
210 : }
211 84 : else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
212 : {
213 84 : rStr = ";";
214 84 : return true;
215 : }
216 : }
217 0 : break;
218 : case SC_OPCODE_ARRAY_ROW_SEP:
219 : {
220 84 : if (meSepType == FormulaCompiler::COMMA_BASE)
221 : {
222 0 : rStr = ";";
223 0 : return true;
224 : }
225 84 : else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
226 : {
227 84 : rStr = "|";
228 84 : return true;
229 : }
230 : }
231 0 : break;
232 : }
233 :
234 39396 : return false;
235 : }
236 :
237 72436 : void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp )
238 : {
239 72436 : ResId aRes( nOp, *ResourceManager::getResManager());
240 72436 : aRes.SetRT( RSC_STRING);
241 72436 : if (IsAvailableRes( aRes))
242 61348 : xMap->putOpCode( aRes.toString(), OpCode( nOp));
243 72436 : }
244 :
245 : // static
246 488 : const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr, sal_Unicode c )
247 : {
248 488 : if ( !pStr )
249 0 : return NULL;
250 3834 : while ( *pStr )
251 : {
252 2858 : if ( *pStr == c )
253 0 : return pStr;
254 2858 : pStr++;
255 : }
256 488 : return NULL;
257 : }
258 :
259 304 : struct OpCodeMapData
260 : {
261 : FormulaCompiler::NonConstOpCodeMapPtr mxSymbolMap;
262 : osl::Mutex maMtx;
263 : };
264 :
265 :
266 : } // namespace
267 :
268 :
269 58476 : void FormulaCompiler::OpCodeMap::putExternal( const OUString & rSymbol, const OUString & rAddIn )
270 : {
271 : // Different symbols may map to the same AddIn, but the same AddIn may not
272 : // map to different symbols, the first pair wins. Same symbol of course may
273 : // not map to different AddIns, again the first pair wins and also the
274 : // AddIn->symbol mapping is not inserted in other cases.
275 58476 : bool bOk = mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second;
276 : SAL_WARN_IF( !bOk, "formula.core", "OpCodeMap::putExternal: symbol not inserted, " << rSymbol << " -> " << rAddIn);
277 58476 : if (bOk)
278 : {
279 58476 : bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
280 : // Failed insertion of the AddIn is ok for different symbols mapping to
281 : // the same AddIn. Make this INFO only.
282 : SAL_INFO_IF( !bOk, "formula.core", "OpCodeMap::putExternal: AddIn not inserted, " << rAddIn << " -> " << rSymbol);
283 : }
284 58476 : }
285 :
286 4052 : void FormulaCompiler::OpCodeMap::putExternalSoftly( const OUString & rSymbol, const OUString & rAddIn )
287 : {
288 4052 : bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
289 4052 : if (bOk)
290 80 : mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn));
291 4052 : }
292 :
293 0 : uno::Sequence< sheet::FormulaToken > FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(
294 : const FormulaCompiler& rCompiler, const uno::Sequence< OUString >& rNames ) const
295 : {
296 0 : const sal_Int32 nLen = rNames.getLength();
297 0 : uno::Sequence< sheet::FormulaToken > aTokens( nLen);
298 0 : sheet::FormulaToken* pToken = aTokens.getArray();
299 0 : OUString const * pName = rNames.getConstArray();
300 0 : OUString const * const pStop = pName + nLen;
301 0 : for ( ; pName < pStop; ++pName, ++pToken)
302 : {
303 0 : OpCodeHashMap::const_iterator iLook( mpHashMap->find( *pName));
304 0 : if (iLook != mpHashMap->end())
305 0 : pToken->OpCode = (*iLook).second;
306 : else
307 : {
308 0 : OUString aIntName;
309 0 : if (hasExternals())
310 : {
311 0 : ExternalHashMap::const_iterator iExt( mpExternalHashMap->find( *pName));
312 0 : if (iExt != mpExternalHashMap->end())
313 0 : aIntName = (*iExt).second;
314 : // Check for existence not needed here, only name-mapping is of
315 : // interest.
316 : }
317 0 : if (aIntName.isEmpty())
318 0 : aIntName = rCompiler.FindAddInFunction(*pName, !isEnglish()); // bLocalFirst=false for english
319 0 : if (aIntName.isEmpty())
320 0 : pToken->OpCode = getOpCodeUnknown();
321 : else
322 : {
323 0 : pToken->OpCode = ocExternal;
324 0 : pToken->Data <<= aIntName;
325 0 : }
326 : }
327 : }
328 0 : return aTokens;
329 : }
330 :
331 2556 : uno::Sequence< sheet::FormulaOpCodeMapEntry > FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(
332 : const FormulaCompiler& rCompiler, const sal_Int32 nGroups ) const
333 : {
334 : using namespace sheet;
335 :
336 : // Unfortunately uno::Sequence can't grow without cumbersome reallocs. As
337 : // we don't know in advance how many elements it will have we use a
338 : // temporary vector to add elements and then copy to Sequence :-(
339 2556 : ::std::vector< FormulaOpCodeMapEntry > aVec;
340 :
341 2556 : if (nGroups == FormulaMapGroup::SPECIAL)
342 : {
343 : // Use specific order, keep in sync with
344 : // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl
345 : static const struct
346 : {
347 : sal_Int32 nOff;
348 : OpCode eOp;
349 : } aMap[] = {
350 : { FormulaMapGroupSpecialOffset::PUSH , ocPush } ,
351 : { FormulaMapGroupSpecialOffset::CALL , ocCall } ,
352 : { FormulaMapGroupSpecialOffset::STOP , ocStop } ,
353 : { FormulaMapGroupSpecialOffset::EXTERNAL , ocExternal } ,
354 : { FormulaMapGroupSpecialOffset::NAME , ocName } ,
355 : { FormulaMapGroupSpecialOffset::NO_NAME , ocNoName } ,
356 : { FormulaMapGroupSpecialOffset::MISSING , ocMissing } ,
357 : { FormulaMapGroupSpecialOffset::BAD , ocBad } ,
358 : { FormulaMapGroupSpecialOffset::SPACES , ocSpaces } ,
359 : { FormulaMapGroupSpecialOffset::MAT_REF , ocMatRef } ,
360 : { FormulaMapGroupSpecialOffset::DB_AREA , ocDBArea } ,
361 : { FormulaMapGroupSpecialOffset::MACRO , ocMacro } ,
362 : { FormulaMapGroupSpecialOffset::COL_ROW_NAME , ocColRowName }
363 : };
364 426 : const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
365 : // Preallocate vector elements.
366 426 : if (aVec.size() < nCount)
367 : {
368 426 : FormulaOpCodeMapEntry aEntry;
369 426 : aEntry.Token.OpCode = getOpCodeUnknown();
370 426 : aVec.resize( nCount, aEntry);
371 : } // if (aVec.size() < nCount)
372 :
373 426 : FormulaOpCodeMapEntry aEntry;
374 5964 : for (size_t i=0; i < nCount; ++i)
375 : {
376 5538 : size_t nIndex = static_cast< size_t >( aMap[i].nOff );
377 5538 : if (aVec.size() <= nIndex)
378 : {
379 : // The offsets really should be aligned with the size, so if
380 : // the vector was preallocated above this code to resize it is
381 : // just a measure in case the table isn't in sync with the API,
382 : // usually it isn't executed.
383 0 : aEntry.Token.OpCode = getOpCodeUnknown();
384 0 : aVec.resize( nIndex + 1, aEntry );
385 : }
386 5538 : aEntry.Token.OpCode = aMap[i].eOp;
387 5538 : aVec[nIndex] = aEntry;
388 426 : }
389 : }
390 : else
391 : {
392 : /* FIXME: Once we support error constants in formulas we'll need a map
393 : * group for that, e.g. FormulaMapGroup::ERROR_CONSTANTS, and fill
394 : * SC_OPCODE_START_ERRORS to SC_OPCODE_STOP_ERRORS. */
395 :
396 : // Anything else but SPECIAL.
397 2130 : if ((nGroups & FormulaMapGroup::SEPARATORS) != 0)
398 : {
399 : static const sal_uInt16 aOpCodes[] = {
400 : SC_OPCODE_OPEN,
401 : SC_OPCODE_CLOSE,
402 : SC_OPCODE_SEP,
403 : };
404 426 : lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
405 : }
406 2130 : if ((nGroups & FormulaMapGroup::ARRAY_SEPARATORS) != 0)
407 : {
408 : static const sal_uInt16 aOpCodes[] = {
409 : SC_OPCODE_ARRAY_OPEN,
410 : SC_OPCODE_ARRAY_CLOSE,
411 : SC_OPCODE_ARRAY_ROW_SEP,
412 : SC_OPCODE_ARRAY_COL_SEP
413 : };
414 426 : lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
415 : }
416 2130 : if ((nGroups & FormulaMapGroup::UNARY_OPERATORS) != 0)
417 : {
418 : // Due to the nature of the percent operator following its operand
419 : // it isn't sorted into unary operators for compiler interna.
420 426 : lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
421 : // "+" can be used as unary operator too, push only if binary group is not set
422 426 : if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
423 426 : lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
424 : // regular unary operators
425 1704 : for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
426 : {
427 1278 : switch (nOp)
428 : {
429 : // NOT and NEG in fact are functions but for legacy reasons
430 : // are sorted into unary operators for compiler interna.
431 : case SC_OPCODE_NOT :
432 : case SC_OPCODE_NEG :
433 852 : break; // nothing,
434 : default:
435 426 : lclPushOpCodeMapEntry( aVec, mpTable, nOp );
436 : }
437 : }
438 : }
439 2130 : if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
440 : {
441 7668 : for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
442 : {
443 7242 : switch (nOp)
444 : {
445 : // AND and OR in fact are functions but for legacy reasons
446 : // are sorted into binary operators for compiler interna.
447 : case SC_OPCODE_AND :
448 : case SC_OPCODE_OR :
449 852 : break; // nothing,
450 : default:
451 6390 : lclPushOpCodeMapEntry( aVec, mpTable, nOp );
452 : }
453 : }
454 : }
455 2130 : if ((nGroups & FormulaMapGroup::FUNCTIONS) != 0)
456 : {
457 : // Function names are not consecutive, skip the gaps between
458 : // functions with no parameter, functions with 1 parameter
459 : lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_NO_PAR,
460 426 : ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
461 : lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_1_PAR,
462 426 : ::std::min< sal_uInt16 >( SC_OPCODE_STOP_1_PAR, mnSymbols ) );
463 : // Additional functions not within range of functions.
464 : static const sal_uInt16 aOpCodes[] = {
465 : SC_OPCODE_IF,
466 : SC_OPCODE_IF_ERROR,
467 : SC_OPCODE_IF_NA,
468 : SC_OPCODE_CHOSE,
469 : SC_OPCODE_AND,
470 : SC_OPCODE_OR,
471 : SC_OPCODE_NOT,
472 : SC_OPCODE_NEG
473 : };
474 426 : lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
475 : // functions with 2 or more parameters.
476 115872 : for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
477 : {
478 115446 : switch (nOp)
479 : {
480 : // NO_NAME is in SPECIAL.
481 : case SC_OPCODE_NO_NAME :
482 426 : break; // nothing,
483 : default:
484 115020 : lclPushOpCodeMapEntry( aVec, mpTable, nOp );
485 : }
486 : }
487 : // If AddIn functions are present in this mapping, use them, and only those.
488 426 : if (hasExternals())
489 : {
490 46860 : for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
491 : {
492 46434 : FormulaOpCodeMapEntry aEntry;
493 46434 : aEntry.Name = (*it).first;
494 46434 : aEntry.Token.Data <<= OUString( (*it).second);
495 46434 : aEntry.Token.OpCode = ocExternal;
496 46434 : aVec.push_back( aEntry);
497 46434 : }
498 : }
499 : else
500 : {
501 0 : rCompiler.fillAddInToken( aVec, isEnglish());
502 : }
503 : }
504 : }
505 2556 : const FormulaOpCodeMapEntry* pRet = aVec.empty() ? 0 : &aVec[0];
506 2556 : return uno::Sequence< FormulaOpCodeMapEntry >( pRet, aVec.size());
507 : }
508 :
509 :
510 231744 : void FormulaCompiler::OpCodeMap::putOpCode( const OUString & rStr, const OpCode eOp )
511 : {
512 : DBG_ASSERT( 0 < eOp && sal_uInt16(eOp) < mnSymbols, "OpCodeMap::putOpCode: OpCode out of range");
513 231744 : if (0 < eOp && sal_uInt16(eOp) < mnSymbols)
514 : {
515 : SAL_WARN_IF( !(mpTable[eOp].isEmpty() || (mpTable[eOp] == rStr) ||
516 : (eOp == ocCurrency) || (eOp == ocSep) || (eOp == ocArrayColSep) ||
517 : (eOp == ocArrayRowSep)), "formula.core",
518 : "OpCodeMap::putOpCode: reusing OpCode " << eOp
519 : << ", replacing '" << mpTable[eOp] << "' with '" << rStr << "' in "
520 : << (mbEnglish ? "" : "non-") << "English map 0x" << ::std::hex << meGrammar);
521 231744 : mpTable[eOp] = rStr;
522 231744 : mpHashMap->insert( OpCodeHashMap::value_type( rStr, eOp));
523 : }
524 231744 : }
525 :
526 : // class FormulaCompiler
527 :
528 19188 : FormulaCompiler::FormulaCompiler( FormulaTokenArray& rArr )
529 : :
530 : pArr( &rArr ),
531 : pCode( NULL ),
532 : pStack( NULL ),
533 : eLastOp( ocPush ),
534 : nRecursion( 0 ),
535 : nNumFmt( NUMBERFORMAT_UNDEFINED ),
536 : pc( 0 ),
537 : meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
538 : bAutoCorrect( false ),
539 : bCorrected( false ),
540 : glSubTotal( false ),
541 : mbJumpCommandReorder(true),
542 19188 : mbStopOnError(true)
543 : {
544 19188 : }
545 :
546 61880 : FormulaCompiler::FormulaCompiler()
547 : :
548 : pArr( NULL ),
549 : pCode( NULL ),
550 : pStack( NULL ),
551 : eLastOp( ocPush ),
552 : nRecursion(0),
553 : nNumFmt( NUMBERFORMAT_UNDEFINED ),
554 : pc( 0 ),
555 : meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
556 : bAutoCorrect( false ),
557 : bCorrected( false ),
558 : glSubTotal( false ),
559 : mbJumpCommandReorder(true),
560 61880 : mbStopOnError(true)
561 : {
562 61880 : }
563 :
564 81070 : FormulaCompiler::~FormulaCompiler()
565 : {
566 81070 : }
567 :
568 85002 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
569 : {
570 85002 : FormulaCompiler::OpCodeMapPtr xMap;
571 : using namespace sheet;
572 85002 : switch (nLanguage)
573 : {
574 : case FormulaLanguage::ODFF :
575 8870 : if (!mxSymbolsODFF)
576 6740 : InitSymbolsODFF();
577 8870 : xMap = mxSymbolsODFF;
578 8870 : break;
579 : case FormulaLanguage::ODF_11 :
580 692 : if (!mxSymbolsPODF)
581 692 : InitSymbolsPODF();
582 692 : xMap = mxSymbolsPODF;
583 692 : break;
584 : case FormulaLanguage::ENGLISH :
585 304 : if (!mxSymbolsEnglish)
586 304 : InitSymbolsEnglish();
587 304 : xMap = mxSymbolsEnglish;
588 304 : break;
589 : case FormulaLanguage::NATIVE :
590 71888 : if (!mxSymbolsNative)
591 71752 : InitSymbolsNative();
592 71888 : xMap = mxSymbolsNative;
593 71888 : break;
594 : case FormulaLanguage::XL_ENGLISH:
595 628 : if (!mxSymbolsEnglishXL)
596 628 : InitSymbolsEnglishXL();
597 628 : xMap = mxSymbolsEnglishXL;
598 628 : break;
599 : case FormulaLanguage::OOXML:
600 2620 : if (!mxSymbolsOOXML)
601 2620 : InitSymbolsOOXML();
602 2620 : xMap = mxSymbolsOOXML;
603 2620 : break;
604 : default:
605 : ; // nothing, NULL map returned
606 : }
607 85002 : return xMap;
608 : }
609 :
610 0 : OUString FormulaCompiler::FindAddInFunction( const OUString& /*rUpperName*/, bool /*bLocalFirst*/ ) const
611 : {
612 0 : return OUString();
613 : }
614 :
615 426 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
616 : const uno::Sequence<
617 : const sheet::FormulaOpCodeMapEntry > & rMapping,
618 : bool bEnglish )
619 : {
620 : using sheet::FormulaOpCodeMapEntry;
621 : // Filter / API maps are never Core
622 : NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, false,
623 : FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(
624 426 : FormulaGrammar::GRAM_EXTERNAL, bEnglish), FormulaGrammar::CONV_UNSPECIFIED)));
625 426 : FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
626 426 : FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
627 216028 : for ( ; pArr2 < pStop; ++pArr2)
628 : {
629 215602 : OpCode eOp = OpCode(pArr2->Token.OpCode);
630 215602 : if (eOp != ocExternal)
631 166064 : xMap->putOpCode( pArr2->Name, eOp);
632 : else
633 : {
634 49538 : OUString aExternalName;
635 49538 : if (pArr2->Token.Data >>= aExternalName)
636 49538 : xMap->putExternal( pArr2->Name, aExternalName);
637 : else
638 : {
639 : SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
640 49538 : }
641 : }
642 : }
643 426 : return xMap;
644 : }
645 :
646 134067 : void lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& xMap, bool bDestroy = false )
647 : {
648 134067 : static OpCodeMapData aSymbolMap;
649 134067 : osl::MutexGuard aGuard(&aSymbolMap.maMtx);
650 :
651 134067 : if ( bDestroy )
652 : {
653 70 : aSymbolMap.mxSymbolMap.reset();
654 : }
655 133997 : else if (!aSymbolMap.mxSymbolMap)
656 : {
657 : // Core
658 : aSymbolMap.mxSymbolMap.reset(
659 : new FormulaCompiler::OpCodeMap(
660 72 : SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
661 72 : OModuleClient aModuleClient;
662 72 : OpCodeList aOpCodeListNative(RID_STRLIST_FUNCTION_NAMES, aSymbolMap.mxSymbolMap);
663 : // No AddInMap for native core mapping.
664 : }
665 :
666 134067 : xMap = aSymbolMap.mxSymbolMap;
667 134067 : }
668 :
669 61443 : const OUString& FormulaCompiler::GetNativeSymbol( OpCode eOp )
670 : {
671 61443 : NonConstOpCodeMapPtr xSymbolsNative;
672 61443 : lcl_fillNativeSymbols( xSymbolsNative);
673 61443 : return xSymbolsNative->getSymbol( eOp );
674 : }
675 :
676 57420 : sal_Unicode FormulaCompiler::GetNativeSymbolChar( OpCode eOp )
677 : {
678 57420 : return GetNativeSymbol(eOp)[0];
679 : }
680 :
681 71752 : void FormulaCompiler::InitSymbolsNative() const
682 : {
683 71752 : lcl_fillNativeSymbols( mxSymbolsNative);
684 71752 : }
685 :
686 304 : void FormulaCompiler::InitSymbolsEnglish() const
687 : {
688 304 : static OpCodeMapData aMap;
689 304 : osl::MutexGuard aGuard(&aMap.maMtx);
690 304 : if (!aMap.mxSymbolMap)
691 6 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
692 304 : mxSymbolsEnglish = aMap.mxSymbolMap;
693 304 : }
694 :
695 692 : void FormulaCompiler::InitSymbolsPODF() const
696 : {
697 692 : static OpCodeMapData aMap;
698 692 : osl::MutexGuard aGuard(&aMap.maMtx);
699 692 : if (!aMap.mxSymbolMap)
700 14 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_PODF, aMap.mxSymbolMap, RESOURCE_BASE);
701 692 : mxSymbolsPODF = aMap.mxSymbolMap;
702 692 : }
703 :
704 6740 : void FormulaCompiler::InitSymbolsODFF() const
705 : {
706 6740 : static OpCodeMapData aMap;
707 6740 : osl::MutexGuard aGuard(&aMap.maMtx);
708 6740 : if (!aMap.mxSymbolMap)
709 50 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF, FormulaGrammar::GRAM_ODFF, aMap.mxSymbolMap, RESOURCE_BASE);
710 6740 : mxSymbolsODFF = aMap.mxSymbolMap;
711 6740 : }
712 :
713 628 : void FormulaCompiler::InitSymbolsEnglishXL() const
714 : {
715 628 : static OpCodeMapData aMap;
716 628 : osl::MutexGuard aGuard(&aMap.maMtx);
717 628 : if (!aMap.mxSymbolMap)
718 6 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
719 628 : mxSymbolsEnglishXL = aMap.mxSymbolMap;
720 :
721 : // TODO: For now, just replace the separators to the Excel English
722 : // variants. Later, if we want to properly map Excel functions with Calc
723 : // functions, we'll need to do a little more work here.
724 628 : mxSymbolsEnglishXL->putOpCode( OUString(','), ocSep);
725 628 : mxSymbolsEnglishXL->putOpCode( OUString(','), ocArrayColSep);
726 628 : mxSymbolsEnglishXL->putOpCode( OUString(';'), ocArrayRowSep);
727 628 : }
728 :
729 2620 : void FormulaCompiler::InitSymbolsOOXML() const
730 : {
731 2620 : static OpCodeMapData aMap;
732 2620 : osl::MutexGuard aGuard(&aMap.maMtx);
733 2620 : if (!aMap.mxSymbolMap)
734 6 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML, FormulaGrammar::GRAM_OOXML, aMap.mxSymbolMap, RESOURCE_BASE);
735 2620 : mxSymbolsOOXML = aMap.mxSymbolMap;
736 2620 : }
737 :
738 :
739 82 : void FormulaCompiler::loadSymbols( sal_uInt16 nSymbols, FormulaGrammar::Grammar eGrammar,
740 : NonConstOpCodeMapPtr& rxMap, SeparatorType eSepType) const
741 : {
742 82 : if ( !rxMap.get() )
743 : {
744 : // not Core
745 82 : rxMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, eGrammar != FormulaGrammar::GRAM_ODFF, eGrammar ));
746 82 : OModuleClient aModuleClient;
747 164 : OpCodeList aOpCodeList( nSymbols, rxMap, eSepType);
748 :
749 82 : fillFromAddInMap( rxMap, eGrammar);
750 : // Fill from collection for AddIns not already present.
751 82 : if ( FormulaGrammar::GRAM_ENGLISH != eGrammar )
752 70 : fillFromAddInCollectionUpperName( rxMap);
753 : else
754 94 : fillFromAddInCollectionEnglishName( rxMap);
755 : }
756 82 : }
757 :
758 0 : void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const
759 : {
760 0 : }
761 :
762 0 : void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const
763 : {
764 0 : }
765 :
766 0 : void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const
767 : {
768 0 : }
769 :
770 0 : OpCode FormulaCompiler::GetEnglishOpCode( const OUString& rName ) const
771 : {
772 0 : FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap( sheet::FormulaLanguage::ENGLISH);
773 :
774 0 : formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) );
775 0 : bool bFound = (iLook != xMap->getHashMap()->end());
776 0 : return bFound ? (*iLook).second : OpCode(ocNone);
777 : }
778 :
779 43139 : bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
780 : {
781 43139 : bool bRet = false;
782 43139 : switch (eOp)
783 : {
784 : // no parameters:
785 : case ocRandom:
786 : case ocGetActDate:
787 : case ocGetActTime:
788 : // one parameter:
789 : case ocFormula:
790 : case ocInfo:
791 : // more than one parameters:
792 : // ocIndirect/ocIndirectXL otherwise would have to do
793 : // StopListening and StartListening on a reference for every
794 : // interpreted value.
795 : case ocIndirect:
796 : case ocIndirectXL:
797 : // ocOffset results in indirect references.
798 : case ocOffset:
799 : // ocDebugVar shows internal value that may change as the internal state changes.
800 : case ocDebugVar:
801 162 : bRet = true;
802 162 : break;
803 : default:
804 42977 : bRet = false;
805 42977 : break;
806 : }
807 43139 : return bRet;
808 : }
809 :
810 1816 : bool FormulaCompiler::IsOpCodeJumpCommand( OpCode eOp )
811 : {
812 1816 : switch (eOp)
813 : {
814 : case ocIf:
815 : case ocIfError:
816 : case ocIfNA:
817 : case ocChose:
818 80 : return true;
819 : default:
820 : ;
821 : }
822 1736 : return false;
823 : }
824 :
825 : // Remove quotes, escaped quotes are unescaped.
826 32 : bool FormulaCompiler::DeQuote( OUString& rStr )
827 : {
828 32 : sal_Int32 nLen = rStr.getLength();
829 32 : if ( nLen > 1 && rStr[0] == '\'' && rStr[ nLen-1 ] == '\'' )
830 : {
831 0 : rStr = rStr.copy( 1, nLen-2 );
832 0 : rStr = rStr.replaceAll( "\\\'", "\'" );
833 0 : return true;
834 : }
835 32 : return false;
836 : }
837 :
838 0 : void FormulaCompiler::fillAddInToken(
839 : ::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,
840 : bool /*_bIsEnglish*/) const
841 : {
842 0 : }
843 :
844 0 : bool FormulaCompiler::IsMatrixFunction( OpCode eOpCode )
845 : {
846 0 : switch (eOpCode)
847 : {
848 : case ocDde :
849 : case ocGrowth :
850 : case ocTrend :
851 : case ocRKP :
852 : case ocRGP :
853 : case ocFrequency :
854 : case ocMatTrans :
855 : case ocMatMult :
856 : case ocMatInv :
857 : case ocMatrixUnit :
858 : case ocModalValue_Multi :
859 0 : return true;
860 : default:
861 : {
862 : // added to avoid warnings
863 : }
864 : }
865 0 : return false;
866 : }
867 :
868 :
869 1160 : FormulaCompiler::OpCodeMap::~OpCodeMap()
870 : {
871 580 : delete mpReverseExternalHashMap;
872 580 : delete mpExternalHashMap;
873 580 : delete [] mpTable;
874 580 : delete mpHashMap;
875 1160 : }
876 :
877 0 : void FormulaCompiler::OpCodeMap::putCopyOpCode( const OUString& rSymbol, OpCode eOp )
878 : {
879 : SAL_WARN_IF( !mpTable[eOp].isEmpty() && rSymbol.isEmpty(), "formula.core",
880 : "OpCodeMap::putCopyOpCode: NOT replacing OpCode " << eOp << " '" << mpTable[eOp] << "' with empty name!");
881 0 : if (!mpTable[eOp].isEmpty() && rSymbol.isEmpty())
882 0 : mpHashMap->insert( OpCodeHashMap::value_type( mpTable[eOp], eOp));
883 : else
884 : {
885 0 : mpTable[eOp] = rSymbol;
886 0 : mpHashMap->insert( OpCodeHashMap::value_type( rSymbol, eOp));
887 : }
888 0 : }
889 :
890 0 : void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap& r, bool bOverrideKnownBad )
891 : {
892 0 : delete mpHashMap;
893 0 : mpHashMap = new OpCodeHashMap( mnSymbols);
894 :
895 0 : sal_uInt16 n = r.getSymbolCount();
896 : SAL_WARN_IF( n != mnSymbols, "formula.core",
897 : "OpCodeMap::copyFrom: unequal size, this: " << mnSymbols << " that: " << n);
898 0 : if (n > mnSymbols)
899 0 : n = mnSymbols;
900 :
901 : // OpCode 0 (ocPush) should never be in a map.
902 : SAL_WARN_IF( !mpTable[0].isEmpty() || !r.mpTable[0].isEmpty(), "formula.core",
903 : "OpCodeMap::copyFrom: OpCode 0 assigned, this: '"
904 : << mpTable[0] << "' that: '" << r.mpTable[0] << "'");
905 :
906 : // For bOverrideKnownBad when copying from the English core map (ODF 1.1
907 : // and API) to the native map (UI "use English function names") replace the
908 : // known bad legacy function names with correct ones.
909 0 : if (bOverrideKnownBad && r.mbCore &&
910 0 : FormulaGrammar::extractFormulaLanguage( meGrammar) == sheet::FormulaLanguage::NATIVE &&
911 0 : FormulaGrammar::extractFormulaLanguage( r.meGrammar) == sheet::FormulaLanguage::ENGLISH)
912 : {
913 0 : for (sal_uInt16 i = 1; i < n; ++i)
914 : {
915 0 : OUString aSymbol;
916 0 : OpCode eOp = OpCode(i);
917 0 : switch (eOp)
918 : {
919 : case ocZGZ:
920 0 : aSymbol = "RRI";
921 0 : break;
922 : case ocTableOp:
923 0 : aSymbol = "MULTIPLE.OPERATIONS";
924 0 : break;
925 : default:
926 0 : aSymbol = r.mpTable[i];
927 : }
928 0 : putCopyOpCode( aSymbol, eOp);
929 0 : }
930 : }
931 : else
932 : {
933 0 : for (sal_uInt16 i = 1; i < n; ++i)
934 : {
935 0 : OpCode eOp = OpCode(i);
936 0 : const OUString& rSymbol = r.mpTable[i];
937 0 : putCopyOpCode( rSymbol, eOp);
938 : }
939 : }
940 :
941 : // TODO: maybe copy the external maps too?
942 0 : }
943 :
944 :
945 74 : sal_uInt16 FormulaCompiler::GetErrorConstant( const OUString& rName ) const
946 : {
947 74 : sal_uInt16 nError = 0;
948 74 : OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
949 74 : if (iLook != mxSymbols->getHashMap()->end())
950 : {
951 74 : switch ((*iLook).second)
952 : {
953 : // Not all may make sense in a formula, but these we know as
954 : // opcodes.
955 : case ocErrNull:
956 0 : nError = errNoCode;
957 0 : break;
958 : case ocErrDivZero:
959 8 : nError = errDivisionByZero;
960 8 : break;
961 : case ocErrValue:
962 0 : nError = errNoValue;
963 0 : break;
964 : case ocErrRef:
965 46 : nError = errNoRef;
966 46 : break;
967 : case ocErrName:
968 0 : nError = errNoName;
969 0 : break;
970 : case ocErrNum:
971 0 : nError = errIllegalFPOperation;
972 0 : break;
973 : case ocErrNA:
974 20 : nError = NOTAVAILABLE;
975 20 : break;
976 : default:
977 : ; // nothing
978 : }
979 : }
980 74 : return nError;
981 : }
982 :
983 236 : void FormulaCompiler::EnableJumpCommandReorder( bool bEnable )
984 : {
985 236 : mbJumpCommandReorder = bEnable;
986 236 : }
987 :
988 234 : void FormulaCompiler::EnableStopOnError( bool bEnable )
989 : {
990 234 : mbStopOnError = bEnable;
991 234 : }
992 :
993 0 : void FormulaCompiler::AppendErrorConstant( OUStringBuffer& rBuffer, sal_uInt16 nError ) const
994 : {
995 : OpCode eOp;
996 0 : switch (nError)
997 : {
998 : default:
999 : case errNoCode:
1000 0 : eOp = ocErrNull;
1001 0 : break;
1002 : case errDivisionByZero:
1003 0 : eOp = ocErrDivZero;
1004 0 : break;
1005 : case errNoValue:
1006 0 : eOp = ocErrValue;
1007 0 : break;
1008 : case errNoRef:
1009 0 : eOp = ocErrRef;
1010 0 : break;
1011 : case errNoName:
1012 0 : eOp = ocErrName;
1013 0 : break;
1014 : case errIllegalFPOperation:
1015 0 : eOp = ocErrNum;
1016 0 : break;
1017 : case NOTAVAILABLE:
1018 0 : eOp = ocErrNA;
1019 0 : break;
1020 : }
1021 0 : rBuffer.append( mxSymbols->getSymbol( eOp));
1022 0 : }
1023 :
1024 :
1025 852 : sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
1026 : {
1027 : static const sal_Int32 kOpCodeUnknown = -1;
1028 852 : return kOpCodeUnknown;
1029 : }
1030 :
1031 125740 : bool FormulaCompiler::GetToken()
1032 : {
1033 : static const short nRecursionMax = 42;
1034 125740 : FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
1035 125740 : if ( nRecursion > nRecursionMax )
1036 : {
1037 0 : SetError( errStackOverflow );
1038 0 : mpToken = new FormulaByteToken( ocStop );
1039 0 : return false;
1040 : }
1041 125740 : if ( bAutoCorrect && !pStack )
1042 : { // don't merge stacked subroutine code into entered formula
1043 0 : aCorrectedFormula += aCorrectedSymbol;
1044 0 : aCorrectedSymbol = "";
1045 : }
1046 125740 : bool bStop = false;
1047 125740 : if (pArr->GetCodeError() && mbStopOnError)
1048 0 : bStop = true;
1049 : else
1050 : {
1051 : short nWasColRowName;
1052 125740 : if ( pArr->nIndex
1053 125740 : && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
1054 0 : nWasColRowName = 1;
1055 : else
1056 125740 : nWasColRowName = 0;
1057 125740 : mpToken = pArr->Next();
1058 252264 : while( mpToken && mpToken->GetOpCode() == ocSpaces )
1059 : {
1060 784 : if ( nWasColRowName )
1061 0 : nWasColRowName++;
1062 784 : if ( bAutoCorrect && !pStack )
1063 0 : CreateStringFromToken( aCorrectedFormula, mpToken.get(), false );
1064 784 : mpToken = pArr->Next();
1065 : }
1066 125740 : if ( bAutoCorrect && !pStack && mpToken )
1067 0 : CreateStringFromToken( aCorrectedSymbol, mpToken.get(), false );
1068 125740 : if( !mpToken )
1069 : {
1070 15926 : if( pStack )
1071 : {
1072 802 : PopTokenArray();
1073 802 : return GetToken();
1074 : }
1075 : else
1076 15124 : bStop = true;
1077 : }
1078 : else
1079 : {
1080 109814 : if ( nWasColRowName >= 2 && mpToken->GetOpCode() == ocColRowName )
1081 : { // convert an ocSpaces to ocIntersect in RPN
1082 0 : mpToken = new FormulaByteToken( ocIntersect );
1083 0 : pArr->nIndex--; // we advanced to the second ocColRowName, step back
1084 : }
1085 : }
1086 : }
1087 124938 : if( bStop )
1088 : {
1089 15124 : mpToken = new FormulaByteToken( ocStop );
1090 15124 : return false;
1091 : }
1092 219588 : if ( mpToken->GetOpCode() == ocSubTotal ||
1093 109774 : mpToken->GetOpCode() == ocAggregate )
1094 882 : glSubTotal = true;
1095 108932 : else if ( mpToken->IsExternalRef() )
1096 : {
1097 268 : return HandleExternalReference(*mpToken);
1098 : }
1099 108664 : else if( mpToken->GetOpCode() == ocName )
1100 : {
1101 722 : return HandleRange();
1102 : }
1103 107942 : else if( mpToken->GetOpCode() == ocColRowName )
1104 : {
1105 0 : return HandleSingleRef();
1106 : }
1107 107942 : else if( mpToken->GetOpCode() == ocDBArea )
1108 : {
1109 16 : return HandleDbData();
1110 : }
1111 107926 : else if( mpToken->GetType() == svSingleRef )
1112 : {
1113 20098 : pArr->nRefs++;
1114 : }
1115 87828 : else if( mpToken->GetType() == svDoubleRef )
1116 : {
1117 6298 : pArr->nRefs++;
1118 : }
1119 108808 : return true;
1120 : }
1121 :
1122 :
1123 : // RPN creation by recursion
1124 56800 : void FormulaCompiler::Factor()
1125 : {
1126 56800 : if (pArr->GetCodeError() && mbStopOnError)
1127 56800 : return;
1128 :
1129 56800 : CurrentFactor pFacToken( this );
1130 :
1131 56800 : OpCode eOp = mpToken->GetOpCode();
1132 56800 : if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
1133 : eOp == ocDBArea
1134 15714 : || (!mbJumpCommandReorder && ((eOp == ocName) || (eOp == ocDBArea)
1135 2 : || (eOp == ocColRowName) || (eOp == ocBad)))
1136 : )
1137 : {
1138 41086 : PutCode( mpToken );
1139 41086 : eOp = NextToken();
1140 82172 : if( eOp == ocOpen )
1141 : {
1142 : // PUSH( is an error that may be caused by an unknown function.
1143 : SetError(
1144 0 : ( mpToken->GetType() == svString
1145 0 : || mpToken->GetType() == svSingleRef )
1146 0 : ? errNoName : errOperatorExpected );
1147 0 : if ( bAutoCorrect && !pStack )
1148 : { // assume multiplication
1149 0 : aCorrectedFormula += mxSymbols->getSymbol( ocMul);
1150 0 : bCorrected = true;
1151 0 : NextToken();
1152 0 : eOp = Expression();
1153 0 : if( eOp != ocClose )
1154 0 : SetError( errPairExpected);
1155 : else
1156 0 : eOp = NextToken();
1157 : }
1158 : }
1159 : }
1160 15714 : else if( eOp == ocOpen )
1161 : {
1162 2042 : NextToken();
1163 2042 : eOp = Expression();
1164 4084 : while ((eOp == ocSep) && (!pArr->GetCodeError() || !mbStopOnError))
1165 : { // range list (A1;A2) converted to (A1~A2)
1166 0 : pFacToken = mpToken;
1167 0 : NextToken();
1168 0 : eOp = Expression();
1169 : // Do not ignore error here, regardless of bIgnoreErrors, otherwise
1170 : // errors like =(1;) would also result in display of =(1~)
1171 0 : if (!pArr->GetCodeError())
1172 : {
1173 0 : pFacToken->NewOpCode( ocUnion, FormulaToken::PrivateAccess());
1174 0 : PutCode( pFacToken);
1175 : }
1176 : }
1177 2042 : if (eOp != ocClose)
1178 0 : SetError( errPairExpected);
1179 : else
1180 2042 : eOp = NextToken();
1181 : }
1182 : else
1183 : {
1184 13672 : if( nNumFmt == NUMBERFORMAT_UNDEFINED )
1185 8384 : nNumFmt = lcl_GetRetFormat( eOp );
1186 :
1187 13672 : if ( IsOpCodeVolatile( eOp) )
1188 58 : pArr->SetExclusiveRecalcModeAlways();
1189 : else
1190 : {
1191 13614 : switch( eOp )
1192 : {
1193 : // Functions recalculated on every document load.
1194 : // Don't use SetExclusiveRecalcModeOnLoad() which would
1195 : // override ModeAlways, use
1196 : // AddRecalcMode(RECALCMODE_ONLOAD) instead.
1197 : case ocConvert :
1198 : case ocDde:
1199 : case ocMacro:
1200 : case ocExternal:
1201 190 : pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1202 190 : break;
1203 : // If the referred cell is moved the value changes.
1204 : case ocColumn :
1205 : case ocRow :
1206 136 : pArr->SetRecalcModeOnRefMove();
1207 136 : break;
1208 : // ocCell needs recalc on move for some possible type values.
1209 : // and recalc mode on load, fdo#60646
1210 : case ocCell :
1211 56 : pArr->SetRecalcModeOnRefMove();
1212 56 : pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1213 56 : break;
1214 : case ocHyperLink :
1215 : // cell with hyperlink needs to be calculated on load to
1216 : // get its matrix result generated.
1217 0 : pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1218 0 : pArr->SetHyperLink( true);
1219 0 : break;
1220 : default:
1221 : ; // nothing
1222 : }
1223 : }
1224 13672 : if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
1225 : {
1226 122 : pFacToken = mpToken;
1227 122 : eOp = NextToken();
1228 244 : if (eOp != ocOpen)
1229 : {
1230 0 : SetError( errPairExpected);
1231 0 : PutCode( pFacToken );
1232 : }
1233 : else
1234 : {
1235 122 : eOp = NextToken();
1236 122 : if (eOp != ocClose)
1237 0 : SetError( errPairExpected);
1238 122 : PutCode( pFacToken);
1239 122 : eOp = NextToken();
1240 : }
1241 : }
1242 : // special cases NOT() and NEG()
1243 13550 : else if( eOp == ocNot || eOp == ocNeg
1244 13550 : || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
1245 : {
1246 662 : pFacToken = mpToken;
1247 662 : eOp = NextToken();
1248 662 : if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot )
1249 0 : nNumFmt = NUMBERFORMAT_LOGICAL;
1250 662 : if (eOp == ocOpen)
1251 : {
1252 662 : NextToken();
1253 662 : eOp = Expression();
1254 : }
1255 : else
1256 0 : SetError( errPairExpected);
1257 662 : if (eOp != ocClose)
1258 0 : SetError( errPairExpected);
1259 662 : else if ( !pArr->GetCodeError() )
1260 662 : pFacToken->SetByte( 1 );
1261 662 : PutCode( pFacToken );
1262 662 : eOp = NextToken();
1263 : }
1264 23684 : else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
1265 2092 : || eOp == ocExternal
1266 1922 : || eOp == ocMacro
1267 1918 : || eOp == ocAnd
1268 1876 : || eOp == ocOr
1269 1846 : || eOp == ocBad
1270 1816 : || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1271 14704 : || (!mbJumpCommandReorder && IsOpCodeJumpCommand(eOp)))
1272 : {
1273 11074 : pFacToken = mpToken;
1274 11074 : OpCode eMyLastOp = eOp;
1275 11074 : eOp = NextToken();
1276 11074 : bool bNoParam = false;
1277 11074 : bool bBadName = false;
1278 11074 : if (eOp == ocOpen)
1279 : {
1280 11044 : eOp = NextToken();
1281 11044 : if (eOp == ocClose)
1282 90 : bNoParam = true;
1283 : else
1284 10954 : eOp = Expression();
1285 : }
1286 30 : else if (eMyLastOp == ocBad)
1287 : {
1288 : // Just a bad name, not an unknown function, no parameters, no
1289 : // closing expected.
1290 30 : bBadName = true;
1291 30 : bNoParam = true;
1292 : }
1293 : else
1294 0 : SetError( errPairExpected);
1295 11074 : sal_uInt8 nSepCount = 0;
1296 11074 : if( !bNoParam )
1297 : {
1298 10954 : nSepCount++;
1299 35032 : while ((eOp == ocSep) && (!pArr->GetCodeError() || !mbStopOnError))
1300 : {
1301 13124 : nSepCount++;
1302 13124 : NextToken();
1303 13124 : eOp = Expression();
1304 : }
1305 : }
1306 11074 : if (bBadName)
1307 : ; // nothing, keep current token for return
1308 11044 : else if (eOp != ocClose)
1309 0 : SetError( errPairExpected);
1310 : else
1311 11044 : eOp = NextToken();
1312 : // Jumps are just normal functions for the FunctionAutoPilot tree view
1313 11074 : if (!mbJumpCommandReorder && pFacToken->GetType() == svJump)
1314 2 : pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
1315 : else
1316 11072 : pFacToken->SetByte( nSepCount );
1317 11074 : PutCode( pFacToken );
1318 : }
1319 1814 : else if (IsOpCodeJumpCommand(eOp))
1320 : {
1321 : // the PC counters are -1
1322 78 : pFacToken = mpToken;
1323 78 : switch (eOp)
1324 : {
1325 : case ocIf:
1326 52 : pFacToken->GetJump()[ 0 ] = 3; // if, else, behind
1327 52 : break;
1328 : case ocChose:
1329 2 : pFacToken->GetJump()[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
1330 2 : break;
1331 : case ocIfError:
1332 : case ocIfNA:
1333 24 : pFacToken->GetJump()[ 0 ] = 2; // if, behind
1334 24 : break;
1335 : default:
1336 : SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump count case?");
1337 : }
1338 78 : eOp = NextToken();
1339 78 : if (eOp == ocOpen)
1340 : {
1341 78 : NextToken();
1342 78 : eOp = Expression();
1343 : }
1344 : else
1345 0 : SetError( errPairExpected);
1346 78 : PutCode( pFacToken );
1347 : // During AutoCorrect (since pArr->GetCodeError() is
1348 : // ignored) an unlimited ocIf would crash because
1349 : // ScRawToken::Clone() allocates the JumpBuffer according to
1350 : // nJump[0]*2+2, which is 3*2+2 on ocIf and 2*2+2 ocIfError and ocIfNA.
1351 : short nJumpMax;
1352 78 : OpCode eFacOpCode = pFacToken->GetOpCode();
1353 78 : switch (eFacOpCode)
1354 : {
1355 : case ocIf:
1356 52 : nJumpMax = 3;
1357 52 : break;
1358 : case ocChose:
1359 2 : nJumpMax = FORMULA_MAXJUMPCOUNT;
1360 2 : break;
1361 : case ocIfError:
1362 : case ocIfNA:
1363 24 : nJumpMax = 2;
1364 24 : break;
1365 : default:
1366 0 : nJumpMax = 0;
1367 : SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump max case?");
1368 : }
1369 78 : short nJumpCount = 0;
1370 434 : while ( (nJumpCount < (FORMULA_MAXJUMPCOUNT - 1)) && (eOp == ocSep)
1371 278 : && (!pArr->GetCodeError() || !mbStopOnError))
1372 : {
1373 100 : if ( ++nJumpCount <= nJumpMax )
1374 100 : pFacToken->GetJump()[nJumpCount] = pc-1;
1375 100 : NextToken();
1376 100 : eOp = Expression();
1377 : // ocSep or ocClose terminate the subexpression
1378 100 : PutCode( mpToken );
1379 : }
1380 78 : if (eOp != ocClose)
1381 0 : SetError( errPairExpected);
1382 : else
1383 : {
1384 78 : eOp = NextToken();
1385 : // always limit to nJumpMax, no arbitrary overwrites
1386 78 : if ( ++nJumpCount <= nJumpMax )
1387 78 : pFacToken->GetJump()[ nJumpCount ] = pc-1;
1388 78 : eFacOpCode = pFacToken->GetOpCode();
1389 : bool bLimitOk;
1390 78 : switch (eFacOpCode)
1391 : {
1392 : case ocIf:
1393 52 : bLimitOk = (nJumpCount <= 3);
1394 52 : break;
1395 : case ocChose:
1396 2 : bLimitOk = (nJumpCount < FORMULA_MAXJUMPCOUNT); /* TODO: check, really <, not <=? */
1397 2 : break;
1398 : case ocIfError:
1399 : case ocIfNA:
1400 24 : bLimitOk = (nJumpCount <= 2);
1401 24 : break;
1402 : default:
1403 0 : bLimitOk = false;
1404 : SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump limit case?");
1405 : }
1406 78 : if (bLimitOk)
1407 78 : pFacToken->GetJump()[ 0 ] = nJumpCount;
1408 : else
1409 0 : SetError( errIllegalParameter);
1410 : }
1411 : }
1412 1736 : else if ( eOp == ocMissing )
1413 : {
1414 26 : PutCode( mpToken );
1415 26 : eOp = NextToken();
1416 : }
1417 1710 : else if ( eOp == ocClose )
1418 : {
1419 0 : SetError( errParameterExpected );
1420 : }
1421 1710 : else if ( eOp == ocSep )
1422 : { // Subsequent ocSep
1423 0 : SetError( errParameterExpected );
1424 0 : if ( bAutoCorrect && !pStack )
1425 : {
1426 0 : aCorrectedSymbol = "";
1427 0 : bCorrected = true;
1428 : }
1429 : }
1430 1710 : else if ( mpToken->IsExternalRef() )
1431 : {
1432 0 : PutCode( mpToken);
1433 0 : eOp = NextToken();
1434 : }
1435 : else
1436 : {
1437 1710 : SetError( errUnknownToken );
1438 1710 : if ( bAutoCorrect && !pStack )
1439 : {
1440 0 : if ( eOp == ocStop )
1441 : { // trailing operator w/o operand
1442 0 : sal_Int32 nLen = aCorrectedFormula.getLength();
1443 0 : if ( nLen )
1444 0 : aCorrectedFormula = aCorrectedFormula.copy( 0, nLen - 1 );
1445 0 : aCorrectedSymbol = "";
1446 0 : bCorrected = true;
1447 : }
1448 : }
1449 : }
1450 56800 : }
1451 : }
1452 :
1453 56800 : void FormulaCompiler::RangeLine()
1454 : {
1455 56800 : Factor();
1456 113600 : while (mpToken->GetOpCode() == ocRange)
1457 : {
1458 0 : FormulaToken** pCode1 = pCode - 1;
1459 0 : FormulaTokenRef p = mpToken;
1460 0 : NextToken();
1461 0 : Factor();
1462 0 : FormulaToken** pCode2 = pCode - 1;
1463 0 : if (!MergeRangeReference( pCode1, pCode2))
1464 0 : PutCode(p);
1465 0 : }
1466 56800 : }
1467 :
1468 56800 : void FormulaCompiler::IntersectionLine()
1469 : {
1470 56800 : RangeLine();
1471 113600 : while (mpToken->GetOpCode() == ocIntersect)
1472 : {
1473 0 : FormulaTokenRef p = mpToken;
1474 0 : NextToken();
1475 0 : RangeLine();
1476 0 : PutCode(p);
1477 0 : }
1478 56800 : }
1479 :
1480 56800 : void FormulaCompiler::UnionLine()
1481 : {
1482 56800 : IntersectionLine();
1483 113600 : while (mpToken->GetOpCode() == ocUnion)
1484 : {
1485 0 : FormulaTokenRef p = mpToken;
1486 0 : NextToken();
1487 0 : IntersectionLine();
1488 0 : PutCode(p);
1489 0 : }
1490 56800 : }
1491 :
1492 56992 : void FormulaCompiler::UnaryLine()
1493 : {
1494 56992 : if( mpToken->GetOpCode() == ocAdd )
1495 0 : GetToken();
1496 68764 : else if (SC_OPCODE_START_UN_OP <= mpToken->GetOpCode() &&
1497 11772 : mpToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
1498 : {
1499 192 : FormulaTokenRef p = mpToken;
1500 192 : NextToken();
1501 192 : UnaryLine();
1502 192 : PutCode( p );
1503 : }
1504 : else
1505 56800 : UnionLine();
1506 56992 : }
1507 :
1508 56800 : void FormulaCompiler::PostOpLine()
1509 : {
1510 56800 : UnaryLine();
1511 113600 : while ( mpToken->GetOpCode() == ocPercentSign )
1512 : { // this operator _follows_ its operand
1513 0 : PutCode( mpToken );
1514 0 : NextToken();
1515 : }
1516 56800 : }
1517 :
1518 56798 : void FormulaCompiler::PowLine()
1519 : {
1520 56798 : PostOpLine();
1521 113598 : while (mpToken->GetOpCode() == ocPow)
1522 : {
1523 2 : FormulaTokenRef p = mpToken;
1524 2 : NextToken();
1525 2 : PostOpLine();
1526 2 : PutCode(p);
1527 2 : }
1528 56798 : }
1529 :
1530 52644 : void FormulaCompiler::MulDivLine()
1531 : {
1532 52644 : PowLine();
1533 109442 : while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv)
1534 : {
1535 4154 : FormulaTokenRef p = mpToken;
1536 4154 : NextToken();
1537 4154 : PowLine();
1538 4154 : PutCode(p);
1539 4154 : }
1540 52644 : }
1541 :
1542 44490 : void FormulaCompiler::AddSubLine()
1543 : {
1544 44490 : MulDivLine();
1545 97134 : while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub)
1546 : {
1547 8154 : FormulaTokenRef p = mpToken;
1548 8154 : NextToken();
1549 8154 : MulDivLine();
1550 8154 : PutCode(p);
1551 8154 : }
1552 44490 : }
1553 :
1554 44474 : void FormulaCompiler::ConcatLine()
1555 : {
1556 44474 : AddSubLine();
1557 88964 : while (mpToken->GetOpCode() == ocAmpersand)
1558 : {
1559 16 : FormulaTokenRef p = mpToken;
1560 16 : NextToken();
1561 16 : AddSubLine();
1562 16 : PutCode(p);
1563 16 : }
1564 44474 : }
1565 :
1566 43800 : void FormulaCompiler::CompareLine()
1567 : {
1568 43800 : ConcatLine();
1569 88274 : while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual)
1570 : {
1571 674 : FormulaTokenRef p = mpToken;
1572 674 : NextToken();
1573 674 : ConcatLine();
1574 674 : PutCode(p);
1575 674 : }
1576 43800 : }
1577 :
1578 43800 : void FormulaCompiler::NotLine()
1579 : {
1580 43800 : CompareLine();
1581 87600 : while (mpToken->GetOpCode() == ocNot)
1582 : {
1583 0 : FormulaTokenRef p = mpToken;
1584 0 : NextToken();
1585 0 : CompareLine();
1586 0 : PutCode(p);
1587 0 : }
1588 43800 : }
1589 :
1590 43800 : OpCode FormulaCompiler::Expression()
1591 : {
1592 : static const short nRecursionMax = 42;
1593 43800 : FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
1594 43800 : if ( nRecursion > nRecursionMax )
1595 : {
1596 0 : SetError( errStackOverflow );
1597 0 : return ocStop; //! generate token instead?
1598 : }
1599 43800 : NotLine();
1600 87600 : while (mpToken->GetOpCode() == ocAnd || mpToken->GetOpCode() == ocOr)
1601 : {
1602 0 : FormulaTokenRef p = mpToken;
1603 0 : mpToken->SetByte( 2 ); // 2 parameters!
1604 0 : NextToken();
1605 0 : NotLine();
1606 0 : PutCode(p);
1607 0 : }
1608 43800 : return mpToken->GetOpCode();
1609 : }
1610 :
1611 :
1612 0 : void FormulaCompiler::SetError( sal_uInt16 /*nError*/ )
1613 : {
1614 0 : }
1615 :
1616 0 : FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/,
1617 : bool /*bReuseDoubleRef*/ )
1618 : {
1619 0 : return FormulaTokenRef();
1620 : }
1621 :
1622 0 : bool FormulaCompiler::MergeRangeReference( FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
1623 : {
1624 : FormulaToken *p1, *p2;
1625 0 : if (pc < 2 || !pCode1 || !pCode2 ||
1626 0 : (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
1627 0 : ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
1628 0 : return false;
1629 :
1630 0 : FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
1631 0 : if (!p)
1632 0 : return false;
1633 :
1634 0 : p->IncRef();
1635 0 : p1->DecRef();
1636 0 : p2->DecRef();
1637 0 : *pCode1 = p.get();
1638 0 : --pCode, --pc;
1639 0 : pArr->nRefs--;
1640 :
1641 0 : return true;
1642 : }
1643 :
1644 16840 : bool FormulaCompiler::CompileTokenArray()
1645 : {
1646 16840 : glSubTotal = false;
1647 16840 : bCorrected = false;
1648 16840 : if (!pArr->GetCodeError() || !mbStopOnError)
1649 : {
1650 16840 : if ( bAutoCorrect )
1651 : {
1652 0 : aCorrectedFormula = "";
1653 0 : aCorrectedSymbol = "";
1654 : }
1655 16840 : pArr->nRefs = 0; // count from start
1656 16840 : pArr->DelRPN();
1657 16840 : pStack = NULL;
1658 : FormulaToken* pData[ FORMULA_MAXTOKENS ];
1659 16840 : pCode = pData;
1660 16840 : bool bWasForced = pArr->IsRecalcModeForced();
1661 16840 : if ( bWasForced )
1662 : {
1663 0 : if ( bAutoCorrect )
1664 0 : aCorrectedFormula = "=";
1665 : }
1666 16840 : pArr->ClearRecalcMode();
1667 16840 : pArr->Reset();
1668 16840 : eLastOp = ocOpen;
1669 16840 : pc = 0;
1670 16840 : NextToken();
1671 16840 : OpCode eOp = Expression();
1672 : // Some trailing garbage that doesn't form an expression?
1673 16840 : if (eOp != ocStop)
1674 1712 : SetError( errOperatorExpected);
1675 :
1676 16840 : sal_uInt16 nErrorBeforePop = pArr->GetCodeError();
1677 :
1678 33680 : while( pStack )
1679 0 : PopTokenArray();
1680 16840 : if( pc )
1681 : {
1682 15130 : pArr->pRPN = new FormulaToken*[ pc ];
1683 15130 : pArr->nRPN = pc;
1684 15130 : memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
1685 : }
1686 :
1687 : // once an error, always an error
1688 16840 : if( !pArr->GetCodeError() && nErrorBeforePop )
1689 0 : pArr->SetCodeError( nErrorBeforePop);
1690 :
1691 16840 : if (pArr->GetCodeError() && mbStopOnError)
1692 : {
1693 1712 : pArr->DelRPN();
1694 1712 : pArr->SetHyperLink( false);
1695 : }
1696 :
1697 16840 : if ( bWasForced )
1698 0 : pArr->SetRecalcModeForced();
1699 : }
1700 16840 : if( nNumFmt == NUMBERFORMAT_UNDEFINED )
1701 8456 : nNumFmt = NUMBERFORMAT_NUMBER;
1702 16840 : return glSubTotal;
1703 : }
1704 :
1705 802 : void FormulaCompiler::PopTokenArray()
1706 : {
1707 802 : if( pStack )
1708 : {
1709 802 : FormulaArrayStack* p = pStack;
1710 802 : pStack = p->pNext;
1711 802 : p->pArr->nRefs = sal::static_int_cast<short>( p->pArr->nRefs + pArr->nRefs );
1712 : // obtain special RecalcMode from SharedFormula
1713 802 : if ( pArr->IsRecalcModeAlways() )
1714 0 : p->pArr->SetExclusiveRecalcModeAlways();
1715 802 : else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
1716 0 : p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
1717 802 : p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
1718 802 : if( p->bTemp )
1719 802 : delete pArr;
1720 802 : pArr = p->pArr;
1721 802 : delete p;
1722 : }
1723 802 : }
1724 :
1725 288 : void FormulaCompiler::CreateStringFromTokenArray( OUString& rFormula )
1726 : {
1727 288 : OUStringBuffer aBuffer( pArr->GetLen() * 5 );
1728 288 : CreateStringFromTokenArray( aBuffer );
1729 288 : rFormula = aBuffer.makeStringAndClear();
1730 288 : }
1731 :
1732 3980 : void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer )
1733 : {
1734 3980 : rBuffer.setLength(0);
1735 3980 : if( !pArr->GetLen() )
1736 3980 : return;
1737 :
1738 3980 : FormulaTokenArray* pSaveArr = pArr;
1739 3980 : bool bODFF = FormulaGrammar::isODFF( meGrammar);
1740 3980 : if (bODFF || FormulaGrammar::isPODF( meGrammar) )
1741 : {
1742 : // Scan token array for missing args and re-write if present.
1743 1564 : MissingConvention aConv( bODFF);
1744 1564 : if (pArr->NeedsPofRewrite( aConv))
1745 12 : pArr = pArr->RewriteMissingToPof( aConv);
1746 : }
1747 :
1748 : // At least one character per token, plus some are references, some are
1749 : // function names, some are numbers, ...
1750 3980 : rBuffer.ensureCapacity( pArr->GetLen() * 5 );
1751 :
1752 3980 : if ( pArr->IsRecalcModeForced() )
1753 0 : rBuffer.append( '=');
1754 3980 : FormulaToken* t = pArr->First();
1755 31976 : while( t )
1756 24016 : t = CreateStringFromToken( rBuffer, t, true );
1757 :
1758 3980 : if (pSaveArr != pArr)
1759 : {
1760 12 : delete pArr;
1761 12 : pArr = pSaveArr;
1762 : }
1763 : }
1764 :
1765 50632 : FormulaToken* FormulaCompiler::CreateStringFromToken( OUString& rFormula, FormulaToken* pTokenP,bool bAllowArrAdvance )
1766 : {
1767 50632 : OUStringBuffer aBuffer;
1768 50632 : FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
1769 50632 : rFormula += aBuffer.makeStringAndClear();
1770 50632 : return p;
1771 : }
1772 :
1773 74648 : FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuffer, FormulaToken* pTokenP, bool bAllowArrAdvance )
1774 : {
1775 74648 : bool bNext = true;
1776 74648 : bool bSpaces = false;
1777 74648 : FormulaToken* t = pTokenP;
1778 74648 : OpCode eOp = t->GetOpCode();
1779 74648 : if( eOp >= ocAnd && eOp <= ocOr )
1780 : {
1781 : // AND, OR infix?
1782 62 : if ( bAllowArrAdvance )
1783 62 : t = pArr->Next();
1784 : else
1785 0 : t = pArr->PeekNext();
1786 62 : bNext = false;
1787 62 : bSpaces = ( !t || t->GetOpCode() != ocOpen );
1788 : }
1789 74648 : if( bSpaces )
1790 0 : rBuffer.append( ' ');
1791 :
1792 74648 : if( eOp == ocSpaces )
1793 : {
1794 538 : bool bIntersectionOp = mxSymbols->isODFF();
1795 538 : if (bIntersectionOp)
1796 : {
1797 184 : const FormulaToken* p = pArr->PeekPrevNoSpaces();
1798 184 : bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1799 184 : if (bIntersectionOp)
1800 : {
1801 0 : p = pArr->PeekNextNoSpaces();
1802 0 : bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1803 : }
1804 : }
1805 538 : if (bIntersectionOp)
1806 0 : rBuffer.appendAscii( "!!");
1807 : else
1808 : {
1809 : // most times it's just one blank
1810 538 : sal_uInt8 n = t->GetByte();
1811 1076 : for ( sal_uInt8 j=0; j<n; ++j )
1812 : {
1813 538 : rBuffer.append( ' ');
1814 : }
1815 : }
1816 : }
1817 74110 : else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1818 0 : rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
1819 74110 : else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount()) // Keyword:
1820 74110 : rBuffer.append( mxSymbols->getSymbol( eOp));
1821 : else
1822 : {
1823 : SAL_WARN( "formula.core","unknown OpCode");
1824 0 : rBuffer.append( GetNativeSymbol( ocErrName ));
1825 : }
1826 74648 : if( bNext )
1827 : {
1828 74586 : if (t->IsExternalRef())
1829 : {
1830 62 : CreateStringFromExternal( rBuffer, pTokenP);
1831 : }
1832 : else
1833 : {
1834 74524 : switch( t->GetType() )
1835 : {
1836 : case svDouble:
1837 3386 : AppendDouble( rBuffer, t->GetDouble() );
1838 3386 : break;
1839 :
1840 : case svString:
1841 612 : if( eOp == ocBad || eOp == ocStringXML )
1842 124 : rBuffer.append( t->GetString().getString());
1843 : else
1844 488 : AppendString( rBuffer, t->GetString().getString() );
1845 612 : break;
1846 : case svSingleRef:
1847 29044 : CreateStringFromSingleRef( rBuffer, t);
1848 29044 : break;
1849 : case svDoubleRef:
1850 26172 : CreateStringFromDoubleRef( rBuffer, t);
1851 26172 : break;
1852 : case svMatrix:
1853 4 : CreateStringFromMatrix( rBuffer, t );
1854 4 : break;
1855 :
1856 : case svIndex:
1857 62 : CreateStringFromIndex( rBuffer, t );
1858 62 : break;
1859 : case svExternal:
1860 : {
1861 : // mapped or translated name of AddIns
1862 154 : OUString aAddIn( t->GetExternal() );
1863 154 : bool bMapped = mxSymbols->isPODF(); // ODF 1.1 directly uses programmatical name
1864 154 : if (!bMapped && mxSymbols->hasExternals())
1865 : {
1866 152 : ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
1867 152 : if (iLook != mxSymbols->getReverseExternalHashMap()->end())
1868 : {
1869 152 : aAddIn = (*iLook).second;
1870 152 : bMapped = true;
1871 : }
1872 : }
1873 154 : if (!bMapped && !mxSymbols->isEnglish())
1874 2 : LocalizeString( aAddIn );
1875 154 : rBuffer.append( aAddIn);
1876 : }
1877 154 : break;
1878 : case svError:
1879 0 : AppendErrorConstant( rBuffer, t->GetError());
1880 0 : break;
1881 : case svByte:
1882 : case svJump:
1883 : case svFAP:
1884 : case svMissing:
1885 : case svSep:
1886 15090 : break; // Opcodes
1887 : default:
1888 : SAL_WARN("formula.core", "FormulaCompiler::GetStringFromToken: unknown token type " << t->GetType());
1889 : } // of switch
1890 : }
1891 : }
1892 74648 : if( bSpaces )
1893 0 : rBuffer.append( ' ');
1894 74648 : if ( bAllowArrAdvance )
1895 : {
1896 24016 : if( bNext )
1897 23954 : t = pArr->Next();
1898 24016 : return t;
1899 : }
1900 50632 : return pTokenP;
1901 : }
1902 :
1903 :
1904 3398 : void FormulaCompiler::AppendDouble( OUStringBuffer& rBuffer, double fVal ) const
1905 : {
1906 3398 : if ( mxSymbols->isEnglish() )
1907 : {
1908 : ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1909 : rtl_math_StringFormat_Automatic,
1910 3326 : rtl_math_DecimalPlaces_Max, '.', true );
1911 : }
1912 : else
1913 : {
1914 72 : SvtSysLocale aSysLocale;
1915 : ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1916 : rtl_math_StringFormat_Automatic,
1917 : rtl_math_DecimalPlaces_Max,
1918 72 : aSysLocale.GetLocaleDataPtr()->getNumDecimalSep()[0],
1919 72 : true );
1920 : }
1921 3398 : }
1922 :
1923 0 : void FormulaCompiler::AppendBoolean( OUStringBuffer& rBuffer, bool bVal ) const
1924 : {
1925 0 : rBuffer.append( mxSymbols->getSymbol( static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
1926 0 : }
1927 :
1928 488 : void FormulaCompiler::AppendString( OUStringBuffer& rBuffer, const OUString & rStr ) const
1929 : {
1930 488 : rBuffer.append( '"');
1931 488 : if ( lcl_UnicodeStrChr( rStr.getStr(), '"' ) == NULL )
1932 488 : rBuffer.append( rStr );
1933 : else
1934 : {
1935 0 : OUString aStr = rStr.replaceAll( "\"", "\"\"" );
1936 0 : rBuffer.append(aStr);
1937 : }
1938 488 : rBuffer.append( '"');
1939 488 : }
1940 :
1941 732 : void FormulaCompiler::UpdateSeparatorsNative(
1942 : const OUString& rSep, const OUString& rArrayColSep, const OUString& rArrayRowSep )
1943 : {
1944 732 : NonConstOpCodeMapPtr xSymbolsNative;
1945 732 : lcl_fillNativeSymbols( xSymbolsNative);
1946 732 : xSymbolsNative->putOpCode( rSep, ocSep);
1947 732 : xSymbolsNative->putOpCode( rArrayColSep, ocArrayColSep);
1948 732 : xSymbolsNative->putOpCode( rArrayRowSep, ocArrayRowSep);
1949 732 : }
1950 :
1951 70 : void FormulaCompiler::ResetNativeSymbols()
1952 : {
1953 70 : NonConstOpCodeMapPtr xSymbolsNative;
1954 70 : lcl_fillNativeSymbols( xSymbolsNative, true);
1955 70 : lcl_fillNativeSymbols( xSymbolsNative);
1956 70 : }
1957 :
1958 0 : void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr& xMap )
1959 : {
1960 0 : NonConstOpCodeMapPtr xSymbolsNative;
1961 0 : lcl_fillNativeSymbols( xSymbolsNative);
1962 0 : xSymbolsNative->copyFrom( *xMap, true);
1963 0 : }
1964 :
1965 :
1966 124200 : OpCode FormulaCompiler::NextToken()
1967 : {
1968 124200 : if( !GetToken() )
1969 15124 : return ocStop;
1970 109076 : OpCode eOp = mpToken->GetOpCode();
1971 : // There must be an operator before a push
1972 149894 : if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
1973 60914 : !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
1974 7090 : (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
1975 0 : SetError( errOperatorExpected);
1976 : // Operator and Plus => operator
1977 115596 : if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
1978 6520 : (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
1979 0 : eOp = NextToken();
1980 : else
1981 : {
1982 : // Before an operator there must not be another operator, with the
1983 : // exception of AND and OR.
1984 109076 : if ( eOp != ocAnd && eOp != ocOr &&
1985 24772 : (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP )
1986 26000 : && (eLastOp == ocOpen || eLastOp == ocSep ||
1987 13000 : (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
1988 : {
1989 0 : SetError( errVariableExpected);
1990 0 : if ( bAutoCorrect && !pStack )
1991 : {
1992 0 : if ( eOp == eLastOp || eLastOp == ocOpen )
1993 : { // throw away duplicated operator
1994 0 : aCorrectedSymbol = "";
1995 0 : bCorrected = true;
1996 : }
1997 : else
1998 : {
1999 0 : sal_Int32 nPos = aCorrectedFormula.getLength();
2000 0 : if ( nPos )
2001 : {
2002 0 : nPos--;
2003 0 : sal_Unicode c = aCorrectedFormula[ nPos ];
2004 0 : switch ( eOp )
2005 : { // swap operators
2006 : case ocGreater:
2007 0 : if ( c == mxSymbols->getSymbolChar( ocEqual) )
2008 : { // >= instead of =>
2009 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2010 0 : OUString( mxSymbols->getSymbolChar(ocGreater) ) );
2011 0 : aCorrectedSymbol = OUString(c);
2012 0 : bCorrected = true;
2013 : }
2014 0 : break;
2015 : case ocLess:
2016 0 : if ( c == mxSymbols->getSymbolChar( ocEqual) )
2017 : { // <= instead of =<
2018 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2019 0 : OUString( mxSymbols->getSymbolChar(ocLess) ) );
2020 0 : aCorrectedSymbol = OUString(c);
2021 0 : bCorrected = true;
2022 : }
2023 0 : else if ( c == mxSymbols->getSymbolChar( ocGreater) )
2024 : { // <> instead of ><
2025 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2026 0 : OUString( mxSymbols->getSymbolChar(ocLess) ) );
2027 0 : aCorrectedSymbol = OUString(c);
2028 0 : bCorrected = true;
2029 : }
2030 0 : break;
2031 : case ocMul:
2032 0 : if ( c == mxSymbols->getSymbolChar( ocSub) )
2033 : { // *- instead of -*
2034 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2035 0 : OUString( mxSymbols->getSymbolChar(ocMul) ) );
2036 0 : aCorrectedSymbol = OUString(c);
2037 0 : bCorrected = true;
2038 : }
2039 0 : break;
2040 : case ocDiv:
2041 0 : if ( c == mxSymbols->getSymbolChar( ocSub) )
2042 : { // /- instead of -/
2043 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2044 0 : OUString( mxSymbols->getSymbolChar(ocDiv) ) );
2045 0 : aCorrectedSymbol = OUString(c);
2046 0 : bCorrected = true;
2047 : }
2048 0 : break;
2049 : default:
2050 : ; // nothing
2051 : }
2052 : }
2053 : }
2054 : }
2055 : }
2056 109076 : eLastOp = eOp;
2057 : }
2058 109076 : return eOp;
2059 : }
2060 66340 : void FormulaCompiler::PutCode( FormulaTokenRef& p )
2061 : {
2062 66340 : if( pc >= FORMULA_MAXTOKENS - 1 )
2063 : {
2064 0 : if ( pc == FORMULA_MAXTOKENS - 1 )
2065 : {
2066 0 : p = new FormulaByteToken( ocStop );
2067 0 : p->IncRef();
2068 0 : *pCode++ = p.get();
2069 0 : ++pc;
2070 : }
2071 0 : SetError( errCodeOverflow);
2072 0 : return;
2073 : }
2074 66340 : if (pArr->GetCodeError() && mbJumpCommandReorder)
2075 0 : return;
2076 66340 : ForceArrayOperator( p, pCurrentFactorToken);
2077 66340 : p->IncRef();
2078 66340 : *pCode++ = p.get();
2079 66340 : pc++;
2080 : }
2081 :
2082 :
2083 0 : bool FormulaCompiler::HandleExternalReference( const FormulaToken& /*_aToken*/)
2084 : {
2085 0 : return true;
2086 : }
2087 :
2088 0 : bool FormulaCompiler::HandleRange()
2089 : {
2090 0 : return true;
2091 : }
2092 :
2093 0 : bool FormulaCompiler::HandleSingleRef()
2094 : {
2095 0 : return true;
2096 : }
2097 :
2098 0 : bool FormulaCompiler::HandleDbData()
2099 : {
2100 0 : return true;
2101 : }
2102 :
2103 0 : void FormulaCompiler::CreateStringFromSingleRef( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2104 : {
2105 0 : }
2106 :
2107 0 : void FormulaCompiler::CreateStringFromDoubleRef( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2108 : {
2109 0 : }
2110 :
2111 0 : void FormulaCompiler::CreateStringFromIndex( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2112 : {
2113 0 : }
2114 :
2115 0 : void FormulaCompiler::CreateStringFromMatrix( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2116 : {
2117 0 : }
2118 :
2119 0 : void FormulaCompiler::CreateStringFromExternal( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2120 : {
2121 0 : }
2122 :
2123 0 : void FormulaCompiler::LocalizeString( OUString& /*rName*/ ) const
2124 : {
2125 0 : }
2126 :
2127 802 : void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
2128 : {
2129 802 : if ( bAutoCorrect && !pStack )
2130 : { // don't merge stacked subroutine code into entered formula
2131 0 : aCorrectedFormula += aCorrectedSymbol;
2132 0 : aCorrectedSymbol = "";
2133 : }
2134 802 : FormulaArrayStack* p = new FormulaArrayStack;
2135 802 : p->pNext = pStack;
2136 802 : p->pArr = pArr;
2137 802 : p->bTemp = bTemp;
2138 802 : pStack = p;
2139 802 : pArr = pa;
2140 802 : }
2141 :
2142 : } // namespace formula
2143 :
2144 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|