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