update credits
[LibreOffice.git] / formula / source / core / api / FormulaCompiler.cxx
blobaecacd4bf1f0632a1c4d438026403e39bb992f0f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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"
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>
36 // =============================================================================
37 namespace formula
39 // =============================================================================
40 using namespace ::com::sun::star;
42 static const sal_Char* pInternal[ 1 ] = { "TTT" };
44 // =============================================================================
45 namespace
47 // =============================================================================
48 class FormulaCompilerRecursionGuard
50 private:
51 short& rRecursion;
52 public:
53 FormulaCompilerRecursionGuard( short& rRec )
54 : rRecursion( rRec ) { ++rRecursion; }
55 ~FormulaCompilerRecursionGuard() { --rRecursion; }
58 short lcl_GetRetFormat( OpCode eOpCode )
60 switch (eOpCode)
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 return NUMBERFORMAT_LOGICAL;
88 case ocGetActDate:
89 case ocGetDate:
90 case ocEasterSunday :
91 return NUMBERFORMAT_DATE;
92 case ocGetActTime:
93 return NUMBERFORMAT_DATETIME;
94 case ocGetTime:
95 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 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 return NUMBERFORMAT_PERCENT;
118 default:
119 return NUMBERFORMAT_NUMBER;
123 inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, sal_uInt16 nOpCode )
125 sheet::FormulaOpCodeMapEntry aEntry;
126 aEntry.Token.OpCode = nOpCode;
127 aEntry.Name = pTable[nOpCode];
128 rVec.push_back( aEntry);
131 void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, sal_uInt16 nOpCodeBeg, sal_uInt16 nOpCodeEnd )
133 for (sal_uInt16 nOpCode = nOpCodeBeg; nOpCode < nOpCodeEnd; ++nOpCode)
134 lclPushOpCodeMapEntry( rVec, pTable, nOpCode );
137 void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, const sal_uInt16* pnOpCodes, size_t nCount )
139 for (const sal_uInt16* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes)
140 lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes );
143 class OpCodeList : public Resource // temp object for resource
145 public:
147 OpCodeList( sal_uInt16, FormulaCompiler::NonConstOpCodeMapPtr );
149 private:
150 bool getOpCodeString( String& rStr, sal_uInt16 nOp );
151 void putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp );
153 private:
154 enum SeparatorType
156 SEMICOLON_BASE,
157 COMMA_BASE
159 SeparatorType meSepType;
162 OpCodeList::OpCodeList( sal_uInt16 nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap ) :
163 Resource( ResId(nRID,*ResourceManager::getResManager()) )
164 ,meSepType(SEMICOLON_BASE)
166 for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
168 String aOpStr;
169 if ( getOpCodeString(aOpStr, i) )
170 xMap->putOpCode(aOpStr, OpCode(i));
171 else
172 putDefaultOpCode(xMap, i);
175 FreeResource();
178 bool OpCodeList::getOpCodeString( String& rStr, sal_uInt16 nOp )
180 switch (nOp)
182 case SC_OPCODE_SEP:
184 if (meSepType == COMMA_BASE)
186 rStr = OUString(",");
187 return true;
189 else if (meSepType == SEMICOLON_BASE)
191 rStr = OUString(";");
192 return true;
195 break;
196 case SC_OPCODE_ARRAY_COL_SEP:
198 if (meSepType == COMMA_BASE)
200 rStr = OUString(",");
201 return true;
203 else if (meSepType == SEMICOLON_BASE)
205 rStr = OUString(";");
206 return true;
209 break;
210 case SC_OPCODE_ARRAY_ROW_SEP:
212 if (meSepType == COMMA_BASE)
214 rStr = OUString(";");
215 return true;
217 else if (meSepType == SEMICOLON_BASE)
219 rStr = OUString("|");
220 return true;
223 break;
226 return false;
229 void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp )
231 ResId aRes(nOp,*ResourceManager::getResManager());
232 aRes.SetRT(RSC_STRING);
233 if (IsAvailableRes(aRes))
234 xMap->putOpCode(aRes, OpCode(nOp));
236 // -----------------------------------------------------------------------------
237 // static
238 const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,sal_Unicode c )
240 if ( !pStr )
241 return NULL;
242 while ( *pStr )
244 if ( *pStr == c )
245 return pStr;
246 pStr++;
248 return NULL;
250 // =============================================================================
251 } // empty
252 // =============================================================================
254 void FormulaCompiler::OpCodeMap::putExternal( const String & rSymbol, const String & rAddIn )
256 // Different symbols may map to the same AddIn, but the same AddIn may not
257 // map to different symbols, the first pair wins. Same symbol of course may
258 // not map to different AddIns, again the first pair wins and also the
259 // AddIn->symbol mapping is not inserted in other cases.
260 bool bOk = mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second;
261 SAL_WARN_IF( !bOk, "formula.core", "OpCodeMap::putExternal: symbol not inserted, " << rSymbol << " -> " << rAddIn);
262 if (bOk)
264 bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
265 // Failed insertion of the AddIn is ok for different symbols mapping to
266 // the same AddIn. Make this INFO only.
267 SAL_INFO_IF( !bOk, "formula.core", "OpCodeMap::putExternal: AddIn not inserted, " << rAddIn << " -> " << rSymbol);
271 void FormulaCompiler::OpCodeMap::putExternalSoftly( const String & rSymbol, const String & rAddIn )
273 bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
274 if (bOk)
275 mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn));
277 uno::Sequence< sheet::FormulaToken > FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(const FormulaCompiler& _rCompiler,const uno::Sequence< OUString >& rNames ) const
279 const sal_Int32 nLen = rNames.getLength();
280 uno::Sequence< sheet::FormulaToken > aTokens( nLen);
281 sheet::FormulaToken* pToken = aTokens.getArray();
282 OUString const * pName = rNames.getConstArray();
283 OUString const * const pStop = pName + nLen;
284 for ( ; pName < pStop; ++pName, ++pToken)
286 OpCodeHashMap::const_iterator iLook( mpHashMap->find( *pName));
287 if (iLook != mpHashMap->end())
288 pToken->OpCode = (*iLook).second;
289 else
291 OUString aIntName;
292 if (hasExternals())
294 ExternalHashMap::const_iterator iExt( mpExternalHashMap->find( *pName));
295 if (iExt != mpExternalHashMap->end())
296 aIntName = (*iExt).second;
297 // Check for existence not needed here, only name-mapping is of
298 // interest.
300 if (aIntName.isEmpty())
301 aIntName = _rCompiler.FindAddInFunction(*pName, !isEnglish()); // bLocalFirst=false for english
302 if (aIntName.isEmpty())
303 pToken->OpCode = getOpCodeUnknown();
304 else
306 pToken->OpCode = ocExternal;
307 pToken->Data <<= aIntName;
311 return aTokens;
313 uno::Sequence< sheet::FormulaOpCodeMapEntry > FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(const FormulaCompiler& _rCompiler,const sal_Int32 nGroups ) const
315 using namespace sheet;
317 // Unfortunately uno::Sequence can't grow without cumbersome reallocs. As
318 // we don't know in advance how many elements it will have we use a
319 // temporary vector to add elements and then copy to Sequence :-(
320 ::std::vector< FormulaOpCodeMapEntry > aVec;
322 if (nGroups == FormulaMapGroup::SPECIAL)
324 // Use specific order, keep in sync with
325 // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl
326 static const struct
328 sal_Int32 nOff;
329 OpCode eOp;
330 } aMap[] = {
331 { FormulaMapGroupSpecialOffset::PUSH , ocPush } ,
332 { FormulaMapGroupSpecialOffset::CALL , ocCall } ,
333 { FormulaMapGroupSpecialOffset::STOP , ocStop } ,
334 { FormulaMapGroupSpecialOffset::EXTERNAL , ocExternal } ,
335 { FormulaMapGroupSpecialOffset::NAME , ocName } ,
336 { FormulaMapGroupSpecialOffset::NO_NAME , ocNoName } ,
337 { FormulaMapGroupSpecialOffset::MISSING , ocMissing } ,
338 { FormulaMapGroupSpecialOffset::BAD , ocBad } ,
339 { FormulaMapGroupSpecialOffset::SPACES , ocSpaces } ,
340 { FormulaMapGroupSpecialOffset::MAT_REF , ocMatRef } ,
341 { FormulaMapGroupSpecialOffset::DB_AREA , ocDBArea } ,
342 { FormulaMapGroupSpecialOffset::MACRO , ocMacro } ,
343 { FormulaMapGroupSpecialOffset::COL_ROW_NAME , ocColRowName }
345 const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
346 // Preallocate vector elements.
347 if (aVec.size() < nCount)
349 FormulaOpCodeMapEntry aEntry;
350 aEntry.Token.OpCode = getOpCodeUnknown();
351 aVec.resize( nCount, aEntry);
352 } // if (aVec.size() < nCount)
354 FormulaOpCodeMapEntry aEntry;
355 for (size_t i=0; i < nCount; ++i)
357 size_t nIndex = static_cast< size_t >( aMap[i].nOff );
358 if (aVec.size() <= nIndex)
360 // The offsets really should be aligned with the size, so if
361 // the vector was preallocated above this code to resize it is
362 // just a measure in case the table isn't in sync with the API,
363 // usually it isn't executed.
364 aEntry.Token.OpCode = getOpCodeUnknown();
365 aVec.resize( nIndex + 1, aEntry );
367 aEntry.Token.OpCode = aMap[i].eOp;
368 aVec[nIndex] = aEntry;
371 else
373 /* FIXME: Once we support error constants in formulas we'll need a map
374 * group for that, e.g. FormulaMapGroup::ERROR_CONSTANTS, and fill
375 * SC_OPCODE_START_ERRORS to SC_OPCODE_STOP_ERRORS. */
377 // Anything else but SPECIAL.
378 if ((nGroups & FormulaMapGroup::SEPARATORS) != 0)
380 static const sal_uInt16 aOpCodes[] = {
381 SC_OPCODE_OPEN,
382 SC_OPCODE_CLOSE,
383 SC_OPCODE_SEP,
385 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
387 if ((nGroups & FormulaMapGroup::ARRAY_SEPARATORS) != 0)
389 static const sal_uInt16 aOpCodes[] = {
390 SC_OPCODE_ARRAY_OPEN,
391 SC_OPCODE_ARRAY_CLOSE,
392 SC_OPCODE_ARRAY_ROW_SEP,
393 SC_OPCODE_ARRAY_COL_SEP
395 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
397 if ((nGroups & FormulaMapGroup::UNARY_OPERATORS) != 0)
399 // Due to the nature of the percent operator following its operand
400 // it isn't sorted into unary operators for compiler interna.
401 lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
402 // "+" can be used as unary operator too, push only if binary group is not set
403 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
404 lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
405 // regular unary operators
406 for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
408 switch (nOp)
410 // NOT and NEG in fact are functions but for legacy reasons
411 // are sorted into unary operators for compiler interna.
412 case SC_OPCODE_NOT :
413 case SC_OPCODE_NEG :
414 break; // nothing,
415 default:
416 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
420 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
422 for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
424 switch (nOp)
426 // AND and OR in fact are functions but for legacy reasons
427 // are sorted into binary operators for compiler interna.
428 case SC_OPCODE_AND :
429 case SC_OPCODE_OR :
430 break; // nothing,
431 default:
432 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
436 if ((nGroups & FormulaMapGroup::FUNCTIONS) != 0)
438 // Function names are not consecutive, skip the gaps between
439 // functions with no parameter, functions with 1 parameter
440 lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_NO_PAR, ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
441 lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_1_PAR, ::std::min< sal_uInt16 >( SC_OPCODE_STOP_1_PAR, mnSymbols ) );
442 // Additional functions not within range of functions.
443 static const sal_uInt16 aOpCodes[] = {
444 SC_OPCODE_IF,
445 SC_OPCODE_IF_ERROR,
446 SC_OPCODE_IF_NA,
447 SC_OPCODE_CHOSE,
448 SC_OPCODE_AND,
449 SC_OPCODE_OR,
450 SC_OPCODE_NOT,
451 SC_OPCODE_NEG
453 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
454 // functions with 2 or more parameters.
455 for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
457 switch (nOp)
459 // NO_NAME is in SPECIAL.
460 case SC_OPCODE_NO_NAME :
461 break; // nothing,
462 default:
463 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
466 // If AddIn functions are present in this mapping, use them, and only those.
467 if (hasExternals())
469 for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
471 FormulaOpCodeMapEntry aEntry;
472 aEntry.Name = (*it).first;
473 aEntry.Token.Data <<= OUString( (*it).second);
474 aEntry.Token.OpCode = ocExternal;
475 aVec.push_back( aEntry);
478 else
480 _rCompiler.fillAddInToken(aVec,isEnglish());
484 const FormulaOpCodeMapEntry* pRet = aVec.empty() ? 0 : &aVec[0];
485 return uno::Sequence< FormulaOpCodeMapEntry >(pRet, aVec.size());
487 //-----------------------------------------------------------------------------
489 void FormulaCompiler::OpCodeMap::putOpCode( const String & rStr, const OpCode eOp )
491 DBG_ASSERT( 0 < eOp && sal_uInt16(eOp) < mnSymbols, "OpCodeMap::putOpCode: OpCode out of range");
492 if (0 < eOp && sal_uInt16(eOp) < mnSymbols)
494 DBG_ASSERT( (mpTable[eOp].Len() == 0) || (mpTable[eOp] == rStr) ||
495 (eOp == ocCurrency) || (eOp == ocSep) || (eOp == ocArrayColSep) ||
496 (eOp == ocArrayRowSep),
497 OStringBuffer(
498 RTL_CONSTASCII_STRINGPARAM("OpCodeMap::putOpCode: reusing OpCode ")).
499 append(sal_Int32(eOp)).append(RTL_CONSTASCII_STRINGPARAM(" (")).
500 append(OUStringToOString(rStr, RTL_TEXTENCODING_ASCII_US)).
501 append(')').getStr());
502 mpTable[eOp] = rStr;
503 mpHashMap->insert( OpCodeHashMap::value_type( rStr, eOp));
506 // -----------------------------------------------------------------------------
507 // class FormulaCompiler
508 // -----------------------------------------------------------------------------
509 DBG_NAME(FormulaCompiler)
510 FormulaCompiler::FormulaCompiler(FormulaTokenArray& _rArr)
512 pArr( &_rArr ),
513 pExternalRef(NULL),
514 pStack( NULL ),
515 nRecursion(0),
516 nNumFmt( NUMBERFORMAT_UNDEFINED ),
517 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
518 bAutoCorrect( false ),
519 bCorrected( false ),
520 bCompileForFAP( false ),
521 bIgnoreErrors( false )
524 DBG_CTOR(FormulaCompiler,NULL);
526 FormulaCompiler::FormulaCompiler()
528 pArr( NULL ),
529 pExternalRef(NULL),
530 pStack( NULL ),
531 nRecursion(0),
532 nNumFmt( NUMBERFORMAT_UNDEFINED ),
533 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
534 bAutoCorrect( false ),
535 bCorrected( false ),
536 bCompileForFAP( false ),
537 bIgnoreErrors( false )
540 DBG_CTOR(FormulaCompiler,NULL);
542 FormulaCompiler::~FormulaCompiler()
544 DBG_DTOR(FormulaCompiler,NULL);
547 FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
549 FormulaCompiler::OpCodeMapPtr xMap;
550 using namespace sheet;
551 switch (nLanguage)
553 case FormulaLanguage::ODFF :
554 if (!mxSymbolsODFF)
555 InitSymbolsODFF();
556 xMap = mxSymbolsODFF;
557 break;
558 case FormulaLanguage::ODF_11 :
559 if (!mxSymbolsPODF)
560 InitSymbolsPODF();
561 xMap = mxSymbolsPODF;
562 break;
563 case FormulaLanguage::ENGLISH :
564 if (!mxSymbolsEnglish)
565 InitSymbolsEnglish();
566 xMap = mxSymbolsEnglish;
567 break;
568 case FormulaLanguage::NATIVE :
569 if (!mxSymbolsNative)
570 InitSymbolsNative();
571 xMap = mxSymbolsNative;
572 break;
573 case FormulaLanguage::XL_ENGLISH:
574 if (!mxSymbolsEnglishXL)
575 InitSymbolsEnglishXL();
576 xMap = mxSymbolsEnglishXL;
577 break;
578 default:
579 ; // nothing, NULL map returned
581 return xMap;
583 // -----------------------------------------------------------------------------
585 String FormulaCompiler::FindAddInFunction( const String& /*rUpperName*/, bool /*bLocalFirst*/ ) const
587 return String();
589 // -----------------------------------------------------------------------------
590 FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
591 const uno::Sequence<
592 const sheet::FormulaOpCodeMapEntry > & rMapping,
593 bool bEnglish )
595 using sheet::FormulaOpCodeMapEntry;
596 // Filter / API maps are never Core
597 NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1,false, FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(FormulaGrammar::GRAM_EXTERNAL, bEnglish),FormulaGrammar::CONV_UNSPECIFIED)));
598 FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
599 FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
600 for ( ; pArr2 < pStop; ++pArr2)
602 OpCode eOp = OpCode(pArr2->Token.OpCode);
603 if (eOp != ocExternal)
604 xMap->putOpCode( pArr2->Name, eOp);
605 else
607 OUString aExternalName;
608 if (pArr2->Token.Data >>= aExternalName)
609 xMap->putExternal( pArr2->Name, aExternalName);
610 else
612 SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
616 return xMap;
619 // -----------------------------------------------------------------------------
620 void lcl_fillNativeSymbols(FormulaCompiler::NonConstOpCodeMapPtr& _xMap,bool _destroy = false)
622 static FormulaCompiler::NonConstOpCodeMapPtr s_SymbolMap;
623 if ( _destroy )
625 s_SymbolMap.reset();
626 } // if ( _destroy )
627 else if ( !s_SymbolMap.get() )
629 // Core
630 s_SymbolMap.reset( new FormulaCompiler::OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
631 OModuleClient aModuleClient;
632 OpCodeList aOpCodeListNative( RID_STRLIST_FUNCTION_NAMES, s_SymbolMap );
633 // No AddInMap for native core mapping.
634 } // if ( !s_SymbolMap.get() )
635 _xMap = s_SymbolMap;
637 // -----------------------------------------------------------------------------
638 const String& FormulaCompiler::GetNativeSymbol( OpCode eOp )
640 NonConstOpCodeMapPtr xSymbolsNative;
641 lcl_fillNativeSymbols(xSymbolsNative);
642 return xSymbolsNative->getSymbol( eOp );
644 // -----------------------------------------------------------------------------
645 void FormulaCompiler::InitSymbolsNative() const
647 lcl_fillNativeSymbols(mxSymbolsNative);
649 // -----------------------------------------------------------------------------
650 void FormulaCompiler::InitSymbolsEnglish() const
652 static NonConstOpCodeMapPtr s_sSymbol;
653 if ( !s_sSymbol.get() )
654 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
655 mxSymbolsEnglish = s_sSymbol;
657 // -----------------------------------------------------------------------------
658 void FormulaCompiler::InitSymbolsPODF() const
660 static NonConstOpCodeMapPtr s_sSymbol;
661 if ( !s_sSymbol.get() )
662 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_PODF,s_sSymbol);
663 mxSymbolsPODF = s_sSymbol;
665 // -----------------------------------------------------------------------------
666 void FormulaCompiler::InitSymbolsODFF() const
668 static NonConstOpCodeMapPtr s_sSymbol;
669 if ( !s_sSymbol.get() )
670 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF,FormulaGrammar::GRAM_ODFF,s_sSymbol);
671 mxSymbolsODFF = s_sSymbol;
673 // -----------------------------------------------------------------------------
674 void FormulaCompiler::InitSymbolsEnglishXL() const
676 static NonConstOpCodeMapPtr s_sSymbol;
677 if ( !s_sSymbol.get() )
678 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
679 mxSymbolsEnglishXL = s_sSymbol;
681 // TODO: For now, just replace the separators to the Excel English
682 // variants. Later, if we want to properly map Excel functions with Calc
683 // functions, we'll need to do a little more work here.
684 mxSymbolsEnglishXL->putOpCode(OUString(','), ocSep);
685 mxSymbolsEnglishXL->putOpCode(OUString(','), ocArrayColSep);
686 mxSymbolsEnglishXL->putOpCode(OUString(';'), ocArrayRowSep);
689 // -----------------------------------------------------------------------------
690 void FormulaCompiler::loadSymbols(sal_uInt16 _nSymbols,FormulaGrammar::Grammar _eGrammar,NonConstOpCodeMapPtr& _xMap) const
692 if ( !_xMap.get() )
694 // not Core
695 _xMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, _eGrammar != FormulaGrammar::GRAM_ODFF, _eGrammar ));
696 OModuleClient aModuleClient;
697 OpCodeList aOpCodeList( _nSymbols, _xMap );
699 fillFromAddInMap( _xMap, _eGrammar);
700 // Fill from collection for AddIns not already present.
701 if ( FormulaGrammar::GRAM_ENGLISH != _eGrammar )
702 fillFromAddInCollectionUpperName( _xMap);
703 else
704 fillFromAddInCollectionEnglishName( _xMap);
707 // -----------------------------------------------------------------------------
708 void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const
711 // -----------------------------------------------------------------------------
712 void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const
715 // -----------------------------------------------------------------------------
716 void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const
719 // -----------------------------------------------------------------------------
720 OpCode FormulaCompiler::GetEnglishOpCode( const String& rName ) const
722 FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap(sheet::FormulaLanguage::ENGLISH);
724 formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) );
725 bool bFound = (iLook != xMap->getHashMap()->end());
726 return bFound ? (*iLook).second : OpCode(ocNone);
729 bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
731 bool bRet = false;
732 switch (eOp)
734 // no parameters:
735 case ocRandom:
736 case ocGetActDate:
737 case ocGetActTime:
738 // one parameter:
739 case ocFormula:
740 case ocInfo:
741 // more than one parameters:
742 // ocIndirect/ocIndirectXL otherwise would have to do
743 // StopListening and StartListening on a reference for every
744 // interpreted value.
745 case ocIndirect:
746 case ocIndirectXL:
747 // ocOffset results in indirect references.
748 case ocOffset:
749 bRet = true;
750 break;
751 default:
752 bRet = false;
753 break;
755 return bRet;
758 // Remove quotes, escaped quotes are unescaped.
759 bool FormulaCompiler::DeQuote( String& rStr )
761 xub_StrLen nLen = rStr.Len();
762 if ( nLen > 1 && rStr.GetChar(0) == '\'' && rStr.GetChar( nLen-1 ) == '\'' )
764 rStr.Erase( nLen-1, 1 );
765 rStr.Erase( 0, 1 );
766 xub_StrLen nPos = 0;
767 while ( (nPos = rStr.SearchAscii( "\\\'", nPos)) != STRING_NOTFOUND )
769 rStr.Erase( nPos, 1 );
770 ++nPos;
772 return true;
774 return false;
776 // -----------------------------------------------------------------------------
777 void FormulaCompiler::fillAddInToken(::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,bool /*_bIsEnglish*/) const
780 // -----------------------------------------------------------------------------
781 bool FormulaCompiler::IsMatrixFunction(OpCode _eOpCode)
783 switch ( _eOpCode )
785 case ocDde :
786 case ocGrowth :
787 case ocTrend :
788 case ocRKP :
789 case ocRGP :
790 case ocFrequency :
791 case ocMatTrans :
792 case ocMatMult :
793 case ocMatInv :
794 case ocMatrixUnit :
795 return true;
796 default:
798 // added to avoid warnings
801 return false;
804 // -----------------------------------------------------------------------------
805 FormulaCompiler::OpCodeMap::~OpCodeMap()
807 delete mpReverseExternalHashMap;
808 delete mpExternalHashMap;
809 delete [] mpTable;
810 delete mpHashMap;
812 // -----------------------------------------------------------------------------
813 void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap& r )
815 delete mpHashMap;
816 mpHashMap = new OpCodeHashMap(mnSymbols);
818 sal_uInt16 n = r.getSymbolCount();
819 for (sal_uInt16 i = 0; i < n; ++i)
821 OpCode eOp = OpCode(i);
822 const String& rSymbol = r.getSymbol(eOp);
823 putOpCode(rSymbol, eOp);
826 // TODO: maybe copy the external maps too?
828 // -----------------------------------------------------------------------------
830 sal_uInt16 FormulaCompiler::GetErrorConstant( const String& rName ) const
832 sal_uInt16 nError = 0;
833 OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
834 if (iLook != mxSymbols->getHashMap()->end())
836 switch ((*iLook).second)
838 // Not all may make sense in a formula, but these we know as
839 // opcodes.
840 case ocErrNull:
841 nError = errNoCode;
842 break;
843 case ocErrDivZero:
844 nError = errDivisionByZero;
845 break;
846 case ocErrValue:
847 nError = errNoValue;
848 break;
849 case ocErrRef:
850 nError = errNoRef;
851 break;
852 case ocErrName:
853 nError = errNoName;
854 break;
855 case ocErrNum:
856 nError = errIllegalFPOperation;
857 break;
858 case ocErrNA:
859 nError = NOTAVAILABLE;
860 break;
861 default:
862 ; // nothing
865 return nError;
869 void FormulaCompiler::AppendErrorConstant( OUStringBuffer& rBuffer, sal_uInt16 nError )
871 OpCode eOp;
872 switch (nError)
874 default:
875 case errNoCode:
876 eOp = ocErrNull;
877 break;
878 case errDivisionByZero:
879 eOp = ocErrDivZero;
880 break;
881 case errNoValue:
882 eOp = ocErrValue;
883 break;
884 case errNoRef:
885 eOp = ocErrRef;
886 break;
887 case errNoName:
888 eOp = ocErrName;
889 break;
890 case errIllegalFPOperation:
891 eOp = ocErrNum;
892 break;
893 case NOTAVAILABLE:
894 eOp = ocErrNA;
895 break;
897 rBuffer.append( mxSymbols->getSymbol( eOp));
900 // -----------------------------------------------------------------------------
901 sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
903 static const sal_Int32 kOpCodeUnknown = -1;
904 return kOpCodeUnknown;
906 // -----------------------------------------------------------------------------
907 bool FormulaCompiler::GetToken()
909 static const short nRecursionMax = 42;
910 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
911 if ( nRecursion > nRecursionMax )
913 SetError( errStackOverflow );
914 mpToken = new FormulaByteToken( ocStop );
915 return false;
917 if ( bAutoCorrect && !pStack )
918 { // don't merge stacked subroutine code into entered formula
919 aCorrectedFormula += aCorrectedSymbol;
920 aCorrectedSymbol.Erase();
922 bool bStop = false;
923 if( pArr->GetCodeError() && !bIgnoreErrors )
924 bStop = true;
925 else
927 short nWasColRowName;
928 if ( pArr->nIndex
929 && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
930 nWasColRowName = 1;
931 else
932 nWasColRowName = 0;
933 mpToken = pArr->Next();
934 while( mpToken && mpToken->GetOpCode() == ocSpaces )
936 if ( nWasColRowName )
937 nWasColRowName++;
938 if ( bAutoCorrect && !pStack )
939 CreateStringFromToken( aCorrectedFormula, mpToken.get(), false );
940 mpToken = pArr->Next();
942 if ( bAutoCorrect && !pStack && mpToken )
943 CreateStringFromToken( aCorrectedSymbol, mpToken.get(), false );
944 if( !mpToken )
946 if( pStack )
948 PopTokenArray();
949 return GetToken();
951 else
952 bStop = true;
954 else
956 if ( nWasColRowName >= 2 && mpToken->GetOpCode() == ocColRowName )
957 { // convert an ocSpaces to ocIntersect in RPN
958 mpToken = new FormulaByteToken( ocIntersect );
959 pArr->nIndex--; // we advanced to the second ocColRowName, step back
963 if( bStop )
965 mpToken = new FormulaByteToken( ocStop );
966 return false;
968 if( mpToken->GetOpCode() == ocSubTotal )
969 glSubTotal = true;
970 else if ( mpToken->IsExternalRef() )
972 return HandleExternalReference(*mpToken);
974 else if( mpToken->GetOpCode() == ocName )
976 return HandleRange();
978 else if( mpToken->GetOpCode() == ocColRowName )
980 return HandleSingleRef();
982 else if( mpToken->GetOpCode() == ocDBArea )
984 return HandleDbData();
986 else if( mpToken->GetType() == svSingleRef )
988 pArr->nRefs++;
990 else if( mpToken->GetType() == svDoubleRef )
992 pArr->nRefs++;
994 return true;
996 //---------------------------------------------------------------------------
997 // RPN creation by recursion
998 //---------------------------------------------------------------------------
1000 void FormulaCompiler::Factor()
1002 if ( pArr->GetCodeError() && !bIgnoreErrors )
1003 return;
1005 CurrentFactor pFacToken( this );
1007 OpCode eOp = mpToken->GetOpCode();
1008 if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
1009 eOp == ocDBArea
1010 || (bCompileForFAP && ((eOp == ocName) || (eOp == ocDBArea)
1011 || (eOp == ocColRowName) || (eOp == ocBad)))
1014 PutCode( mpToken );
1015 eOp = NextToken();
1016 if( eOp == ocOpen )
1018 // PUSH( is an error that may be caused by an unknown function.
1019 SetError(
1020 ( mpToken->GetType() == svString
1021 || mpToken->GetType() == svSingleRef )
1022 ? errNoName : errOperatorExpected );
1023 if ( bAutoCorrect && !pStack )
1024 { // assume multiplication
1025 aCorrectedFormula += mxSymbols->getSymbol(ocMul);
1026 bCorrected = true;
1027 NextToken();
1028 eOp = Expression();
1029 if( eOp != ocClose )
1030 SetError(errPairExpected);
1031 else
1032 eOp = NextToken();
1036 else if( eOp == ocOpen )
1038 NextToken();
1039 eOp = Expression();
1040 while ((eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors))
1041 { // range list (A1;A2) converted to (A1~A2)
1042 pFacToken = mpToken;
1043 NextToken();
1044 eOp = Expression();
1045 // Do not ignore error here, regardless of bIgnoreErrors, otherwise
1046 // errors like =(1;) would also result in display of =(1~)
1047 if (!pArr->GetCodeError())
1049 pFacToken->NewOpCode( ocUnion,FormulaToken::PrivateAccess());
1050 PutCode( pFacToken);
1053 if (eOp != ocClose)
1054 SetError(errPairExpected);
1055 else
1056 eOp = NextToken();
1058 else
1060 if( nNumFmt == NUMBERFORMAT_UNDEFINED )
1061 nNumFmt = lcl_GetRetFormat( eOp );
1063 if ( IsOpCodeVolatile(eOp) )
1064 pArr->SetExclusiveRecalcModeAlways();
1065 else
1067 switch( eOp )
1069 // Functions recalculated on every document load.
1070 // Don't use SetExclusiveRecalcModeOnLoad() which would
1071 // override ModeAlways, use
1072 // AddRecalcMode(RECALCMODE_ONLOAD) instead.
1073 case ocConvert :
1074 case ocDde:
1075 case ocMacro:
1076 case ocExternal:
1077 pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1078 break;
1079 // If the referred cell is moved the value changes.
1080 case ocColumn :
1081 case ocRow :
1082 pArr->SetRecalcModeOnRefMove();
1083 break;
1084 // ocCell needs recalc on move for some possible type values.
1085 // and recalc mode on load, fdo#60646
1086 case ocCell :
1087 pArr->SetRecalcModeOnRefMove();
1088 pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1089 break;
1090 case ocHyperLink :
1091 // cell with hyperlink needs to be calculated on load to
1092 // get its matrix result generated.
1093 pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1094 pArr->SetHyperLink(true);
1095 break;
1096 default:
1097 ; // nothing
1100 if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
1102 pFacToken = mpToken;
1103 eOp = NextToken();
1104 if (eOp != ocOpen)
1106 SetError(errPairExpected);
1107 PutCode( pFacToken );
1109 else
1111 eOp = NextToken();
1112 if (eOp != ocClose)
1113 SetError(errPairExpected);
1114 PutCode(pFacToken);
1115 eOp = NextToken();
1118 // special cases NOT() and NEG()
1119 else if( eOp == ocNot || eOp == ocNeg
1120 || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
1122 pFacToken = mpToken;
1123 eOp = NextToken();
1124 if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot )
1125 nNumFmt = NUMBERFORMAT_LOGICAL;
1126 if (eOp == ocOpen)
1128 NextToken();
1129 eOp = Expression();
1131 else
1132 SetError(errPairExpected);
1133 if (eOp != ocClose)
1134 SetError(errPairExpected);
1135 else if ( !pArr->GetCodeError() )
1136 pFacToken->SetByte( 1 );
1137 PutCode( pFacToken );
1138 eOp = NextToken();
1140 else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
1141 || eOp == ocExternal
1142 || eOp == ocMacro
1143 || eOp == ocAnd
1144 || eOp == ocOr
1145 || eOp == ocBad
1146 || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1147 || ( bCompileForFAP
1148 && ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose ) )
1151 pFacToken = mpToken;
1152 OpCode eMyLastOp = eOp;
1153 eOp = NextToken();
1154 bool bNoParam = false;
1155 bool bBadName = false;
1156 if (eOp == ocOpen)
1158 eOp = NextToken();
1159 if (eOp == ocClose)
1160 bNoParam = true;
1161 else
1162 eOp = Expression();
1164 else if (eMyLastOp == ocBad)
1166 // Just a bad name, not an unknown function, no parameters, no
1167 // closing expected.
1168 bBadName = true;
1169 bNoParam = true;
1171 else
1172 SetError(errPairExpected);
1173 sal_uInt8 nSepCount = 0;
1174 if( !bNoParam )
1176 nSepCount++;
1177 while ( (eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors) )
1179 nSepCount++;
1180 NextToken();
1181 eOp = Expression();
1184 if (bBadName)
1185 ; // nothing, keep current token for return
1186 else if (eOp != ocClose)
1187 SetError(errPairExpected);
1188 else
1189 eOp = NextToken();
1190 // Jumps are just normal functions for the FunctionAutoPilot tree view
1191 if ( bCompileForFAP && pFacToken->GetType() == svJump )
1192 pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
1193 else
1194 pFacToken->SetByte( nSepCount );
1195 PutCode( pFacToken );
1197 else if (eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose)
1199 // the PC counters are -1
1200 pFacToken = mpToken;
1201 switch (eOp)
1203 case ocIf:
1204 pFacToken->GetJump()[ 0 ] = 3; // if, else, behind
1205 break;
1206 case ocChose:
1207 pFacToken->GetJump()[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
1208 break;
1209 case ocIfError:
1210 case ocIfNA:
1211 pFacToken->GetJump()[ 0 ] = 2; // if, behind
1212 break;
1213 default:
1214 SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump count case?");
1216 eOp = NextToken();
1217 if (eOp == ocOpen)
1219 NextToken();
1220 eOp = Expression();
1222 else
1223 SetError(errPairExpected);
1224 PutCode( pFacToken );
1225 // During AutoCorrect (since pArr->GetCodeError() is
1226 // ignored) an unlimited ocIf would crash because
1227 // ScRawToken::Clone() allocates the JumpBuffer according to
1228 // nJump[0]*2+2, which is 3*2+2 on ocIf and 2*2+2 ocIfError and ocIfNA.
1229 short nJumpMax;
1230 OpCode eFacOpCode = pFacToken->GetOpCode();
1231 switch (eFacOpCode)
1233 case ocIf:
1234 nJumpMax = 3;
1235 break;
1236 case ocChose:
1237 nJumpMax = FORMULA_MAXJUMPCOUNT;
1238 break;
1239 case ocIfError:
1240 case ocIfNA:
1241 nJumpMax = 2;
1242 break;
1243 default:
1244 nJumpMax = 0;
1245 SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump max case?");
1247 short nJumpCount = 0;
1248 while ( (nJumpCount < (FORMULA_MAXJUMPCOUNT - 1)) && (eOp == ocSep)
1249 && (!pArr->GetCodeError() || bIgnoreErrors) )
1251 if ( ++nJumpCount <= nJumpMax )
1252 pFacToken->GetJump()[nJumpCount] = pc-1;
1253 NextToken();
1254 eOp = Expression();
1255 // ocSep or ocClose terminate the subexpression
1256 PutCode( mpToken );
1258 if (eOp != ocClose)
1259 SetError(errPairExpected);
1260 else
1262 eOp = NextToken();
1263 // always limit to nJumpMax, no arbitrary overwrites
1264 if ( ++nJumpCount <= nJumpMax )
1265 pFacToken->GetJump()[ nJumpCount ] = pc-1;
1266 eFacOpCode = pFacToken->GetOpCode();
1267 bool bLimitOk;
1268 switch (eFacOpCode)
1270 case ocIf:
1271 bLimitOk = (nJumpCount <= 3);
1272 break;
1273 case ocChose:
1274 bLimitOk = (nJumpCount < FORMULA_MAXJUMPCOUNT); /* TODO: check, really <, not <=? */
1275 break;
1276 case ocIfError:
1277 case ocIfNA:
1278 bLimitOk = (nJumpCount <= 2);
1279 break;
1280 default:
1281 bLimitOk = false;
1282 SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump limit case?");
1284 if (bLimitOk)
1285 pFacToken->GetJump()[ 0 ] = nJumpCount;
1286 else
1287 SetError(errIllegalParameter);
1290 else if ( eOp == ocMissing )
1292 PutCode( mpToken );
1293 eOp = NextToken();
1295 else if ( eOp == ocClose )
1297 SetError( errParameterExpected );
1299 else if ( eOp == ocSep )
1300 { // Subsequent ocSep
1301 SetError( errParameterExpected );
1302 if ( bAutoCorrect && !pStack )
1304 aCorrectedSymbol.Erase();
1305 bCorrected = true;
1308 else if ( mpToken->IsExternalRef() )
1310 PutCode(mpToken);
1311 eOp = NextToken();
1313 else
1315 SetError( errUnknownToken );
1316 if ( bAutoCorrect && !pStack )
1318 if ( eOp == ocStop )
1319 { // trailing operator w/o operand
1320 xub_StrLen nLen = aCorrectedFormula.Len();
1321 if ( nLen )
1322 aCorrectedFormula.Erase( nLen - 1 );
1323 aCorrectedSymbol.Erase();
1324 bCorrected = true;
1331 //---------------------------------------------------------------------------
1333 void FormulaCompiler::RangeLine()
1335 Factor();
1336 while (mpToken->GetOpCode() == ocRange)
1338 FormulaToken** pCode1 = pCode - 1;
1339 FormulaTokenRef p = mpToken;
1340 NextToken();
1341 Factor();
1342 FormulaToken** pCode2 = pCode - 1;
1343 if (!MergeRangeReference( pCode1, pCode2))
1344 PutCode(p);
1348 //---------------------------------------------------------------------------
1350 void FormulaCompiler::IntersectionLine()
1352 RangeLine();
1353 while (mpToken->GetOpCode() == ocIntersect)
1355 FormulaTokenRef p = mpToken;
1356 NextToken();
1357 RangeLine();
1358 PutCode(p);
1362 //---------------------------------------------------------------------------
1364 void FormulaCompiler::UnionLine()
1366 IntersectionLine();
1367 while (mpToken->GetOpCode() == ocUnion)
1369 FormulaTokenRef p = mpToken;
1370 NextToken();
1371 IntersectionLine();
1372 PutCode(p);
1376 //---------------------------------------------------------------------------
1378 void FormulaCompiler::UnaryLine()
1380 if( mpToken->GetOpCode() == ocAdd )
1381 GetToken();
1382 else if (SC_OPCODE_START_UN_OP <= mpToken->GetOpCode() &&
1383 mpToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
1385 FormulaTokenRef p = mpToken;
1386 NextToken();
1387 UnaryLine();
1388 PutCode( p );
1390 else
1391 UnionLine();
1394 //---------------------------------------------------------------------------
1396 void FormulaCompiler::PostOpLine()
1398 UnaryLine();
1399 while ( mpToken->GetOpCode() == ocPercentSign )
1400 { // this operator _follows_ its operand
1401 PutCode( mpToken );
1402 NextToken();
1406 //---------------------------------------------------------------------------
1408 void FormulaCompiler::PowLine()
1410 PostOpLine();
1411 while (mpToken->GetOpCode() == ocPow)
1413 FormulaTokenRef p = mpToken;
1414 NextToken();
1415 PostOpLine();
1416 PutCode(p);
1420 //---------------------------------------------------------------------------
1422 void FormulaCompiler::MulDivLine()
1424 PowLine();
1425 while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv)
1427 FormulaTokenRef p = mpToken;
1428 NextToken();
1429 PowLine();
1430 PutCode(p);
1434 //---------------------------------------------------------------------------
1436 void FormulaCompiler::AddSubLine()
1438 MulDivLine();
1439 while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub)
1441 FormulaTokenRef p = mpToken;
1442 NextToken();
1443 MulDivLine();
1444 PutCode(p);
1448 //---------------------------------------------------------------------------
1450 void FormulaCompiler::ConcatLine()
1452 AddSubLine();
1453 while (mpToken->GetOpCode() == ocAmpersand)
1455 FormulaTokenRef p = mpToken;
1456 NextToken();
1457 AddSubLine();
1458 PutCode(p);
1462 //---------------------------------------------------------------------------
1464 void FormulaCompiler::CompareLine()
1466 ConcatLine();
1467 while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual)
1469 FormulaTokenRef p = mpToken;
1470 NextToken();
1471 ConcatLine();
1472 PutCode(p);
1476 //---------------------------------------------------------------------------
1478 void FormulaCompiler::NotLine()
1480 CompareLine();
1481 while (mpToken->GetOpCode() == ocNot)
1483 FormulaTokenRef p = mpToken;
1484 NextToken();
1485 CompareLine();
1486 PutCode(p);
1490 //---------------------------------------------------------------------------
1492 OpCode FormulaCompiler::Expression()
1494 static const short nRecursionMax = 42;
1495 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
1496 if ( nRecursion > nRecursionMax )
1498 SetError( errStackOverflow );
1499 return ocStop; //! generate token instead?
1501 NotLine();
1502 while (mpToken->GetOpCode() == ocAnd || mpToken->GetOpCode() == ocOr)
1504 FormulaTokenRef p = mpToken;
1505 mpToken->SetByte( 2 ); // 2 parameters!
1506 NextToken();
1507 NotLine();
1508 PutCode(p);
1510 return mpToken->GetOpCode();
1512 // -----------------------------------------------------------------------------
1513 void FormulaCompiler::SetError(sal_uInt16 /*nError*/)
1516 // -----------------------------------------------------------------------------
1517 FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/, bool /*bReuseDoubleRef*/ )
1519 return FormulaTokenRef();
1521 // -----------------------------------------------------------------------------
1522 bool FormulaCompiler::MergeRangeReference(FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
1524 FormulaToken *p1, *p2;
1525 if (pc < 2 || !pCode1 || !pCode2 ||
1526 (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
1527 ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
1528 return false;
1530 FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
1531 if (!p)
1532 return false;
1534 p->IncRef();
1535 p1->DecRef();
1536 p2->DecRef();
1537 *pCode1 = p.get();
1538 --pCode, --pc;
1539 pArr->nRefs--;
1541 return true;
1543 // -----------------------------------------------------------------------------
1544 bool FormulaCompiler::CompileTokenArray()
1546 glSubTotal = false;
1547 bCorrected = false;
1548 if( !pArr->GetCodeError() || bIgnoreErrors )
1550 if ( bAutoCorrect )
1552 aCorrectedFormula.Erase();
1553 aCorrectedSymbol.Erase();
1555 pArr->nRefs = 0; // count from start
1556 pArr->DelRPN();
1557 pStack = NULL;
1558 FormulaToken* pData[ FORMULA_MAXTOKENS ];
1559 pCode = pData;
1560 bool bWasForced = pArr->IsRecalcModeForced();
1561 if ( bWasForced )
1563 if ( bAutoCorrect )
1564 aCorrectedFormula = '=';
1566 pArr->ClearRecalcMode();
1567 pArr->Reset();
1568 eLastOp = ocOpen;
1569 pc = 0;
1570 NextToken();
1571 OpCode eOp = Expression();
1572 // Some trailing garbage that doesn't form an expression?
1573 if (eOp != ocStop)
1574 SetError( errOperatorExpected);
1576 sal_uInt16 nErrorBeforePop = pArr->GetCodeError();
1578 while( pStack )
1579 PopTokenArray();
1580 if( pc )
1582 pArr->pRPN = new FormulaToken*[ pc ];
1583 pArr->nRPN = pc;
1584 memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
1587 // once an error, always an error
1588 if( !pArr->GetCodeError() && nErrorBeforePop )
1589 pArr->SetCodeError( nErrorBeforePop);
1591 if( pArr->GetCodeError() && !bIgnoreErrors )
1593 pArr->DelRPN();
1594 pArr->SetHyperLink(false);
1597 if ( bWasForced )
1598 pArr->SetRecalcModeForced();
1600 if( nNumFmt == NUMBERFORMAT_UNDEFINED )
1601 nNumFmt = NUMBERFORMAT_NUMBER;
1602 return glSubTotal;
1604 // -----------------------------------------------------------------------------
1605 void FormulaCompiler::PopTokenArray()
1607 if( pStack )
1609 FormulaArrayStack* p = pStack;
1610 pStack = p->pNext;
1611 p->pArr->nRefs = sal::static_int_cast<short>( p->pArr->nRefs + pArr->nRefs );
1612 // obtain special RecalcMode from SharedFormula
1613 if ( pArr->IsRecalcModeAlways() )
1614 p->pArr->SetExclusiveRecalcModeAlways();
1615 else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
1616 p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
1617 p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
1618 if( p->bTemp )
1619 delete pArr;
1620 pArr = p->pArr;
1621 delete p;
1624 // -----------------------------------------------------------------------------
1625 void FormulaCompiler::CreateStringFromTokenArray( String& rFormula )
1627 OUStringBuffer aBuffer( pArr->GetLen() * 5 );
1628 CreateStringFromTokenArray( aBuffer );
1629 rFormula = aBuffer.makeStringAndClear();
1632 void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer )
1634 rBuffer.setLength(0);
1635 if( !pArr->GetLen() )
1636 return;
1638 FormulaTokenArray* pSaveArr = pArr;
1639 bool bODFF = FormulaGrammar::isODFF( meGrammar);
1640 if (bODFF || FormulaGrammar::isPODF( meGrammar) )
1642 // Scan token array for missing args and re-write if present.
1643 MissingConvention aConv( bODFF);
1644 if (pArr->NeedsPofRewrite( aConv))
1645 pArr = pArr->RewriteMissingToPof( aConv);
1648 // At least one character per token, plus some are references, some are
1649 // function names, some are numbers, ...
1650 rBuffer.ensureCapacity( pArr->GetLen() * 5 );
1652 if ( pArr->IsRecalcModeForced() )
1653 rBuffer.append(sal_Unicode('='));
1654 FormulaToken* t = pArr->First();
1655 while( t )
1656 t = CreateStringFromToken( rBuffer, t, true );
1658 if (pSaveArr != pArr)
1660 delete pArr;
1661 pArr = pSaveArr;
1664 // -----------------------------------------------------------------------------
1665 FormulaToken* FormulaCompiler::CreateStringFromToken( String& rFormula, FormulaToken* pTokenP,bool bAllowArrAdvance )
1667 OUStringBuffer aBuffer;
1668 FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
1669 rFormula += aBuffer.makeStringAndClear();
1670 return p;
1673 FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuffer, FormulaToken* pTokenP,bool bAllowArrAdvance )
1675 bool bNext = true;
1676 bool bSpaces = false;
1677 FormulaToken* t = pTokenP;
1678 OpCode eOp = t->GetOpCode();
1679 if( eOp >= ocAnd && eOp <= ocOr )
1681 // AND, OR infix?
1682 if ( bAllowArrAdvance )
1683 t = pArr->Next();
1684 else
1685 t = pArr->PeekNext();
1686 bNext = false;
1687 bSpaces = ( !t || t->GetOpCode() != ocOpen );
1689 if( bSpaces )
1690 rBuffer.append(sal_Unicode(' '));
1692 if( eOp == ocSpaces )
1694 bool bIntersectionOp = mxSymbols->isODFF();
1695 if (bIntersectionOp)
1697 const FormulaToken* p = pArr->PeekPrevNoSpaces();
1698 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1699 if (bIntersectionOp)
1701 p = pArr->PeekNextNoSpaces();
1702 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1705 if (bIntersectionOp)
1706 rBuffer.appendAscii( "!!");
1707 else
1709 // most times it's just one blank
1710 sal_uInt8 n = t->GetByte();
1711 for ( sal_uInt8 j=0; j<n; ++j )
1713 rBuffer.append(sal_Unicode(' '));
1717 else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1718 rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
1719 else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount()) // Keyword:
1720 rBuffer.append(mxSymbols->getSymbol(eOp));
1721 else
1723 SAL_WARN( "formula.core","unknown OpCode");
1724 rBuffer.append(GetNativeSymbol( ocErrName ));
1726 if( bNext )
1728 if (t->IsExternalRef())
1730 CreateStringFromExternal(rBuffer, pTokenP);
1732 else
1734 switch( t->GetType() )
1736 case svDouble:
1737 AppendDouble( rBuffer, t->GetDouble() );
1738 break;
1740 case svString:
1741 if( eOp == ocBad || eOp == ocStringXML )
1742 rBuffer.append(t->GetString());
1743 else
1744 AppendString( rBuffer, t->GetString() );
1745 break;
1746 case svSingleRef:
1747 CreateStringFromSingleRef(rBuffer,t);
1748 break;
1749 case svDoubleRef:
1750 CreateStringFromDoubleRef(rBuffer,t);
1751 break;
1752 case svMatrix:
1753 CreateStringFromMatrix( rBuffer, t );
1754 break;
1756 case svIndex:
1757 CreateStringFromIndex( rBuffer, t );
1758 break;
1759 case svExternal:
1761 // mapped or translated name of AddIns
1762 String aAddIn( t->GetExternal() );
1763 bool bMapped = mxSymbols->isPODF(); // ODF 1.1 directly uses programmatical name
1764 if (!bMapped && mxSymbols->hasExternals())
1766 ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
1767 if (iLook != mxSymbols->getReverseExternalHashMap()->end())
1769 aAddIn = (*iLook).second;
1770 bMapped = true;
1773 if (!bMapped && !mxSymbols->isEnglish())
1774 LocalizeString( aAddIn );
1775 rBuffer.append(aAddIn);
1777 break;
1778 case svError:
1779 AppendErrorConstant( rBuffer, t->GetError());
1780 break;
1781 case svByte:
1782 case svJump:
1783 case svFAP:
1784 case svMissing:
1785 case svSep:
1786 break; // Opcodes
1787 default:
1788 OSL_FAIL("FormulaCompiler:: GetStringFromToken errUnknownVariable");
1789 } // of switch
1792 if( bSpaces )
1793 rBuffer.append(sal_Unicode(' '));
1794 if ( bAllowArrAdvance )
1796 if( bNext )
1797 t = pArr->Next();
1798 return t;
1800 return pTokenP;
1802 // -----------------------------------------------------------------------------
1804 void FormulaCompiler::AppendDouble( OUStringBuffer& rBuffer, double fVal )
1806 if ( mxSymbols->isEnglish() )
1808 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1809 rtl_math_StringFormat_Automatic,
1810 rtl_math_DecimalPlaces_Max, '.', true );
1812 else
1814 SvtSysLocale aSysLocale;
1815 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1816 rtl_math_StringFormat_Automatic,
1817 rtl_math_DecimalPlaces_Max,
1818 aSysLocale.GetLocaleDataPtr()->getNumDecimalSep()[0],
1819 true );
1822 // -----------------------------------------------------------------------------
1823 void FormulaCompiler::AppendBoolean( OUStringBuffer& rBuffer, bool bVal )
1825 rBuffer.append( mxSymbols->getSymbol(static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
1827 // -----------------------------------------------------------------------------
1828 void FormulaCompiler::AppendString( OUStringBuffer& rBuffer, const String & rStr )
1830 rBuffer.append(sal_Unicode('"'));
1831 if ( lcl_UnicodeStrChr( rStr.GetBuffer(), '"' ) == NULL )
1832 rBuffer.append( rStr );
1833 else
1835 String aStr( rStr );
1836 aStr.SearchAndReplaceAll( OUString('"'), OUString("\"\"") );
1837 rBuffer.append(aStr);
1839 rBuffer.append(sal_Unicode('"'));
1842 void FormulaCompiler::UpdateSeparatorsNative(
1843 const OUString& rSep, const OUString& rArrayColSep, const OUString& rArrayRowSep )
1845 NonConstOpCodeMapPtr xSymbolsNative;
1846 lcl_fillNativeSymbols(xSymbolsNative);
1847 xSymbolsNative->putOpCode(rSep, ocSep);
1848 xSymbolsNative->putOpCode(rArrayColSep, ocArrayColSep);
1849 xSymbolsNative->putOpCode(rArrayRowSep, ocArrayRowSep);
1852 void FormulaCompiler::ResetNativeSymbols()
1854 NonConstOpCodeMapPtr xSymbolsNative;
1855 lcl_fillNativeSymbols(xSymbolsNative, true);
1856 lcl_fillNativeSymbols(xSymbolsNative);
1859 void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr& xMap )
1861 NonConstOpCodeMapPtr xSymbolsNative;
1862 lcl_fillNativeSymbols(xSymbolsNative);
1863 xSymbolsNative->copyFrom(*xMap);
1866 // -----------------------------------------------------------------------------
1867 OpCode FormulaCompiler::NextToken()
1869 if( !GetToken() )
1870 return ocStop;
1871 OpCode eOp = mpToken->GetOpCode();
1872 // There must be an operator before a push
1873 if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
1874 !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
1875 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
1876 SetError(errOperatorExpected);
1877 // Operator and Plus => operator
1878 if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
1879 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
1880 eOp = NextToken();
1881 else
1883 // Before an operator there must not be another operator, with the
1884 // exception of AND and OR.
1885 if ( eOp != ocAnd && eOp != ocOr &&
1886 (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP )
1887 && (eLastOp == ocOpen || eLastOp == ocSep ||
1888 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
1890 SetError(errVariableExpected);
1891 if ( bAutoCorrect && !pStack )
1893 if ( eOp == eLastOp || eLastOp == ocOpen )
1894 { // throw away duplicated operator
1895 aCorrectedSymbol.Erase();
1896 bCorrected = true;
1898 else
1900 xub_StrLen nPos = aCorrectedFormula.Len();
1901 if ( nPos )
1903 nPos--;
1904 sal_Unicode c = aCorrectedFormula.GetChar( nPos );
1905 switch ( eOp )
1906 { // swap operators
1907 case ocGreater:
1908 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
1909 { // >= instead of =>
1910 aCorrectedFormula.SetChar( nPos,
1911 mxSymbols->getSymbol(ocGreater).GetChar(0) );
1912 aCorrectedSymbol = c;
1913 bCorrected = true;
1915 break;
1916 case ocLess:
1917 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
1918 { // <= instead of =<
1919 aCorrectedFormula.SetChar( nPos,
1920 mxSymbols->getSymbol(ocLess).GetChar(0) );
1921 aCorrectedSymbol = c;
1922 bCorrected = true;
1924 else if ( c == mxSymbols->getSymbol(ocGreater).GetChar(0) )
1925 { // <> instead of ><
1926 aCorrectedFormula.SetChar( nPos,
1927 mxSymbols->getSymbol(ocLess).GetChar(0) );
1928 aCorrectedSymbol = c;
1929 bCorrected = true;
1931 break;
1932 case ocMul:
1933 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
1934 { // *- instead of -*
1935 aCorrectedFormula.SetChar( nPos,
1936 mxSymbols->getSymbol(ocMul).GetChar(0) );
1937 aCorrectedSymbol = c;
1938 bCorrected = true;
1940 break;
1941 case ocDiv:
1942 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
1943 { // /- instead of -/
1944 aCorrectedFormula.SetChar( nPos,
1945 mxSymbols->getSymbol(ocDiv).GetChar(0) );
1946 aCorrectedSymbol = c;
1947 bCorrected = true;
1949 break;
1950 default:
1951 ; // nothing
1957 eLastOp = eOp;
1959 return eOp;
1961 void FormulaCompiler::PutCode( FormulaTokenRef& p )
1963 if( pc >= FORMULA_MAXTOKENS - 1 )
1965 if ( pc == FORMULA_MAXTOKENS - 1 )
1967 p = new FormulaByteToken( ocStop );
1968 p->IncRef();
1969 *pCode++ = p.get();
1970 ++pc;
1972 SetError(errCodeOverflow);
1973 return;
1975 if( pArr->GetCodeError() && !bCompileForFAP )
1976 return;
1977 ForceArrayOperator( p, pCurrentFactorToken);
1978 p->IncRef();
1979 *pCode++ = p.get();
1980 pc++;
1983 // -----------------------------------------------------------------------------
1984 bool FormulaCompiler::HandleExternalReference(const FormulaToken& /*_aToken*/)
1986 return true;
1988 // -----------------------------------------------------------------------------
1989 bool FormulaCompiler::HandleRange()
1991 return true;
1993 // -----------------------------------------------------------------------------
1994 bool FormulaCompiler::HandleSingleRef()
1996 return true;
1998 // -----------------------------------------------------------------------------
1999 bool FormulaCompiler::HandleDbData()
2001 return true;
2003 // -----------------------------------------------------------------------------
2004 void FormulaCompiler::CreateStringFromSingleRef(OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
2007 // -----------------------------------------------------------------------------
2008 void FormulaCompiler::CreateStringFromDoubleRef(OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
2011 // -----------------------------------------------------------------------------
2012 void FormulaCompiler::CreateStringFromIndex(OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
2015 // -----------------------------------------------------------------------------
2016 void FormulaCompiler::CreateStringFromMatrix(OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
2019 // -----------------------------------------------------------------------------
2020 void FormulaCompiler::CreateStringFromExternal(OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
2023 // -----------------------------------------------------------------------------
2024 void FormulaCompiler::LocalizeString( String& /*rName*/ )
2027 void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
2029 if ( bAutoCorrect && !pStack )
2030 { // don't merge stacked subroutine code into entered formula
2031 aCorrectedFormula += aCorrectedSymbol;
2032 aCorrectedSymbol.Erase();
2034 FormulaArrayStack* p = new FormulaArrayStack;
2035 p->pNext = pStack;
2036 p->pArr = pArr;
2037 p->bTemp = bTemp;
2038 pStack = p;
2039 pArr = pa;
2042 // =============================================================================
2043 } // formula
2044 // =============================================================================
2046 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */