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