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 62481 : FormulaCompilerRecursionGuard( short& rRec )
52 62481 : : rRecursion( rRec ) { ++rRecursion; }
53 62481 : ~FormulaCompilerRecursionGuard() { --rRecursion; }
54 : };
55 :
56 2823 : short lcl_GetRetFormat( OpCode eOpCode )
57 : {
58 2823 : 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 138 : return NUMBERFORMAT_LOGICAL;
86 : case ocGetActDate:
87 : case ocGetDate:
88 : case ocEasterSunday :
89 0 : return NUMBERFORMAT_DATE;
90 : case ocGetActTime:
91 3 : 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 36 : 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 16 : return NUMBERFORMAT_PERCENT;
116 : default:
117 2630 : return NUMBERFORMAT_NUMBER;
118 : }
119 : }
120 :
121 22736 : inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
122 : const OUString* pTable, sal_uInt16 nOpCode )
123 : {
124 22736 : sheet::FormulaOpCodeMapEntry aEntry;
125 22736 : aEntry.Token.OpCode = nOpCode;
126 22736 : aEntry.Name = pTable[nOpCode];
127 22736 : rVec.push_back( aEntry);
128 22736 : }
129 :
130 116 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
131 : const OUString* pTable, sal_uInt16 nOpCodeBeg, sal_uInt16 nOpCodeEnd )
132 : {
133 5394 : for (sal_uInt16 nOpCode = nOpCodeBeg; nOpCode < nOpCodeEnd; ++nOpCode)
134 5278 : lclPushOpCodeMapEntry( rVec, pTable, nOpCode );
135 116 : }
136 :
137 174 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
138 : const OUString* pTable, const sal_uInt16* pnOpCodes, size_t nCount )
139 : {
140 1044 : for (const sal_uInt16* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes)
141 870 : lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes );
142 174 : }
143 :
144 428 : 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 428 : OpCodeList::OpCodeList( sal_uInt16 nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap,
160 : FormulaCompiler::SeparatorType eSepType ) :
161 428 : Resource( ResId( nRID, *ResourceManager::getResManager()))
162 428 : , meSepType( eSepType)
163 : {
164 428 : if (meSepType == FormulaCompiler::RESOURCE_BASE)
165 : {
166 14601 : for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
167 : {
168 14570 : putDefaultOpCode( xMap, i);
169 : }
170 : }
171 : else
172 : {
173 186987 : for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
174 : {
175 186590 : OUString aOpStr;
176 186590 : if ( getOpCodeString( aOpStr, i) )
177 1191 : xMap->putOpCode( aOpStr, OpCode(i));
178 : else
179 185399 : putDefaultOpCode( xMap, i);
180 186590 : }
181 : }
182 :
183 428 : FreeResource();
184 428 : }
185 :
186 186590 : bool OpCodeList::getOpCodeString( OUString& rStr, sal_uInt16 nOp )
187 : {
188 186590 : switch (nOp)
189 : {
190 : case SC_OPCODE_SEP:
191 : {
192 397 : if (meSepType == FormulaCompiler::COMMA_BASE)
193 : {
194 0 : rStr = ",";
195 0 : return true;
196 : }
197 397 : else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
198 : {
199 397 : rStr = ";";
200 397 : return true;
201 : }
202 : }
203 0 : break;
204 : case SC_OPCODE_ARRAY_COL_SEP:
205 : {
206 397 : if (meSepType == FormulaCompiler::COMMA_BASE)
207 : {
208 0 : rStr = ",";
209 0 : return true;
210 : }
211 397 : else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
212 : {
213 397 : rStr = ";";
214 397 : return true;
215 : }
216 : }
217 0 : break;
218 : case SC_OPCODE_ARRAY_ROW_SEP:
219 : {
220 397 : if (meSepType == FormulaCompiler::COMMA_BASE)
221 : {
222 0 : rStr = ";";
223 0 : return true;
224 : }
225 397 : else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
226 : {
227 397 : rStr = "|";
228 397 : return true;
229 : }
230 : }
231 0 : break;
232 : }
233 :
234 185399 : return false;
235 : }
236 :
237 199969 : void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp )
238 : {
239 199969 : ResId aRes( nOp, *ResourceManager::getResManager());
240 199969 : aRes.SetRT( RSC_STRING);
241 199969 : if (IsAvailableRes( aRes))
242 168297 : xMap->putOpCode( aRes.toString(), OpCode( nOp));
243 199969 : }
244 :
245 : // static
246 60 : const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr, sal_Unicode c )
247 : {
248 60 : if ( !pStr )
249 0 : return NULL;
250 348 : while ( *pStr )
251 : {
252 228 : if ( *pStr == c )
253 0 : return pStr;
254 228 : pStr++;
255 : }
256 60 : return NULL;
257 : }
258 :
259 136 : struct OpCodeMapData
260 : {
261 : FormulaCompiler::NonConstOpCodeMapPtr mxSymbolMap;
262 : osl::Mutex maMtx;
263 : };
264 :
265 :
266 : } // namespace
267 :
268 :
269 10707 : 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 10707 : 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 10707 : if (bOk)
278 : {
279 10707 : 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 10707 : }
285 :
286 1877 : void FormulaCompiler::OpCodeMap::putExternalSoftly( const OUString & rSymbol, const OUString & rAddIn )
287 : {
288 1877 : bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
289 1877 : if (bOk)
290 24 : mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn));
291 1877 : }
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 348 : 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 348 : ::std::vector< FormulaOpCodeMapEntry > aVec;
340 :
341 348 : 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 58 : const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
365 : // Preallocate vector elements.
366 58 : if (aVec.size() < nCount)
367 : {
368 58 : FormulaOpCodeMapEntry aEntry;
369 58 : aEntry.Token.OpCode = getOpCodeUnknown();
370 58 : aVec.resize( nCount, aEntry);
371 : } // if (aVec.size() < nCount)
372 :
373 58 : FormulaOpCodeMapEntry aEntry;
374 812 : for (size_t i=0; i < nCount; ++i)
375 : {
376 754 : size_t nIndex = static_cast< size_t >( aMap[i].nOff );
377 754 : 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 754 : aEntry.Token.OpCode = aMap[i].eOp;
387 754 : aVec[nIndex] = aEntry;
388 58 : }
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 290 : 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 58 : lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
405 : }
406 290 : 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 58 : lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
415 : }
416 290 : 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 58 : lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
421 : // "+" can be used as unary operator too, push only if binary group is not set
422 58 : if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
423 58 : lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
424 : // regular unary operators
425 232 : for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
426 : {
427 174 : 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 116 : break; // nothing,
434 : default:
435 58 : lclPushOpCodeMapEntry( aVec, mpTable, nOp );
436 : }
437 : }
438 : }
439 290 : if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
440 : {
441 1044 : for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
442 : {
443 986 : 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 116 : break; // nothing,
450 : default:
451 870 : lclPushOpCodeMapEntry( aVec, mpTable, nOp );
452 : }
453 : }
454 : }
455 290 : 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 58 : ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
461 : lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_1_PAR,
462 58 : ::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 58 : lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
475 : // functions with 2 or more parameters.
476 15660 : for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
477 : {
478 15602 : switch (nOp)
479 : {
480 : // NO_NAME is in SPECIAL.
481 : case SC_OPCODE_NO_NAME :
482 58 : break; // nothing,
483 : default:
484 15544 : lclPushOpCodeMapEntry( aVec, mpTable, nOp );
485 : }
486 : }
487 : // If AddIn functions are present in this mapping, use them, and only those.
488 58 : if (hasExternals())
489 : {
490 6380 : for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
491 : {
492 6322 : FormulaOpCodeMapEntry aEntry;
493 6322 : aEntry.Name = (*it).first;
494 6322 : aEntry.Token.Data <<= OUString( (*it).second);
495 6322 : aEntry.Token.OpCode = ocExternal;
496 6322 : aVec.push_back( aEntry);
497 6322 : }
498 : }
499 : else
500 : {
501 0 : rCompiler.fillAddInToken( aVec, isEnglish());
502 : }
503 : }
504 : }
505 348 : const FormulaOpCodeMapEntry* pRet = aVec.empty() ? 0 : &aVec[0];
506 348 : return uno::Sequence< FormulaOpCodeMapEntry >( pRet, aVec.size());
507 : }
508 :
509 :
510 193705 : 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 193705 : 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 193705 : mpTable[eOp] = rStr;
522 193705 : mpHashMap->insert( OpCodeHashMap::value_type( rStr, eOp));
523 : }
524 193705 : }
525 :
526 : // class FormulaCompiler
527 :
528 6608 : 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 : bCompileForFAP( false ),
541 : bIgnoreErrors( false ),
542 6608 : glSubTotal( false )
543 :
544 : {
545 6608 : }
546 :
547 29224 : FormulaCompiler::FormulaCompiler()
548 : :
549 : pArr( NULL ),
550 : pStack( NULL ),
551 : nRecursion(0),
552 : nNumFmt( NUMBERFORMAT_UNDEFINED ),
553 : meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
554 : bAutoCorrect( false ),
555 : bCorrected( false ),
556 : bCompileForFAP( false ),
557 29224 : bIgnoreErrors( false )
558 :
559 : {
560 29224 : }
561 :
562 35833 : FormulaCompiler::~FormulaCompiler()
563 : {
564 35833 : }
565 :
566 36309 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
567 : {
568 36309 : FormulaCompiler::OpCodeMapPtr xMap;
569 : using namespace sheet;
570 36309 : switch (nLanguage)
571 : {
572 : case FormulaLanguage::ODFF :
573 2514 : if (!mxSymbolsODFF)
574 2224 : InitSymbolsODFF();
575 2514 : xMap = mxSymbolsODFF;
576 2514 : break;
577 : case FormulaLanguage::ODF_11 :
578 346 : if (!mxSymbolsPODF)
579 346 : InitSymbolsPODF();
580 346 : xMap = mxSymbolsPODF;
581 346 : break;
582 : case FormulaLanguage::ENGLISH :
583 139 : if (!mxSymbolsEnglish)
584 139 : InitSymbolsEnglish();
585 139 : xMap = mxSymbolsEnglish;
586 139 : break;
587 : case FormulaLanguage::NATIVE :
588 32898 : if (!mxSymbolsNative)
589 32830 : InitSymbolsNative();
590 32898 : xMap = mxSymbolsNative;
591 32898 : break;
592 : case FormulaLanguage::XL_ENGLISH:
593 229 : if (!mxSymbolsEnglishXL)
594 229 : InitSymbolsEnglishXL();
595 229 : xMap = mxSymbolsEnglishXL;
596 229 : break;
597 : case FormulaLanguage::OOXML:
598 183 : if (!mxSymbolsOOXML)
599 183 : InitSymbolsOOXML();
600 183 : xMap = mxSymbolsOOXML;
601 183 : break;
602 : default:
603 : ; // nothing, NULL map returned
604 : }
605 36309 : return xMap;
606 : }
607 :
608 0 : OUString FormulaCompiler::FindAddInFunction( const OUString& /*rUpperName*/, bool /*bLocalFirst*/ ) const
609 : {
610 0 : return OUString();
611 : }
612 :
613 58 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
614 : const uno::Sequence<
615 : const sheet::FormulaOpCodeMapEntry > & rMapping,
616 : bool bEnglish )
617 : {
618 : using sheet::FormulaOpCodeMapEntry;
619 : // Filter / API maps are never Core
620 : NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, false,
621 : FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(
622 58 : FormulaGrammar::GRAM_EXTERNAL, bEnglish), FormulaGrammar::CONV_UNSPECIFIED)));
623 58 : FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
624 58 : FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
625 29092 : for ( ; pArr2 < pStop; ++pArr2)
626 : {
627 29034 : OpCode eOp = OpCode(pArr2->Token.OpCode);
628 29034 : if (eOp != ocExternal)
629 22360 : xMap->putOpCode( pArr2->Name, eOp);
630 : else
631 : {
632 6674 : OUString aExternalName;
633 6674 : if (pArr2->Token.Data >>= aExternalName)
634 6674 : xMap->putExternal( pArr2->Name, aExternalName);
635 : else
636 : {
637 : SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
638 6674 : }
639 : }
640 : }
641 58 : return xMap;
642 : }
643 :
644 64704 : void lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& xMap, bool bDestroy = false )
645 : {
646 64704 : static OpCodeMapData aSymbolMap;
647 64704 : osl::MutexGuard aGuard(&aSymbolMap.maMtx);
648 :
649 64704 : if ( bDestroy )
650 : {
651 390 : aSymbolMap.mxSymbolMap.reset();
652 : }
653 64314 : else if (!aSymbolMap.mxSymbolMap)
654 : {
655 : // Core
656 : aSymbolMap.mxSymbolMap.reset(
657 : new FormulaCompiler::OpCodeMap(
658 391 : SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
659 391 : OModuleClient aModuleClient;
660 391 : OpCodeList aOpCodeListNative(RID_STRLIST_FUNCTION_NAMES, aSymbolMap.mxSymbolMap);
661 : // No AddInMap for native core mapping.
662 : }
663 :
664 64704 : xMap = aSymbolMap.mxSymbolMap;
665 64704 : }
666 :
667 30704 : const OUString& FormulaCompiler::GetNativeSymbol( OpCode eOp )
668 : {
669 30704 : NonConstOpCodeMapPtr xSymbolsNative;
670 30704 : lcl_fillNativeSymbols( xSymbolsNative);
671 30704 : return xSymbolsNative->getSymbol( eOp );
672 : }
673 :
674 28493 : sal_Unicode FormulaCompiler::GetNativeSymbolChar( OpCode eOp )
675 : {
676 28493 : return GetNativeSymbol(eOp)[0];
677 : }
678 :
679 32830 : void FormulaCompiler::InitSymbolsNative() const
680 : {
681 32830 : lcl_fillNativeSymbols( mxSymbolsNative);
682 32830 : }
683 :
684 139 : void FormulaCompiler::InitSymbolsEnglish() const
685 : {
686 139 : static OpCodeMapData aMap;
687 139 : osl::MutexGuard aGuard(&aMap.maMtx);
688 139 : if (!aMap.mxSymbolMap)
689 3 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
690 139 : mxSymbolsEnglish = aMap.mxSymbolMap;
691 139 : }
692 :
693 346 : void FormulaCompiler::InitSymbolsPODF() const
694 : {
695 346 : static OpCodeMapData aMap;
696 346 : osl::MutexGuard aGuard(&aMap.maMtx);
697 346 : if (!aMap.mxSymbolMap)
698 7 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_PODF, aMap.mxSymbolMap, RESOURCE_BASE);
699 346 : mxSymbolsPODF = aMap.mxSymbolMap;
700 346 : }
701 :
702 2224 : void FormulaCompiler::InitSymbolsODFF() const
703 : {
704 2224 : static OpCodeMapData aMap;
705 2224 : osl::MutexGuard aGuard(&aMap.maMtx);
706 2224 : if (!aMap.mxSymbolMap)
707 21 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF, FormulaGrammar::GRAM_ODFF, aMap.mxSymbolMap, RESOURCE_BASE);
708 2224 : mxSymbolsODFF = aMap.mxSymbolMap;
709 2224 : }
710 :
711 229 : void FormulaCompiler::InitSymbolsEnglishXL() const
712 : {
713 229 : static OpCodeMapData aMap;
714 229 : osl::MutexGuard aGuard(&aMap.maMtx);
715 229 : if (!aMap.mxSymbolMap)
716 3 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
717 229 : mxSymbolsEnglishXL = aMap.mxSymbolMap;
718 :
719 : // TODO: For now, just replace the separators to the Excel English
720 : // variants. Later, if we want to properly map Excel functions with Calc
721 : // functions, we'll need to do a little more work here.
722 229 : mxSymbolsEnglishXL->putOpCode( OUString(','), ocSep);
723 229 : mxSymbolsEnglishXL->putOpCode( OUString(','), ocArrayColSep);
724 229 : mxSymbolsEnglishXL->putOpCode( OUString(';'), ocArrayRowSep);
725 229 : }
726 :
727 183 : void FormulaCompiler::InitSymbolsOOXML() const
728 : {
729 183 : static OpCodeMapData aMap;
730 183 : osl::MutexGuard aGuard(&aMap.maMtx);
731 183 : if (!aMap.mxSymbolMap)
732 3 : loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML, FormulaGrammar::GRAM_OOXML, aMap.mxSymbolMap, RESOURCE_BASE);
733 183 : mxSymbolsOOXML = aMap.mxSymbolMap;
734 183 : }
735 :
736 :
737 37 : void FormulaCompiler::loadSymbols( sal_uInt16 nSymbols, FormulaGrammar::Grammar eGrammar,
738 : NonConstOpCodeMapPtr& rxMap, SeparatorType eSepType) const
739 : {
740 37 : if ( !rxMap.get() )
741 : {
742 : // not Core
743 37 : rxMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, eGrammar != FormulaGrammar::GRAM_ODFF, eGrammar ));
744 37 : OModuleClient aModuleClient;
745 74 : OpCodeList aOpCodeList( nSymbols, rxMap, eSepType);
746 :
747 37 : fillFromAddInMap( rxMap, eGrammar);
748 : // Fill from collection for AddIns not already present.
749 37 : if ( FormulaGrammar::GRAM_ENGLISH != eGrammar )
750 31 : fillFromAddInCollectionUpperName( rxMap);
751 : else
752 43 : fillFromAddInCollectionEnglishName( rxMap);
753 : }
754 37 : }
755 :
756 0 : void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const
757 : {
758 0 : }
759 :
760 0 : void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const
761 : {
762 0 : }
763 :
764 0 : void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const
765 : {
766 0 : }
767 :
768 0 : OpCode FormulaCompiler::GetEnglishOpCode( const OUString& rName ) const
769 : {
770 0 : FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap( sheet::FormulaLanguage::ENGLISH);
771 :
772 0 : formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) );
773 0 : bool bFound = (iLook != xMap->getHashMap()->end());
774 0 : return bFound ? (*iLook).second : OpCode(ocNone);
775 : }
776 :
777 13550 : bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
778 : {
779 13550 : bool bRet = false;
780 13550 : switch (eOp)
781 : {
782 : // no parameters:
783 : case ocRandom:
784 : case ocGetActDate:
785 : case ocGetActTime:
786 : // one parameter:
787 : case ocFormula:
788 : case ocInfo:
789 : // more than one parameters:
790 : // ocIndirect/ocIndirectXL otherwise would have to do
791 : // StopListening and StartListening on a reference for every
792 : // interpreted value.
793 : case ocIndirect:
794 : case ocIndirectXL:
795 : // ocOffset results in indirect references.
796 : case ocOffset:
797 : // ocDebugVar shows internal value that may change as the internal state changes.
798 : case ocDebugVar:
799 61 : bRet = true;
800 61 : break;
801 : default:
802 13489 : bRet = false;
803 13489 : break;
804 : }
805 13550 : return bRet;
806 : }
807 :
808 : // Remove quotes, escaped quotes are unescaped.
809 19 : bool FormulaCompiler::DeQuote( OUString& rStr )
810 : {
811 19 : sal_Int32 nLen = rStr.getLength();
812 19 : if ( nLen > 1 && rStr[0] == '\'' && rStr[ nLen-1 ] == '\'' )
813 : {
814 0 : rStr = rStr.copy( 1, nLen-2 );
815 0 : rStr = rStr.replaceAll( "\\\'", "\'" );
816 0 : return true;
817 : }
818 19 : return false;
819 : }
820 :
821 0 : void FormulaCompiler::fillAddInToken(
822 : ::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,
823 : bool /*_bIsEnglish*/) const
824 : {
825 0 : }
826 :
827 0 : bool FormulaCompiler::IsMatrixFunction( OpCode eOpCode )
828 : {
829 0 : switch (eOpCode)
830 : {
831 : case ocDde :
832 : case ocGrowth :
833 : case ocTrend :
834 : case ocRKP :
835 : case ocRGP :
836 : case ocFrequency :
837 : case ocMatTrans :
838 : case ocMatMult :
839 : case ocMatInv :
840 : case ocMatrixUnit :
841 : case ocModalValue_Multi :
842 0 : return true;
843 : default:
844 : {
845 : // added to avoid warnings
846 : }
847 : }
848 0 : return false;
849 : }
850 :
851 :
852 972 : FormulaCompiler::OpCodeMap::~OpCodeMap()
853 : {
854 486 : delete mpReverseExternalHashMap;
855 486 : delete mpExternalHashMap;
856 486 : delete [] mpTable;
857 486 : delete mpHashMap;
858 972 : }
859 :
860 0 : void FormulaCompiler::OpCodeMap::putCopyOpCode( const OUString& rSymbol, OpCode eOp )
861 : {
862 : SAL_WARN_IF( !mpTable[eOp].isEmpty() && rSymbol.isEmpty(), "formula.core",
863 : "OpCodeMap::putCopyOpCode: NOT replacing OpCode " << eOp << " '" << mpTable[eOp] << "' with empty name!");
864 0 : if (!mpTable[eOp].isEmpty() && rSymbol.isEmpty())
865 0 : mpHashMap->insert( OpCodeHashMap::value_type( mpTable[eOp], eOp));
866 : else
867 : {
868 0 : mpTable[eOp] = rSymbol;
869 0 : mpHashMap->insert( OpCodeHashMap::value_type( rSymbol, eOp));
870 : }
871 0 : }
872 :
873 0 : void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap& r, bool bOverrideKnownBad )
874 : {
875 0 : delete mpHashMap;
876 0 : mpHashMap = new OpCodeHashMap( mnSymbols);
877 :
878 0 : sal_uInt16 n = r.getSymbolCount();
879 : SAL_WARN_IF( n != mnSymbols, "formula.core",
880 : "OpCodeMap::copyFrom: unequal size, this: " << mnSymbols << " that: " << n);
881 0 : if (n > mnSymbols)
882 0 : n = mnSymbols;
883 :
884 : // OpCode 0 (ocPush) should never be in a map.
885 : SAL_WARN_IF( !mpTable[0].isEmpty() || !r.mpTable[0].isEmpty(), "formula.core",
886 : "OpCodeMap::copyFrom: OpCode 0 assigned, this: '"
887 : << mpTable[0] << "' that: '" << r.mpTable[0] << "'");
888 :
889 : // For bOverrideKnownBad when copying from the English core map (ODF 1.1
890 : // and API) to the native map (UI "use English function names") replace the
891 : // known bad legacy function names with correct ones.
892 0 : if (bOverrideKnownBad && r.mbCore &&
893 0 : FormulaGrammar::extractFormulaLanguage( meGrammar) == sheet::FormulaLanguage::NATIVE &&
894 0 : FormulaGrammar::extractFormulaLanguage( r.meGrammar) == sheet::FormulaLanguage::ENGLISH)
895 : {
896 0 : for (sal_uInt16 i = 1; i < n; ++i)
897 : {
898 0 : OUString aSymbol;
899 0 : OpCode eOp = OpCode(i);
900 0 : switch (eOp)
901 : {
902 : case ocZGZ:
903 0 : aSymbol = "RRI";
904 0 : break;
905 : case ocTableOp:
906 0 : aSymbol = "MULTIPLE.OPERATIONS";
907 0 : break;
908 : default:
909 0 : aSymbol = r.mpTable[i];
910 : }
911 0 : putCopyOpCode( aSymbol, eOp);
912 0 : }
913 : }
914 : else
915 : {
916 0 : for (sal_uInt16 i = 1; i < n; ++i)
917 : {
918 0 : OpCode eOp = OpCode(i);
919 0 : const OUString& rSymbol = r.mpTable[i];
920 0 : putCopyOpCode( rSymbol, eOp);
921 : }
922 : }
923 :
924 : // TODO: maybe copy the external maps too?
925 0 : }
926 :
927 :
928 37 : sal_uInt16 FormulaCompiler::GetErrorConstant( const OUString& rName ) const
929 : {
930 37 : sal_uInt16 nError = 0;
931 37 : OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
932 37 : if (iLook != mxSymbols->getHashMap()->end())
933 : {
934 37 : switch ((*iLook).second)
935 : {
936 : // Not all may make sense in a formula, but these we know as
937 : // opcodes.
938 : case ocErrNull:
939 0 : nError = errNoCode;
940 0 : break;
941 : case ocErrDivZero:
942 4 : nError = errDivisionByZero;
943 4 : break;
944 : case ocErrValue:
945 0 : nError = errNoValue;
946 0 : break;
947 : case ocErrRef:
948 23 : nError = errNoRef;
949 23 : break;
950 : case ocErrName:
951 0 : nError = errNoName;
952 0 : break;
953 : case ocErrNum:
954 0 : nError = errIllegalFPOperation;
955 0 : break;
956 : case ocErrNA:
957 10 : nError = NOTAVAILABLE;
958 10 : break;
959 : default:
960 : ; // nothing
961 : }
962 : }
963 37 : return nError;
964 : }
965 :
966 :
967 0 : void FormulaCompiler::AppendErrorConstant( OUStringBuffer& rBuffer, sal_uInt16 nError ) const
968 : {
969 : OpCode eOp;
970 0 : switch (nError)
971 : {
972 : default:
973 : case errNoCode:
974 0 : eOp = ocErrNull;
975 0 : break;
976 : case errDivisionByZero:
977 0 : eOp = ocErrDivZero;
978 0 : break;
979 : case errNoValue:
980 0 : eOp = ocErrValue;
981 0 : break;
982 : case errNoRef:
983 0 : eOp = ocErrRef;
984 0 : break;
985 : case errNoName:
986 0 : eOp = ocErrName;
987 0 : break;
988 : case errIllegalFPOperation:
989 0 : eOp = ocErrNum;
990 0 : break;
991 : case NOTAVAILABLE:
992 0 : eOp = ocErrNA;
993 0 : break;
994 : }
995 0 : rBuffer.append( mxSymbols->getSymbol( eOp));
996 0 : }
997 :
998 :
999 116 : sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
1000 : {
1001 : static const sal_Int32 kOpCodeUnknown = -1;
1002 116 : return kOpCodeUnknown;
1003 : }
1004 :
1005 46755 : bool FormulaCompiler::GetToken()
1006 : {
1007 : static const short nRecursionMax = 42;
1008 46755 : FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
1009 46755 : if ( nRecursion > nRecursionMax )
1010 : {
1011 0 : SetError( errStackOverflow );
1012 0 : mpToken = new FormulaByteToken( ocStop );
1013 0 : return false;
1014 : }
1015 46755 : if ( bAutoCorrect && !pStack )
1016 : { // don't merge stacked subroutine code into entered formula
1017 0 : aCorrectedFormula += aCorrectedSymbol;
1018 0 : aCorrectedSymbol = "";
1019 : }
1020 46755 : bool bStop = false;
1021 46755 : if( pArr->GetCodeError() && !bIgnoreErrors )
1022 0 : bStop = true;
1023 : else
1024 : {
1025 : short nWasColRowName;
1026 46755 : if ( pArr->nIndex
1027 46755 : && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
1028 0 : nWasColRowName = 1;
1029 : else
1030 46755 : nWasColRowName = 0;
1031 46755 : mpToken = pArr->Next();
1032 93661 : while( mpToken && mpToken->GetOpCode() == ocSpaces )
1033 : {
1034 151 : if ( nWasColRowName )
1035 0 : nWasColRowName++;
1036 151 : if ( bAutoCorrect && !pStack )
1037 0 : CreateStringFromToken( aCorrectedFormula, mpToken.get(), false );
1038 151 : mpToken = pArr->Next();
1039 : }
1040 46755 : if ( bAutoCorrect && !pStack && mpToken )
1041 0 : CreateStringFromToken( aCorrectedSymbol, mpToken.get(), false );
1042 46755 : if( !mpToken )
1043 : {
1044 5512 : if( pStack )
1045 : {
1046 132 : PopTokenArray();
1047 132 : return GetToken();
1048 : }
1049 : else
1050 5380 : bStop = true;
1051 : }
1052 : else
1053 : {
1054 41243 : if ( nWasColRowName >= 2 && mpToken->GetOpCode() == ocColRowName )
1055 : { // convert an ocSpaces to ocIntersect in RPN
1056 0 : mpToken = new FormulaByteToken( ocIntersect );
1057 0 : pArr->nIndex--; // we advanced to the second ocColRowName, step back
1058 : }
1059 : }
1060 : }
1061 46623 : if( bStop )
1062 : {
1063 5380 : mpToken = new FormulaByteToken( ocStop );
1064 5380 : return false;
1065 : }
1066 41243 : if( mpToken->GetOpCode() == ocSubTotal )
1067 5 : glSubTotal = true;
1068 41238 : else if ( mpToken->IsExternalRef() )
1069 : {
1070 52 : return HandleExternalReference(*mpToken);
1071 : }
1072 41186 : else if( mpToken->GetOpCode() == ocName )
1073 : {
1074 102 : return HandleRange();
1075 : }
1076 41084 : else if( mpToken->GetOpCode() == ocColRowName )
1077 : {
1078 0 : return HandleSingleRef();
1079 : }
1080 41084 : else if( mpToken->GetOpCode() == ocDBArea )
1081 : {
1082 2 : return HandleDbData();
1083 : }
1084 41082 : else if( mpToken->GetType() == svSingleRef )
1085 : {
1086 6778 : pArr->nRefs++;
1087 : }
1088 34304 : else if( mpToken->GetType() == svDoubleRef )
1089 : {
1090 2546 : pArr->nRefs++;
1091 : }
1092 41087 : return true;
1093 : }
1094 :
1095 :
1096 : // RPN creation by recursion
1097 21306 : void FormulaCompiler::Factor()
1098 : {
1099 21306 : if ( pArr->GetCodeError() && !bIgnoreErrors )
1100 21306 : return;
1101 :
1102 21306 : CurrentFactor pFacToken( this );
1103 :
1104 21306 : OpCode eOp = mpToken->GetOpCode();
1105 21306 : if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
1106 : eOp == ocDBArea
1107 6154 : || (bCompileForFAP && ((eOp == ocName) || (eOp == ocDBArea)
1108 0 : || (eOp == ocColRowName) || (eOp == ocBad)))
1109 : )
1110 : {
1111 15152 : PutCode( mpToken );
1112 15152 : eOp = NextToken();
1113 30304 : if( eOp == ocOpen )
1114 : {
1115 : // PUSH( is an error that may be caused by an unknown function.
1116 : SetError(
1117 0 : ( mpToken->GetType() == svString
1118 0 : || mpToken->GetType() == svSingleRef )
1119 0 : ? errNoName : errOperatorExpected );
1120 0 : if ( bAutoCorrect && !pStack )
1121 : { // assume multiplication
1122 0 : aCorrectedFormula += mxSymbols->getSymbol( ocMul);
1123 0 : bCorrected = true;
1124 0 : NextToken();
1125 0 : eOp = Expression();
1126 0 : if( eOp != ocClose )
1127 0 : SetError( errPairExpected);
1128 : else
1129 0 : eOp = NextToken();
1130 : }
1131 : }
1132 : }
1133 6154 : else if( eOp == ocOpen )
1134 : {
1135 1011 : NextToken();
1136 1011 : eOp = Expression();
1137 2022 : while ((eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors))
1138 : { // range list (A1;A2) converted to (A1~A2)
1139 0 : pFacToken = mpToken;
1140 0 : NextToken();
1141 0 : eOp = Expression();
1142 : // Do not ignore error here, regardless of bIgnoreErrors, otherwise
1143 : // errors like =(1;) would also result in display of =(1~)
1144 0 : if (!pArr->GetCodeError())
1145 : {
1146 0 : pFacToken->NewOpCode( ocUnion, FormulaToken::PrivateAccess());
1147 0 : PutCode( pFacToken);
1148 : }
1149 : }
1150 1011 : if (eOp != ocClose)
1151 0 : SetError( errPairExpected);
1152 : else
1153 1011 : eOp = NextToken();
1154 : }
1155 : else
1156 : {
1157 5143 : if( nNumFmt == NUMBERFORMAT_UNDEFINED )
1158 2823 : nNumFmt = lcl_GetRetFormat( eOp );
1159 :
1160 5143 : if ( IsOpCodeVolatile( eOp) )
1161 25 : pArr->SetExclusiveRecalcModeAlways();
1162 : else
1163 : {
1164 5118 : switch( eOp )
1165 : {
1166 : // Functions recalculated on every document load.
1167 : // Don't use SetExclusiveRecalcModeOnLoad() which would
1168 : // override ModeAlways, use
1169 : // AddRecalcMode(RECALCMODE_ONLOAD) instead.
1170 : case ocConvert :
1171 : case ocDde:
1172 : case ocMacro:
1173 : case ocExternal:
1174 73 : pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1175 73 : break;
1176 : // If the referred cell is moved the value changes.
1177 : case ocColumn :
1178 : case ocRow :
1179 53 : pArr->SetRecalcModeOnRefMove();
1180 53 : break;
1181 : // ocCell needs recalc on move for some possible type values.
1182 : // and recalc mode on load, fdo#60646
1183 : case ocCell :
1184 28 : pArr->SetRecalcModeOnRefMove();
1185 28 : pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1186 28 : break;
1187 : case ocHyperLink :
1188 : // cell with hyperlink needs to be calculated on load to
1189 : // get its matrix result generated.
1190 0 : pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1191 0 : pArr->SetHyperLink( true);
1192 0 : break;
1193 : default:
1194 : ; // nothing
1195 : }
1196 : }
1197 5143 : if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
1198 : {
1199 54 : pFacToken = mpToken;
1200 54 : eOp = NextToken();
1201 108 : if (eOp != ocOpen)
1202 : {
1203 0 : SetError( errPairExpected);
1204 0 : PutCode( pFacToken );
1205 : }
1206 : else
1207 : {
1208 54 : eOp = NextToken();
1209 54 : if (eOp != ocClose)
1210 0 : SetError( errPairExpected);
1211 54 : PutCode( pFacToken);
1212 54 : eOp = NextToken();
1213 : }
1214 : }
1215 : // special cases NOT() and NEG()
1216 5089 : else if( eOp == ocNot || eOp == ocNeg
1217 5089 : || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
1218 : {
1219 288 : pFacToken = mpToken;
1220 288 : eOp = NextToken();
1221 288 : if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot )
1222 0 : nNumFmt = NUMBERFORMAT_LOGICAL;
1223 288 : if (eOp == ocOpen)
1224 : {
1225 288 : NextToken();
1226 288 : eOp = Expression();
1227 : }
1228 : else
1229 0 : SetError( errPairExpected);
1230 288 : if (eOp != ocClose)
1231 0 : SetError( errPairExpected);
1232 288 : else if ( !pArr->GetCodeError() )
1233 288 : pFacToken->SetByte( 1 );
1234 288 : PutCode( pFacToken );
1235 288 : eOp = NextToken();
1236 : }
1237 4801 : else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
1238 857 : || eOp == ocExternal
1239 793 : || eOp == ocMacro
1240 792 : || eOp == ocAnd
1241 779 : || eOp == ocOr
1242 761 : || eOp == ocBad
1243 743 : || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1244 743 : || ( bCompileForFAP
1245 0 : && ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose ) )
1246 : )
1247 : {
1248 4058 : pFacToken = mpToken;
1249 4058 : OpCode eMyLastOp = eOp;
1250 4058 : eOp = NextToken();
1251 4058 : bool bNoParam = false;
1252 4058 : bool bBadName = false;
1253 4058 : if (eOp == ocOpen)
1254 : {
1255 4043 : eOp = NextToken();
1256 4043 : if (eOp == ocClose)
1257 32 : bNoParam = true;
1258 : else
1259 4011 : eOp = Expression();
1260 : }
1261 15 : else if (eMyLastOp == ocBad)
1262 : {
1263 : // Just a bad name, not an unknown function, no parameters, no
1264 : // closing expected.
1265 15 : bBadName = true;
1266 15 : bNoParam = true;
1267 : }
1268 : else
1269 0 : SetError( errPairExpected);
1270 4058 : sal_uInt8 nSepCount = 0;
1271 4058 : if( !bNoParam )
1272 : {
1273 4011 : nSepCount++;
1274 12275 : while ( (eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors) )
1275 : {
1276 4253 : nSepCount++;
1277 4253 : NextToken();
1278 4253 : eOp = Expression();
1279 : }
1280 : }
1281 4058 : if (bBadName)
1282 : ; // nothing, keep current token for return
1283 4043 : else if (eOp != ocClose)
1284 0 : SetError( errPairExpected);
1285 : else
1286 4043 : eOp = NextToken();
1287 : // Jumps are just normal functions for the FunctionAutoPilot tree view
1288 4058 : if ( bCompileForFAP && pFacToken->GetType() == svJump )
1289 0 : pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
1290 : else
1291 4058 : pFacToken->SetByte( nSepCount );
1292 4058 : PutCode( pFacToken );
1293 : }
1294 743 : else if (eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose)
1295 : {
1296 : // the PC counters are -1
1297 37 : pFacToken = mpToken;
1298 37 : switch (eOp)
1299 : {
1300 : case ocIf:
1301 25 : pFacToken->GetJump()[ 0 ] = 3; // if, else, behind
1302 25 : break;
1303 : case ocChose:
1304 0 : pFacToken->GetJump()[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
1305 0 : break;
1306 : case ocIfError:
1307 : case ocIfNA:
1308 12 : pFacToken->GetJump()[ 0 ] = 2; // if, behind
1309 12 : break;
1310 : default:
1311 : SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump count case?");
1312 : }
1313 37 : eOp = NextToken();
1314 37 : if (eOp == ocOpen)
1315 : {
1316 37 : NextToken();
1317 37 : eOp = Expression();
1318 : }
1319 : else
1320 0 : SetError( errPairExpected);
1321 37 : PutCode( pFacToken );
1322 : // During AutoCorrect (since pArr->GetCodeError() is
1323 : // ignored) an unlimited ocIf would crash because
1324 : // ScRawToken::Clone() allocates the JumpBuffer according to
1325 : // nJump[0]*2+2, which is 3*2+2 on ocIf and 2*2+2 ocIfError and ocIfNA.
1326 : short nJumpMax;
1327 37 : OpCode eFacOpCode = pFacToken->GetOpCode();
1328 37 : switch (eFacOpCode)
1329 : {
1330 : case ocIf:
1331 25 : nJumpMax = 3;
1332 25 : break;
1333 : case ocChose:
1334 0 : nJumpMax = FORMULA_MAXJUMPCOUNT;
1335 0 : break;
1336 : case ocIfError:
1337 : case ocIfNA:
1338 12 : nJumpMax = 2;
1339 12 : break;
1340 : default:
1341 0 : nJumpMax = 0;
1342 : SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump max case?");
1343 : }
1344 37 : short nJumpCount = 0;
1345 203 : while ( (nJumpCount < (FORMULA_MAXJUMPCOUNT - 1)) && (eOp == ocSep)
1346 129 : && (!pArr->GetCodeError() || bIgnoreErrors) )
1347 : {
1348 46 : if ( ++nJumpCount <= nJumpMax )
1349 46 : pFacToken->GetJump()[nJumpCount] = pc-1;
1350 46 : NextToken();
1351 46 : eOp = Expression();
1352 : // ocSep or ocClose terminate the subexpression
1353 46 : PutCode( mpToken );
1354 : }
1355 37 : if (eOp != ocClose)
1356 0 : SetError( errPairExpected);
1357 : else
1358 : {
1359 37 : eOp = NextToken();
1360 : // always limit to nJumpMax, no arbitrary overwrites
1361 37 : if ( ++nJumpCount <= nJumpMax )
1362 37 : pFacToken->GetJump()[ nJumpCount ] = pc-1;
1363 37 : eFacOpCode = pFacToken->GetOpCode();
1364 : bool bLimitOk;
1365 37 : switch (eFacOpCode)
1366 : {
1367 : case ocIf:
1368 25 : bLimitOk = (nJumpCount <= 3);
1369 25 : break;
1370 : case ocChose:
1371 0 : bLimitOk = (nJumpCount < FORMULA_MAXJUMPCOUNT); /* TODO: check, really <, not <=? */
1372 0 : break;
1373 : case ocIfError:
1374 : case ocIfNA:
1375 12 : bLimitOk = (nJumpCount <= 2);
1376 12 : break;
1377 : default:
1378 0 : bLimitOk = false;
1379 : SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump limit case?");
1380 : }
1381 37 : if (bLimitOk)
1382 37 : pFacToken->GetJump()[ 0 ] = nJumpCount;
1383 : else
1384 0 : SetError( errIllegalParameter);
1385 37 : }
1386 : }
1387 706 : else if ( eOp == ocMissing )
1388 : {
1389 9 : PutCode( mpToken );
1390 9 : eOp = NextToken();
1391 : }
1392 697 : else if ( eOp == ocClose )
1393 : {
1394 0 : SetError( errParameterExpected );
1395 : }
1396 697 : else if ( eOp == ocSep )
1397 : { // Subsequent ocSep
1398 0 : SetError( errParameterExpected );
1399 0 : if ( bAutoCorrect && !pStack )
1400 : {
1401 0 : aCorrectedSymbol = "";
1402 0 : bCorrected = true;
1403 : }
1404 : }
1405 697 : else if ( mpToken->IsExternalRef() )
1406 : {
1407 0 : PutCode( mpToken);
1408 0 : eOp = NextToken();
1409 : }
1410 : else
1411 : {
1412 697 : SetError( errUnknownToken );
1413 697 : if ( bAutoCorrect && !pStack )
1414 : {
1415 0 : if ( eOp == ocStop )
1416 : { // trailing operator w/o operand
1417 0 : sal_Int32 nLen = aCorrectedFormula.getLength();
1418 0 : if ( nLen )
1419 0 : aCorrectedFormula = aCorrectedFormula.copy( 0, nLen - 1 );
1420 0 : aCorrectedSymbol = "";
1421 0 : bCorrected = true;
1422 : }
1423 : }
1424 : }
1425 21306 : }
1426 : }
1427 :
1428 21306 : void FormulaCompiler::RangeLine()
1429 : {
1430 21306 : Factor();
1431 42612 : while (mpToken->GetOpCode() == ocRange)
1432 : {
1433 0 : FormulaToken** pCode1 = pCode - 1;
1434 0 : FormulaTokenRef p = mpToken;
1435 0 : NextToken();
1436 0 : Factor();
1437 0 : FormulaToken** pCode2 = pCode - 1;
1438 0 : if (!MergeRangeReference( pCode1, pCode2))
1439 0 : PutCode(p);
1440 0 : }
1441 21306 : }
1442 :
1443 21306 : void FormulaCompiler::IntersectionLine()
1444 : {
1445 21306 : RangeLine();
1446 42612 : while (mpToken->GetOpCode() == ocIntersect)
1447 : {
1448 0 : FormulaTokenRef p = mpToken;
1449 0 : NextToken();
1450 0 : RangeLine();
1451 0 : PutCode(p);
1452 0 : }
1453 21306 : }
1454 :
1455 21306 : void FormulaCompiler::UnionLine()
1456 : {
1457 21306 : IntersectionLine();
1458 42612 : while (mpToken->GetOpCode() == ocUnion)
1459 : {
1460 0 : FormulaTokenRef p = mpToken;
1461 0 : NextToken();
1462 0 : IntersectionLine();
1463 0 : PutCode(p);
1464 0 : }
1465 21306 : }
1466 :
1467 21402 : void FormulaCompiler::UnaryLine()
1468 : {
1469 21402 : if( mpToken->GetOpCode() == ocAdd )
1470 0 : GetToken();
1471 25784 : else if (SC_OPCODE_START_UN_OP <= mpToken->GetOpCode() &&
1472 4382 : mpToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
1473 : {
1474 96 : FormulaTokenRef p = mpToken;
1475 96 : NextToken();
1476 96 : UnaryLine();
1477 96 : PutCode( p );
1478 : }
1479 : else
1480 21306 : UnionLine();
1481 21402 : }
1482 :
1483 21306 : void FormulaCompiler::PostOpLine()
1484 : {
1485 21306 : UnaryLine();
1486 42612 : while ( mpToken->GetOpCode() == ocPercentSign )
1487 : { // this operator _follows_ its operand
1488 0 : PutCode( mpToken );
1489 0 : NextToken();
1490 : }
1491 21306 : }
1492 :
1493 21305 : void FormulaCompiler::PowLine()
1494 : {
1495 21305 : PostOpLine();
1496 42611 : while (mpToken->GetOpCode() == ocPow)
1497 : {
1498 1 : FormulaTokenRef p = mpToken;
1499 1 : NextToken();
1500 1 : PostOpLine();
1501 1 : PutCode(p);
1502 1 : }
1503 21305 : }
1504 :
1505 19391 : void FormulaCompiler::MulDivLine()
1506 : {
1507 19391 : PowLine();
1508 40696 : while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv)
1509 : {
1510 1914 : FormulaTokenRef p = mpToken;
1511 1914 : NextToken();
1512 1914 : PowLine();
1513 1914 : PutCode(p);
1514 1914 : }
1515 19391 : }
1516 :
1517 15766 : void FormulaCompiler::AddSubLine()
1518 : {
1519 15766 : MulDivLine();
1520 35157 : while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub)
1521 : {
1522 3625 : FormulaTokenRef p = mpToken;
1523 3625 : NextToken();
1524 3625 : MulDivLine();
1525 3625 : PutCode(p);
1526 3625 : }
1527 15766 : }
1528 :
1529 15758 : void FormulaCompiler::ConcatLine()
1530 : {
1531 15758 : AddSubLine();
1532 31524 : while (mpToken->GetOpCode() == ocAmpersand)
1533 : {
1534 8 : FormulaTokenRef p = mpToken;
1535 8 : NextToken();
1536 8 : AddSubLine();
1537 8 : PutCode(p);
1538 8 : }
1539 15758 : }
1540 :
1541 15726 : void FormulaCompiler::CompareLine()
1542 : {
1543 15726 : ConcatLine();
1544 31484 : while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual)
1545 : {
1546 32 : FormulaTokenRef p = mpToken;
1547 32 : NextToken();
1548 32 : ConcatLine();
1549 32 : PutCode(p);
1550 32 : }
1551 15726 : }
1552 :
1553 15726 : void FormulaCompiler::NotLine()
1554 : {
1555 15726 : CompareLine();
1556 31452 : while (mpToken->GetOpCode() == ocNot)
1557 : {
1558 0 : FormulaTokenRef p = mpToken;
1559 0 : NextToken();
1560 0 : CompareLine();
1561 0 : PutCode(p);
1562 0 : }
1563 15726 : }
1564 :
1565 15726 : OpCode FormulaCompiler::Expression()
1566 : {
1567 : static const short nRecursionMax = 42;
1568 15726 : FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
1569 15726 : if ( nRecursion > nRecursionMax )
1570 : {
1571 0 : SetError( errStackOverflow );
1572 0 : return ocStop; //! generate token instead?
1573 : }
1574 15726 : NotLine();
1575 31452 : while (mpToken->GetOpCode() == ocAnd || mpToken->GetOpCode() == ocOr)
1576 : {
1577 0 : FormulaTokenRef p = mpToken;
1578 0 : mpToken->SetByte( 2 ); // 2 parameters!
1579 0 : NextToken();
1580 0 : NotLine();
1581 0 : PutCode(p);
1582 0 : }
1583 15726 : return mpToken->GetOpCode();
1584 : }
1585 :
1586 :
1587 0 : void FormulaCompiler::SetError( sal_uInt16 /*nError*/ )
1588 : {
1589 0 : }
1590 :
1591 0 : FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/,
1592 : bool /*bReuseDoubleRef*/ )
1593 : {
1594 0 : return FormulaTokenRef();
1595 : }
1596 :
1597 0 : bool FormulaCompiler::MergeRangeReference( FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
1598 : {
1599 : FormulaToken *p1, *p2;
1600 0 : if (pc < 2 || !pCode1 || !pCode2 ||
1601 0 : (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
1602 0 : ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
1603 0 : return false;
1604 :
1605 0 : FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
1606 0 : if (!p)
1607 0 : return false;
1608 :
1609 0 : p->IncRef();
1610 0 : p1->DecRef();
1611 0 : p2->DecRef();
1612 0 : *pCode1 = p.get();
1613 0 : --pCode, --pc;
1614 0 : pArr->nRefs--;
1615 :
1616 0 : return true;
1617 : }
1618 :
1619 6080 : bool FormulaCompiler::CompileTokenArray()
1620 : {
1621 6080 : glSubTotal = false;
1622 6080 : bCorrected = false;
1623 6080 : if( !pArr->GetCodeError() || bIgnoreErrors )
1624 : {
1625 6080 : if ( bAutoCorrect )
1626 : {
1627 0 : aCorrectedFormula = "";
1628 0 : aCorrectedSymbol = "";
1629 : }
1630 6080 : pArr->nRefs = 0; // count from start
1631 6080 : pArr->DelRPN();
1632 6080 : pStack = NULL;
1633 : FormulaToken* pData[ FORMULA_MAXTOKENS ];
1634 6080 : pCode = pData;
1635 6080 : bool bWasForced = pArr->IsRecalcModeForced();
1636 6080 : if ( bWasForced )
1637 : {
1638 0 : if ( bAutoCorrect )
1639 0 : aCorrectedFormula = "=";
1640 : }
1641 6080 : pArr->ClearRecalcMode();
1642 6080 : pArr->Reset();
1643 6080 : eLastOp = ocOpen;
1644 6080 : pc = 0;
1645 6080 : NextToken();
1646 6080 : OpCode eOp = Expression();
1647 : // Some trailing garbage that doesn't form an expression?
1648 6080 : if (eOp != ocStop)
1649 698 : SetError( errOperatorExpected);
1650 :
1651 6080 : sal_uInt16 nErrorBeforePop = pArr->GetCodeError();
1652 :
1653 12160 : while( pStack )
1654 0 : PopTokenArray();
1655 6080 : if( pc )
1656 : {
1657 5383 : pArr->pRPN = new FormulaToken*[ pc ];
1658 5383 : pArr->nRPN = pc;
1659 5383 : memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
1660 : }
1661 :
1662 : // once an error, always an error
1663 6080 : if( !pArr->GetCodeError() && nErrorBeforePop )
1664 0 : pArr->SetCodeError( nErrorBeforePop);
1665 :
1666 6080 : if( pArr->GetCodeError() && !bIgnoreErrors )
1667 : {
1668 698 : pArr->DelRPN();
1669 698 : pArr->SetHyperLink( false);
1670 : }
1671 :
1672 6080 : if ( bWasForced )
1673 0 : pArr->SetRecalcModeForced();
1674 : }
1675 6080 : if( nNumFmt == NUMBERFORMAT_UNDEFINED )
1676 3257 : nNumFmt = NUMBERFORMAT_NUMBER;
1677 6080 : return glSubTotal;
1678 : }
1679 :
1680 132 : void FormulaCompiler::PopTokenArray()
1681 : {
1682 132 : if( pStack )
1683 : {
1684 132 : FormulaArrayStack* p = pStack;
1685 132 : pStack = p->pNext;
1686 132 : p->pArr->nRefs = sal::static_int_cast<short>( p->pArr->nRefs + pArr->nRefs );
1687 : // obtain special RecalcMode from SharedFormula
1688 132 : if ( pArr->IsRecalcModeAlways() )
1689 0 : p->pArr->SetExclusiveRecalcModeAlways();
1690 132 : else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
1691 0 : p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
1692 132 : p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
1693 132 : if( p->bTemp )
1694 132 : delete pArr;
1695 132 : pArr = p->pArr;
1696 132 : delete p;
1697 : }
1698 132 : }
1699 :
1700 144 : void FormulaCompiler::CreateStringFromTokenArray( OUString& rFormula )
1701 : {
1702 144 : OUStringBuffer aBuffer( pArr->GetLen() * 5 );
1703 144 : CreateStringFromTokenArray( aBuffer );
1704 144 : rFormula = aBuffer.makeStringAndClear();
1705 144 : }
1706 :
1707 799 : void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer )
1708 : {
1709 799 : rBuffer.setLength(0);
1710 799 : if( !pArr->GetLen() )
1711 799 : return;
1712 :
1713 799 : FormulaTokenArray* pSaveArr = pArr;
1714 799 : bool bODFF = FormulaGrammar::isODFF( meGrammar);
1715 799 : if (bODFF || FormulaGrammar::isPODF( meGrammar) )
1716 : {
1717 : // Scan token array for missing args and re-write if present.
1718 236 : MissingConvention aConv( bODFF);
1719 236 : if (pArr->NeedsPofRewrite( aConv))
1720 0 : pArr = pArr->RewriteMissingToPof( aConv);
1721 : }
1722 :
1723 : // At least one character per token, plus some are references, some are
1724 : // function names, some are numbers, ...
1725 799 : rBuffer.ensureCapacity( pArr->GetLen() * 5 );
1726 :
1727 799 : if ( pArr->IsRecalcModeForced() )
1728 0 : rBuffer.append( '=');
1729 799 : FormulaToken* t = pArr->First();
1730 3785 : while( t )
1731 2187 : t = CreateStringFromToken( rBuffer, t, true );
1732 :
1733 799 : if (pSaveArr != pArr)
1734 : {
1735 0 : delete pArr;
1736 0 : pArr = pSaveArr;
1737 : }
1738 : }
1739 :
1740 25001 : FormulaToken* FormulaCompiler::CreateStringFromToken( OUString& rFormula, FormulaToken* pTokenP,bool bAllowArrAdvance )
1741 : {
1742 25001 : OUStringBuffer aBuffer;
1743 25001 : FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
1744 25001 : rFormula += aBuffer.makeStringAndClear();
1745 25001 : return p;
1746 : }
1747 :
1748 27188 : FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuffer, FormulaToken* pTokenP, bool bAllowArrAdvance )
1749 : {
1750 27188 : bool bNext = true;
1751 27188 : bool bSpaces = false;
1752 27188 : FormulaToken* t = pTokenP;
1753 27188 : OpCode eOp = t->GetOpCode();
1754 27188 : if( eOp >= ocAnd && eOp <= ocOr )
1755 : {
1756 : // AND, OR infix?
1757 20 : if ( bAllowArrAdvance )
1758 20 : t = pArr->Next();
1759 : else
1760 0 : t = pArr->PeekNext();
1761 20 : bNext = false;
1762 20 : bSpaces = ( !t || t->GetOpCode() != ocOpen );
1763 : }
1764 27188 : if( bSpaces )
1765 0 : rBuffer.append( ' ');
1766 :
1767 27188 : if( eOp == ocSpaces )
1768 : {
1769 12 : bool bIntersectionOp = mxSymbols->isODFF();
1770 12 : if (bIntersectionOp)
1771 : {
1772 0 : const FormulaToken* p = pArr->PeekPrevNoSpaces();
1773 0 : bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1774 0 : if (bIntersectionOp)
1775 : {
1776 0 : p = pArr->PeekNextNoSpaces();
1777 0 : bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1778 : }
1779 : }
1780 12 : if (bIntersectionOp)
1781 0 : rBuffer.appendAscii( "!!");
1782 : else
1783 : {
1784 : // most times it's just one blank
1785 12 : sal_uInt8 n = t->GetByte();
1786 24 : for ( sal_uInt8 j=0; j<n; ++j )
1787 : {
1788 12 : rBuffer.append( ' ');
1789 : }
1790 : }
1791 : }
1792 27176 : else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1793 0 : rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
1794 27176 : else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount()) // Keyword:
1795 27176 : rBuffer.append( mxSymbols->getSymbol( eOp));
1796 : else
1797 : {
1798 : SAL_WARN( "formula.core","unknown OpCode");
1799 0 : rBuffer.append( GetNativeSymbol( ocErrName ));
1800 : }
1801 27188 : if( bNext )
1802 : {
1803 27168 : if (t->IsExternalRef())
1804 : {
1805 20 : CreateStringFromExternal( rBuffer, pTokenP);
1806 : }
1807 : else
1808 : {
1809 27148 : switch( t->GetType() )
1810 : {
1811 : case svDouble:
1812 213 : AppendDouble( rBuffer, t->GetDouble() );
1813 213 : break;
1814 :
1815 : case svString:
1816 120 : if( eOp == ocBad || eOp == ocStringXML )
1817 60 : rBuffer.append( t->GetString().getString());
1818 : else
1819 60 : AppendString( rBuffer, t->GetString().getString() );
1820 120 : break;
1821 : case svSingleRef:
1822 13125 : CreateStringFromSingleRef( rBuffer, t);
1823 13125 : break;
1824 : case svDoubleRef:
1825 12620 : CreateStringFromDoubleRef( rBuffer, t);
1826 12620 : break;
1827 : case svMatrix:
1828 0 : CreateStringFromMatrix( rBuffer, t );
1829 0 : break;
1830 :
1831 : case svIndex:
1832 12 : CreateStringFromIndex( rBuffer, t );
1833 12 : break;
1834 : case svExternal:
1835 : {
1836 : // mapped or translated name of AddIns
1837 0 : OUString aAddIn( t->GetExternal() );
1838 0 : bool bMapped = mxSymbols->isPODF(); // ODF 1.1 directly uses programmatical name
1839 0 : if (!bMapped && mxSymbols->hasExternals())
1840 : {
1841 0 : ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
1842 0 : if (iLook != mxSymbols->getReverseExternalHashMap()->end())
1843 : {
1844 0 : aAddIn = (*iLook).second;
1845 0 : bMapped = true;
1846 : }
1847 : }
1848 0 : if (!bMapped && !mxSymbols->isEnglish())
1849 0 : LocalizeString( aAddIn );
1850 0 : rBuffer.append( aAddIn);
1851 : }
1852 0 : break;
1853 : case svError:
1854 0 : AppendErrorConstant( rBuffer, t->GetError());
1855 0 : break;
1856 : case svByte:
1857 : case svJump:
1858 : case svFAP:
1859 : case svMissing:
1860 : case svSep:
1861 1058 : break; // Opcodes
1862 : default:
1863 : OSL_FAIL("FormulaCompiler:: GetStringFromToken errUnknownVariable");
1864 : } // of switch
1865 : }
1866 : }
1867 27188 : if( bSpaces )
1868 0 : rBuffer.append( ' ');
1869 27188 : if ( bAllowArrAdvance )
1870 : {
1871 2187 : if( bNext )
1872 2167 : t = pArr->Next();
1873 2187 : return t;
1874 : }
1875 25001 : return pTokenP;
1876 : }
1877 :
1878 :
1879 213 : void FormulaCompiler::AppendDouble( OUStringBuffer& rBuffer, double fVal ) const
1880 : {
1881 213 : if ( mxSymbols->isEnglish() )
1882 : {
1883 : ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1884 : rtl_math_StringFormat_Automatic,
1885 173 : rtl_math_DecimalPlaces_Max, '.', true );
1886 : }
1887 : else
1888 : {
1889 40 : SvtSysLocale aSysLocale;
1890 : ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1891 : rtl_math_StringFormat_Automatic,
1892 : rtl_math_DecimalPlaces_Max,
1893 40 : aSysLocale.GetLocaleDataPtr()->getNumDecimalSep()[0],
1894 40 : true );
1895 : }
1896 213 : }
1897 :
1898 0 : void FormulaCompiler::AppendBoolean( OUStringBuffer& rBuffer, bool bVal ) const
1899 : {
1900 0 : rBuffer.append( mxSymbols->getSymbol( static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
1901 0 : }
1902 :
1903 60 : void FormulaCompiler::AppendString( OUStringBuffer& rBuffer, const OUString & rStr ) const
1904 : {
1905 60 : rBuffer.append( '"');
1906 60 : if ( lcl_UnicodeStrChr( rStr.getStr(), '"' ) == NULL )
1907 60 : rBuffer.append( rStr );
1908 : else
1909 : {
1910 0 : OUString aStr = rStr.replaceAll( "\"", "\"\"" );
1911 0 : rBuffer.append(aStr);
1912 : }
1913 60 : rBuffer.append( '"');
1914 60 : }
1915 :
1916 390 : void FormulaCompiler::UpdateSeparatorsNative(
1917 : const OUString& rSep, const OUString& rArrayColSep, const OUString& rArrayRowSep )
1918 : {
1919 390 : NonConstOpCodeMapPtr xSymbolsNative;
1920 390 : lcl_fillNativeSymbols( xSymbolsNative);
1921 390 : xSymbolsNative->putOpCode( rSep, ocSep);
1922 390 : xSymbolsNative->putOpCode( rArrayColSep, ocArrayColSep);
1923 390 : xSymbolsNative->putOpCode( rArrayRowSep, ocArrayRowSep);
1924 390 : }
1925 :
1926 390 : void FormulaCompiler::ResetNativeSymbols()
1927 : {
1928 390 : NonConstOpCodeMapPtr xSymbolsNative;
1929 390 : lcl_fillNativeSymbols( xSymbolsNative, true);
1930 390 : lcl_fillNativeSymbols( xSymbolsNative);
1931 390 : }
1932 :
1933 0 : void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr& xMap )
1934 : {
1935 0 : NonConstOpCodeMapPtr xSymbolsNative;
1936 0 : lcl_fillNativeSymbols( xSymbolsNative);
1937 0 : xSymbolsNative->copyFrom( *xMap, true);
1938 0 : }
1939 :
1940 :
1941 46519 : OpCode FormulaCompiler::NextToken()
1942 : {
1943 46519 : if( !GetToken() )
1944 5380 : return ocStop;
1945 41139 : OpCode eOp = mpToken->GetOpCode();
1946 : // There must be an operator before a push
1947 56161 : if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
1948 22146 : !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
1949 2929 : (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
1950 0 : SetError( errOperatorExpected);
1951 : // Operator and Plus => operator
1952 43952 : if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
1953 2813 : (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
1954 0 : eOp = NextToken();
1955 : else
1956 : {
1957 : // Before an operator there must not be another operator, with the
1958 : // exception of AND and OR.
1959 41139 : if ( eOp != ocAnd && eOp != ocOr &&
1960 9962 : (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP )
1961 11160 : && (eLastOp == ocOpen || eLastOp == ocSep ||
1962 5580 : (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
1963 : {
1964 0 : SetError( errVariableExpected);
1965 0 : if ( bAutoCorrect && !pStack )
1966 : {
1967 0 : if ( eOp == eLastOp || eLastOp == ocOpen )
1968 : { // throw away duplicated operator
1969 0 : aCorrectedSymbol = "";
1970 0 : bCorrected = true;
1971 : }
1972 : else
1973 : {
1974 0 : sal_Int32 nPos = aCorrectedFormula.getLength();
1975 0 : if ( nPos )
1976 : {
1977 0 : nPos--;
1978 0 : sal_Unicode c = aCorrectedFormula[ nPos ];
1979 0 : switch ( eOp )
1980 : { // swap operators
1981 : case ocGreater:
1982 0 : if ( c == mxSymbols->getSymbolChar( ocEqual) )
1983 : { // >= instead of =>
1984 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
1985 0 : OUString( mxSymbols->getSymbolChar(ocGreater) ) );
1986 0 : aCorrectedSymbol = OUString(c);
1987 0 : bCorrected = true;
1988 : }
1989 0 : break;
1990 : case ocLess:
1991 0 : if ( c == mxSymbols->getSymbolChar( ocEqual) )
1992 : { // <= instead of =<
1993 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
1994 0 : OUString( mxSymbols->getSymbolChar(ocLess) ) );
1995 0 : aCorrectedSymbol = OUString(c);
1996 0 : bCorrected = true;
1997 : }
1998 0 : else if ( c == mxSymbols->getSymbolChar( ocGreater) )
1999 : { // <> instead of ><
2000 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2001 0 : OUString( mxSymbols->getSymbolChar(ocLess) ) );
2002 0 : aCorrectedSymbol = OUString(c);
2003 0 : bCorrected = true;
2004 : }
2005 0 : break;
2006 : case ocMul:
2007 0 : if ( c == mxSymbols->getSymbolChar( ocSub) )
2008 : { // *- instead of -*
2009 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2010 0 : OUString( mxSymbols->getSymbolChar(ocMul) ) );
2011 0 : aCorrectedSymbol = OUString(c);
2012 0 : bCorrected = true;
2013 : }
2014 0 : break;
2015 : case ocDiv:
2016 0 : if ( c == mxSymbols->getSymbolChar( ocSub) )
2017 : { // /- instead of -/
2018 0 : aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2019 0 : OUString( mxSymbols->getSymbolChar(ocDiv) ) );
2020 0 : aCorrectedSymbol = OUString(c);
2021 0 : bCorrected = true;
2022 : }
2023 0 : break;
2024 : default:
2025 : ; // nothing
2026 : }
2027 : }
2028 : }
2029 : }
2030 : }
2031 41139 : eLastOp = eOp;
2032 : }
2033 41139 : return eOp;
2034 : }
2035 25320 : void FormulaCompiler::PutCode( FormulaTokenRef& p )
2036 : {
2037 25320 : if( pc >= FORMULA_MAXTOKENS - 1 )
2038 : {
2039 0 : if ( pc == FORMULA_MAXTOKENS - 1 )
2040 : {
2041 0 : p = new FormulaByteToken( ocStop );
2042 0 : p->IncRef();
2043 0 : *pCode++ = p.get();
2044 0 : ++pc;
2045 : }
2046 0 : SetError( errCodeOverflow);
2047 0 : return;
2048 : }
2049 25320 : if( pArr->GetCodeError() && !bCompileForFAP )
2050 0 : return;
2051 25320 : ForceArrayOperator( p, pCurrentFactorToken);
2052 25320 : p->IncRef();
2053 25320 : *pCode++ = p.get();
2054 25320 : pc++;
2055 : }
2056 :
2057 :
2058 0 : bool FormulaCompiler::HandleExternalReference( const FormulaToken& /*_aToken*/)
2059 : {
2060 0 : return true;
2061 : }
2062 :
2063 0 : bool FormulaCompiler::HandleRange()
2064 : {
2065 0 : return true;
2066 : }
2067 :
2068 0 : bool FormulaCompiler::HandleSingleRef()
2069 : {
2070 0 : return true;
2071 : }
2072 :
2073 0 : bool FormulaCompiler::HandleDbData()
2074 : {
2075 0 : return true;
2076 : }
2077 :
2078 0 : void FormulaCompiler::CreateStringFromSingleRef( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2079 : {
2080 0 : }
2081 :
2082 0 : void FormulaCompiler::CreateStringFromDoubleRef( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2083 : {
2084 0 : }
2085 :
2086 0 : void FormulaCompiler::CreateStringFromIndex( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2087 : {
2088 0 : }
2089 :
2090 0 : void FormulaCompiler::CreateStringFromMatrix( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2091 : {
2092 0 : }
2093 :
2094 0 : void FormulaCompiler::CreateStringFromExternal( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
2095 : {
2096 0 : }
2097 :
2098 0 : void FormulaCompiler::LocalizeString( OUString& /*rName*/ ) const
2099 : {
2100 0 : }
2101 :
2102 132 : void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
2103 : {
2104 132 : if ( bAutoCorrect && !pStack )
2105 : { // don't merge stacked subroutine code into entered formula
2106 0 : aCorrectedFormula += aCorrectedSymbol;
2107 0 : aCorrectedSymbol = "";
2108 : }
2109 132 : FormulaArrayStack* p = new FormulaArrayStack;
2110 132 : p->pNext = pStack;
2111 132 : p->pArr = pArr;
2112 132 : p->bTemp = bTemp;
2113 132 : pStack = p;
2114 132 : pArr = pa;
2115 132 : }
2116 :
2117 : } // namespace formula
2118 :
2119 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|