Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / formula / source / core / api / FormulaCompiler.cxx
blob29b66945c7997ed7cdf2e6642305b3f4286333c2
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 = rtl::OUString(",");
187 return true;
189 else if (meSepType == SEMICOLON_BASE)
191 rStr = rtl::OUString(";");
192 return true;
195 break;
196 case SC_OPCODE_ARRAY_COL_SEP:
198 if (meSepType == COMMA_BASE)
200 rStr = rtl::OUString(",");
201 return true;
203 else if (meSepType == SEMICOLON_BASE)
205 rStr = rtl::OUString(";");
206 return true;
209 break;
210 case SC_OPCODE_ARRAY_ROW_SEP:
212 if (meSepType == COMMA_BASE)
214 rStr = rtl::OUString(";");
215 return true;
217 else if (meSepType == SEMICOLON_BASE)
219 rStr = rtl::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 bool bOk = mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second;
257 if (bOk)
258 bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
259 DBG_ASSERT( bOk, "OpCodeMap::putExternal: symbol not inserted");
262 void FormulaCompiler::OpCodeMap::putExternalSoftly( const String & rSymbol, const String & rAddIn )
264 bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
265 if (bOk)
266 mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn));
268 uno::Sequence< sheet::FormulaToken > FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(const FormulaCompiler& _rCompiler,const uno::Sequence< ::rtl::OUString >& rNames ) const
270 const sal_Int32 nLen = rNames.getLength();
271 uno::Sequence< sheet::FormulaToken > aTokens( nLen);
272 sheet::FormulaToken* pToken = aTokens.getArray();
273 ::rtl::OUString const * pName = rNames.getConstArray();
274 ::rtl::OUString const * const pStop = pName + nLen;
275 for ( ; pName < pStop; ++pName, ++pToken)
277 OpCodeHashMap::const_iterator iLook( mpHashMap->find( *pName));
278 if (iLook != mpHashMap->end())
279 pToken->OpCode = (*iLook).second;
280 else
282 ::rtl::OUString aIntName;
283 if (hasExternals())
285 ExternalHashMap::const_iterator iExt( mpExternalHashMap->find( *pName));
286 if (iExt != mpExternalHashMap->end())
287 aIntName = (*iExt).second;
288 // Check for existence not needed here, only name-mapping is of
289 // interest.
291 if (aIntName.isEmpty())
292 aIntName = _rCompiler.FindAddInFunction(*pName, !isEnglish()); // bLocalFirst=false for english
293 if (aIntName.isEmpty())
294 pToken->OpCode = getOpCodeUnknown();
295 else
297 pToken->OpCode = ocExternal;
298 pToken->Data <<= aIntName;
302 return aTokens;
304 uno::Sequence< sheet::FormulaOpCodeMapEntry > FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(const FormulaCompiler& _rCompiler,const sal_Int32 nGroups ) const
306 using namespace sheet;
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 ::std::vector< FormulaOpCodeMapEntry > aVec;
313 if (nGroups == FormulaMapGroup::SPECIAL)
315 // Use specific order, keep in sync with
316 // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl
317 static const struct
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 }
336 const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
337 // Preallocate vector elements.
338 if (aVec.size() < nCount)
340 FormulaOpCodeMapEntry aEntry;
341 aEntry.Token.OpCode = getOpCodeUnknown();
342 aVec.resize( nCount, aEntry);
343 } // if (aVec.size() < nCount)
345 FormulaOpCodeMapEntry aEntry;
346 for (size_t i=0; i < nCount; ++i)
348 size_t nIndex = static_cast< size_t >( aMap[i].nOff );
349 if (aVec.size() <= nIndex)
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 aEntry.Token.OpCode = getOpCodeUnknown();
356 aVec.resize( nIndex + 1, aEntry );
358 aEntry.Token.OpCode = aMap[i].eOp;
359 aVec[nIndex] = aEntry;
362 else
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. */
368 // Anything else but SPECIAL.
369 if ((nGroups & FormulaMapGroup::SEPARATORS) != 0)
371 static const sal_uInt16 aOpCodes[] = {
372 SC_OPCODE_OPEN,
373 SC_OPCODE_CLOSE,
374 SC_OPCODE_SEP,
376 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
378 if ((nGroups & FormulaMapGroup::ARRAY_SEPARATORS) != 0)
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
386 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
388 if ((nGroups & FormulaMapGroup::UNARY_OPERATORS) != 0)
390 // Due to the nature of the percent operator following its operand
391 // it isn't sorted into unary operators for compiler interna.
392 lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
393 // "+" can be used as unary operator too, push only if binary group is not set
394 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
395 lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
396 // regular unary operators
397 for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
399 switch (nOp)
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 break; // nothing,
406 default:
407 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
411 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
413 for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
415 switch (nOp)
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 break; // nothing,
422 default:
423 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
427 if ((nGroups & FormulaMapGroup::FUNCTIONS) != 0)
429 // Function names are not consecutive, skip the gaps between
430 // functions with no parameter, functions with 1 parameter
431 lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_NO_PAR, ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
432 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
442 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
443 // functions with 2 or more parameters.
444 for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
446 switch (nOp)
448 // NO_NAME is in SPECIAL.
449 case SC_OPCODE_NO_NAME :
450 break; // nothing,
451 default:
452 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
455 // If AddIn functions are present in this mapping, use them, and only those.
456 if (hasExternals())
458 for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
460 FormulaOpCodeMapEntry aEntry;
461 aEntry.Name = (*it).first;
462 aEntry.Token.Data <<= ::rtl::OUString( (*it).second);
463 aEntry.Token.OpCode = ocExternal;
464 aVec.push_back( aEntry);
467 else
469 _rCompiler.fillAddInToken(aVec,isEnglish());
473 const FormulaOpCodeMapEntry* pRet = aVec.empty() ? 0 : &aVec[0];
474 return uno::Sequence< FormulaOpCodeMapEntry >(pRet, aVec.size());
476 //-----------------------------------------------------------------------------
478 void FormulaCompiler::OpCodeMap::putOpCode( const String & rStr, const OpCode eOp )
480 DBG_ASSERT( 0 < eOp && sal_uInt16(eOp) < mnSymbols, "OpCodeMap::putOpCode: OpCode out of range");
481 if (0 < eOp && sal_uInt16(eOp) < mnSymbols)
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 mpTable[eOp] = rStr;
492 mpHashMap->insert( OpCodeHashMap::value_type( rStr, eOp));
495 // -----------------------------------------------------------------------------
496 // class FormulaCompiler
497 // -----------------------------------------------------------------------------
498 DBG_NAME(FormulaCompiler)
499 FormulaCompiler::FormulaCompiler(FormulaTokenArray& _rArr)
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 bIgnoreErrors( false )
513 DBG_CTOR(FormulaCompiler,NULL);
515 FormulaCompiler::FormulaCompiler()
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 bIgnoreErrors( false )
529 DBG_CTOR(FormulaCompiler,NULL);
531 FormulaCompiler::~FormulaCompiler()
533 DBG_DTOR(FormulaCompiler,NULL);
536 FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
538 FormulaCompiler::OpCodeMapPtr xMap;
539 using namespace sheet;
540 switch (nLanguage)
542 case FormulaLanguage::ODFF :
543 if (!mxSymbolsODFF)
544 InitSymbolsODFF();
545 xMap = mxSymbolsODFF;
546 break;
547 case FormulaLanguage::ODF_11 :
548 if (!mxSymbolsPODF)
549 InitSymbolsPODF();
550 xMap = mxSymbolsPODF;
551 break;
552 case FormulaLanguage::ENGLISH :
553 if (!mxSymbolsEnglish)
554 InitSymbolsEnglish();
555 xMap = mxSymbolsEnglish;
556 break;
557 case FormulaLanguage::NATIVE :
558 if (!mxSymbolsNative)
559 InitSymbolsNative();
560 xMap = mxSymbolsNative;
561 break;
562 case FormulaLanguage::XL_ENGLISH:
563 if (!mxSymbolsEnglishXL)
564 InitSymbolsEnglishXL();
565 xMap = mxSymbolsEnglishXL;
566 break;
567 default:
568 ; // nothing, NULL map returned
570 return xMap;
572 // -----------------------------------------------------------------------------
574 String FormulaCompiler::FindAddInFunction( const String& /*rUpperName*/, bool /*bLocalFirst*/ ) const
576 return String();
578 // -----------------------------------------------------------------------------
579 FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
580 const uno::Sequence<
581 const sheet::FormulaOpCodeMapEntry > & rMapping,
582 bool bEnglish )
584 using sheet::FormulaOpCodeMapEntry;
585 // Filter / API maps are never Core
586 NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1,false, FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(FormulaGrammar::GRAM_EXTERNAL, bEnglish),FormulaGrammar::CONV_UNSPECIFIED)));
587 FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
588 FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
589 for ( ; pArr2 < pStop; ++pArr2)
591 OpCode eOp = OpCode(pArr2->Token.OpCode);
592 if (eOp != ocExternal)
593 xMap->putOpCode( pArr2->Name, eOp);
594 else
596 ::rtl::OUString aExternalName;
597 if (pArr2->Token.Data >>= aExternalName)
598 xMap->putExternal( pArr2->Name, aExternalName);
599 else
601 SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
605 return xMap;
608 // -----------------------------------------------------------------------------
609 void lcl_fillNativeSymbols(FormulaCompiler::NonConstOpCodeMapPtr& _xMap,bool _destroy = false)
611 static FormulaCompiler::NonConstOpCodeMapPtr s_SymbolMap;
612 if ( _destroy )
614 s_SymbolMap.reset();
615 } // if ( _destroy )
616 else if ( !s_SymbolMap.get() )
618 // Core
619 s_SymbolMap.reset( new FormulaCompiler::OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
620 OModuleClient aModuleClient;
621 OpCodeList aOpCodeListNative( RID_STRLIST_FUNCTION_NAMES, s_SymbolMap );
622 // No AddInMap for native core mapping.
623 } // if ( !s_SymbolMap.get() )
624 _xMap = s_SymbolMap;
626 // -----------------------------------------------------------------------------
627 const String& FormulaCompiler::GetNativeSymbol( OpCode eOp )
629 NonConstOpCodeMapPtr xSymbolsNative;
630 lcl_fillNativeSymbols(xSymbolsNative);
631 return xSymbolsNative->getSymbol( eOp );
633 // -----------------------------------------------------------------------------
634 void FormulaCompiler::InitSymbolsNative() const
636 lcl_fillNativeSymbols(mxSymbolsNative);
638 // -----------------------------------------------------------------------------
639 void FormulaCompiler::InitSymbolsEnglish() const
641 static NonConstOpCodeMapPtr s_sSymbol;
642 if ( !s_sSymbol.get() )
643 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
644 mxSymbolsEnglish = s_sSymbol;
646 // -----------------------------------------------------------------------------
647 void FormulaCompiler::InitSymbolsPODF() const
649 static NonConstOpCodeMapPtr s_sSymbol;
650 if ( !s_sSymbol.get() )
651 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_PODF,s_sSymbol);
652 mxSymbolsPODF = s_sSymbol;
654 // -----------------------------------------------------------------------------
655 void FormulaCompiler::InitSymbolsODFF() const
657 static NonConstOpCodeMapPtr s_sSymbol;
658 if ( !s_sSymbol.get() )
659 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF,FormulaGrammar::GRAM_ODFF,s_sSymbol);
660 mxSymbolsODFF = s_sSymbol;
662 // -----------------------------------------------------------------------------
663 void FormulaCompiler::InitSymbolsEnglishXL() const
665 static NonConstOpCodeMapPtr s_sSymbol;
666 if ( !s_sSymbol.get() )
667 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
668 mxSymbolsEnglishXL = s_sSymbol;
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 mxSymbolsEnglishXL->putOpCode(rtl::OUString(','), ocSep);
674 mxSymbolsEnglishXL->putOpCode(rtl::OUString(','), ocArrayColSep);
675 mxSymbolsEnglishXL->putOpCode(rtl::OUString(';'), ocArrayRowSep);
678 // -----------------------------------------------------------------------------
679 void FormulaCompiler::loadSymbols(sal_uInt16 _nSymbols,FormulaGrammar::Grammar _eGrammar,NonConstOpCodeMapPtr& _xMap) const
681 if ( !_xMap.get() )
683 // not Core
684 _xMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, _eGrammar != FormulaGrammar::GRAM_ODFF, _eGrammar ));
685 OModuleClient aModuleClient;
686 OpCodeList aOpCodeList( _nSymbols, _xMap );
688 fillFromAddInMap( _xMap, _eGrammar);
689 // Fill from collection for AddIns not already present.
690 if ( FormulaGrammar::GRAM_ENGLISH != _eGrammar )
691 fillFromAddInCollectionUpperName( _xMap);
692 else
693 fillFromAddInCollectionEnglishName( _xMap);
696 // -----------------------------------------------------------------------------
697 void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const
700 // -----------------------------------------------------------------------------
701 void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const
704 // -----------------------------------------------------------------------------
705 void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const
708 // -----------------------------------------------------------------------------
709 OpCode FormulaCompiler::GetEnglishOpCode( const String& rName ) const
711 FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap(sheet::FormulaLanguage::ENGLISH);
713 formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) );
714 bool bFound = (iLook != xMap->getHashMap()->end());
715 return bFound ? (*iLook).second : OpCode(ocNone);
718 bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
720 bool bRet = false;
721 switch (eOp)
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 bRet = true;
739 break;
740 default:
741 bRet = false;
742 break;
744 return bRet;
747 // Remove quotes, escaped quotes are unescaped.
748 bool FormulaCompiler::DeQuote( String& rStr )
750 xub_StrLen nLen = rStr.Len();
751 if ( nLen > 1 && rStr.GetChar(0) == '\'' && rStr.GetChar( nLen-1 ) == '\'' )
753 rStr.Erase( nLen-1, 1 );
754 rStr.Erase( 0, 1 );
755 xub_StrLen nPos = 0;
756 while ( (nPos = rStr.SearchAscii( "\\\'", nPos)) != STRING_NOTFOUND )
758 rStr.Erase( nPos, 1 );
759 ++nPos;
761 return true;
763 return false;
765 // -----------------------------------------------------------------------------
766 void FormulaCompiler::fillAddInToken(::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,bool /*_bIsEnglish*/) const
769 // -----------------------------------------------------------------------------
770 bool FormulaCompiler::IsMatrixFunction(OpCode _eOpCode)
772 switch ( _eOpCode )
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 return true;
785 default:
787 // added to avoid warnings
790 return false;
793 // -----------------------------------------------------------------------------
794 FormulaCompiler::OpCodeMap::~OpCodeMap()
796 delete mpReverseExternalHashMap;
797 delete mpExternalHashMap;
798 delete [] mpTable;
799 delete mpHashMap;
801 // -----------------------------------------------------------------------------
802 void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap& r )
804 delete mpHashMap;
805 mpHashMap = new OpCodeHashMap(mnSymbols);
807 sal_uInt16 n = r.getSymbolCount();
808 for (sal_uInt16 i = 0; i < n; ++i)
810 OpCode eOp = OpCode(i);
811 const String& rSymbol = r.getSymbol(eOp);
812 putOpCode(rSymbol, eOp);
815 // TODO: maybe copy the external maps too?
817 // -----------------------------------------------------------------------------
819 sal_uInt16 FormulaCompiler::GetErrorConstant( const String& rName )
821 sal_uInt16 nError = 0;
822 OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
823 if (iLook != mxSymbols->getHashMap()->end())
825 switch ((*iLook).second)
827 // Not all may make sense in a formula, but these we know as
828 // opcodes.
829 case ocErrNull:
830 nError = errNoCode;
831 break;
832 case ocErrDivZero:
833 nError = errDivisionByZero;
834 break;
835 case ocErrValue:
836 nError = errNoValue;
837 break;
838 case ocErrRef:
839 nError = errNoRef;
840 break;
841 case ocErrName:
842 nError = errNoName;
843 break;
844 case ocErrNum:
845 nError = errIllegalFPOperation;
846 break;
847 case ocErrNA:
848 nError = NOTAVAILABLE;
849 break;
850 default:
851 ; // nothing
854 return nError;
858 void FormulaCompiler::AppendErrorConstant( rtl::OUStringBuffer& rBuffer, sal_uInt16 nError )
860 OpCode eOp;
861 switch (nError)
863 default:
864 case errNoCode:
865 eOp = ocErrNull;
866 break;
867 case errDivisionByZero:
868 eOp = ocErrDivZero;
869 break;
870 case errNoValue:
871 eOp = ocErrValue;
872 break;
873 case errNoRef:
874 eOp = ocErrRef;
875 break;
876 case errNoName:
877 eOp = ocErrName;
878 break;
879 case errIllegalFPOperation:
880 eOp = ocErrNum;
881 break;
882 case NOTAVAILABLE:
883 eOp = ocErrNA;
884 break;
886 rBuffer.append( mxSymbols->getSymbol( eOp));
889 // -----------------------------------------------------------------------------
890 sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
892 static const sal_Int32 kOpCodeUnknown = -1;
893 return kOpCodeUnknown;
895 // -----------------------------------------------------------------------------
896 bool FormulaCompiler::GetToken()
898 static const short nRecursionMax = 42;
899 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
900 if ( nRecursion > nRecursionMax )
902 SetError( errStackOverflow );
903 mpToken = new FormulaByteToken( ocStop );
904 return false;
906 if ( bAutoCorrect && !pStack )
907 { // don't merge stacked subroutine code into entered formula
908 aCorrectedFormula += aCorrectedSymbol;
909 aCorrectedSymbol.Erase();
911 bool bStop = false;
912 if( pArr->GetCodeError() && !bIgnoreErrors )
913 bStop = true;
914 else
916 short nWasColRowName;
917 if ( pArr->nIndex
918 && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
919 nWasColRowName = 1;
920 else
921 nWasColRowName = 0;
922 mpToken = pArr->Next();
923 while( mpToken && mpToken->GetOpCode() == ocSpaces )
925 if ( nWasColRowName )
926 nWasColRowName++;
927 if ( bAutoCorrect && !pStack )
928 CreateStringFromToken( aCorrectedFormula, mpToken.get(), false );
929 mpToken = pArr->Next();
931 if ( bAutoCorrect && !pStack && mpToken )
932 CreateStringFromToken( aCorrectedSymbol, mpToken.get(), false );
933 if( !mpToken )
935 if( pStack )
937 PopTokenArray();
938 return GetToken();
940 else
941 bStop = true;
943 else
945 if ( nWasColRowName >= 2 && mpToken->GetOpCode() == ocColRowName )
946 { // convert an ocSpaces to ocIntersect in RPN
947 mpToken = new FormulaByteToken( ocIntersect );
948 pArr->nIndex--; // we advanced to the second ocColRowName, step back
952 if( bStop )
954 mpToken = new FormulaByteToken( ocStop );
955 return false;
957 if( mpToken->GetOpCode() == ocSubTotal )
958 glSubTotal = true;
959 else if ( mpToken->IsExternalRef() )
961 return HandleExternalReference(*mpToken);
963 else if( mpToken->GetOpCode() == ocName )
965 return HandleRange();
967 else if( mpToken->GetOpCode() == ocColRowName )
969 return HandleSingleRef();
971 else if( mpToken->GetOpCode() == ocDBArea )
973 return HandleDbData();
975 else if( mpToken->GetType() == svSingleRef )
977 pArr->nRefs++;
979 else if( mpToken->GetType() == svDoubleRef )
981 pArr->nRefs++;
983 return true;
985 //---------------------------------------------------------------------------
986 // RPN creation by recursion
987 //---------------------------------------------------------------------------
989 void FormulaCompiler::Factor()
991 if ( pArr->GetCodeError() && !bIgnoreErrors )
992 return;
994 CurrentFactor pFacToken( this );
996 OpCode eOp = mpToken->GetOpCode();
997 if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
998 eOp == ocDBArea
999 || (bCompileForFAP && ((eOp == ocName) || (eOp == ocDBArea)
1000 || (eOp == ocColRowName) || (eOp == ocBad)))
1003 PutCode( mpToken );
1004 eOp = NextToken();
1005 if( eOp == ocOpen )
1007 // PUSH( is an error that may be caused by an unknown function.
1008 SetError(
1009 ( mpToken->GetType() == svString
1010 || mpToken->GetType() == svSingleRef )
1011 ? errNoName : errOperatorExpected );
1012 if ( bAutoCorrect && !pStack )
1013 { // assume multiplication
1014 aCorrectedFormula += mxSymbols->getSymbol(ocMul);
1015 bCorrected = true;
1016 NextToken();
1017 eOp = Expression();
1018 if( eOp != ocClose )
1019 SetError(errPairExpected);
1020 else
1021 eOp = NextToken();
1025 else if( eOp == ocOpen )
1027 NextToken();
1028 eOp = Expression();
1029 while ((eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors))
1030 { // range list (A1;A2) converted to (A1~A2)
1031 pFacToken = mpToken;
1032 NextToken();
1033 eOp = Expression();
1034 // Do not ignore error here, regardless of bIgnoreErrors, otherwise
1035 // errors like =(1;) would also result in display of =(1~)
1036 if (!pArr->GetCodeError())
1038 pFacToken->NewOpCode( ocUnion,FormulaToken::PrivateAccess());
1039 PutCode( pFacToken);
1042 if (eOp != ocClose)
1043 SetError(errPairExpected);
1044 else
1045 eOp = NextToken();
1047 else
1049 if( nNumFmt == NUMBERFORMAT_UNDEFINED )
1050 nNumFmt = lcl_GetRetFormat( eOp );
1052 if ( IsOpCodeVolatile(eOp) )
1053 pArr->SetRecalcModeAlways();
1054 else
1056 switch( eOp )
1058 // Functions recalculated on every document load.
1059 // Don't use SetRecalcModeOnLoad() which would override
1060 // ModeAlways.
1061 case ocConvert :
1062 pArr->AddRecalcMode( RECALCMODE_ONLOAD );
1063 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 pArr->SetRecalcModeOnRefMove();
1070 break;
1071 case ocHyperLink :
1072 // cell with hyperlink needs to be calculated on load to
1073 // get its matrix result generated.
1074 pArr->SetRecalcModeOnLoad();
1075 pArr->SetHyperLink(true);
1076 break;
1077 default:
1078 ; // nothing
1081 if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
1083 pFacToken = mpToken;
1084 eOp = NextToken();
1085 if (eOp != ocOpen)
1087 SetError(errPairExpected);
1088 PutCode( pFacToken );
1090 else
1092 eOp = NextToken();
1093 if (eOp != ocClose)
1094 SetError(errPairExpected);
1095 PutCode(pFacToken);
1096 eOp = NextToken();
1099 // special cases NOT() and NEG()
1100 else if( eOp == ocNot || eOp == ocNeg
1101 || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
1103 pFacToken = mpToken;
1104 eOp = NextToken();
1105 if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot )
1106 nNumFmt = NUMBERFORMAT_LOGICAL;
1107 if (eOp == ocOpen)
1109 NextToken();
1110 eOp = Expression();
1112 else
1113 SetError(errPairExpected);
1114 if (eOp != ocClose)
1115 SetError(errPairExpected);
1116 else if ( !pArr->GetCodeError() )
1117 pFacToken->SetByte( 1 );
1118 PutCode( pFacToken );
1119 eOp = NextToken();
1121 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)))
1131 pFacToken = mpToken;
1132 OpCode eMyLastOp = eOp;
1133 eOp = NextToken();
1134 bool bNoParam = false;
1135 bool bBadName = false;
1136 if (eOp == ocOpen)
1138 eOp = NextToken();
1139 if (eOp == ocClose)
1140 bNoParam = true;
1141 else
1142 eOp = Expression();
1144 else if (eMyLastOp == ocBad)
1146 // Just a bad name, not an unknown function, no parameters, no
1147 // closing expected.
1148 bBadName = true;
1149 bNoParam = true;
1151 else
1152 SetError(errPairExpected);
1153 sal_uInt8 nSepCount = 0;
1154 if( !bNoParam )
1156 nSepCount++;
1157 while ( (eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors) )
1159 nSepCount++;
1160 NextToken();
1161 eOp = Expression();
1164 if (bBadName)
1165 ; // nothing, keep current token for return
1166 else if (eOp != ocClose)
1167 SetError(errPairExpected);
1168 else
1169 eOp = NextToken();
1170 // Jumps are just normal functions for the FunctionAutoPilot tree view
1171 if ( bCompileForFAP && pFacToken->GetType() == svJump )
1172 pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
1173 else
1174 pFacToken->SetByte( nSepCount );
1175 PutCode( pFacToken );
1177 else if (eOp == ocIf || eOp == ocChose)
1179 // the PC counters are -1
1180 pFacToken = mpToken;
1181 if ( eOp == ocIf )
1182 pFacToken->GetJump()[ 0 ] = 3; // if, else, behind
1183 else
1184 pFacToken->GetJump()[ 0 ] = MAXJUMPCOUNT+1;
1185 eOp = NextToken();
1186 if (eOp == ocOpen)
1188 NextToken();
1189 eOp = Expression();
1191 else
1192 SetError(errPairExpected);
1193 short nJumpCount = 0;
1194 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 (pFacToken->GetOpCode() == ocIf ? 3 : MAXJUMPCOUNT);
1201 while ( (nJumpCount < (MAXJUMPCOUNT - 1)) && (eOp == ocSep)
1202 && (!pArr->GetCodeError() || bIgnoreErrors) )
1204 if ( ++nJumpCount <= nJumpMax )
1205 pFacToken->GetJump()[nJumpCount] = pc-1;
1206 NextToken();
1207 eOp = Expression();
1208 // ocSep or ocClose terminate the subexpression
1209 PutCode( mpToken );
1211 if (eOp != ocClose)
1212 SetError(errPairExpected);
1213 else
1215 eOp = NextToken();
1216 // always limit to nJumpMax, no arbitrary overwrites
1217 if ( ++nJumpCount <= nJumpMax )
1218 pFacToken->GetJump()[ nJumpCount ] = pc-1;
1219 if ((pFacToken->GetOpCode() == ocIf && (nJumpCount > 3)) ||
1220 (nJumpCount >= MAXJUMPCOUNT))
1221 SetError(errIllegalParameter);
1222 else
1223 pFacToken->GetJump()[ 0 ] = nJumpCount;
1226 else if ( eOp == ocMissing )
1228 PutCode( mpToken );
1229 eOp = NextToken();
1231 else if ( eOp == ocClose )
1233 SetError( errParameterExpected );
1235 else if ( eOp == ocSep )
1236 { // Subsequent ocSep
1237 SetError( errParameterExpected );
1238 if ( bAutoCorrect && !pStack )
1240 aCorrectedSymbol.Erase();
1241 bCorrected = true;
1244 else if ( mpToken->IsExternalRef() )
1246 PutCode(mpToken);
1247 eOp = NextToken();
1249 else
1251 SetError( errUnknownToken );
1252 if ( bAutoCorrect && !pStack )
1254 if ( eOp == ocStop )
1255 { // trailing operator w/o operand
1256 xub_StrLen nLen = aCorrectedFormula.Len();
1257 if ( nLen )
1258 aCorrectedFormula.Erase( nLen - 1 );
1259 aCorrectedSymbol.Erase();
1260 bCorrected = true;
1267 //---------------------------------------------------------------------------
1269 void FormulaCompiler::RangeLine()
1271 Factor();
1272 while (mpToken->GetOpCode() == ocRange)
1274 FormulaToken** pCode1 = pCode - 1;
1275 FormulaTokenRef p = mpToken;
1276 NextToken();
1277 Factor();
1278 FormulaToken** pCode2 = pCode - 1;
1279 if (!MergeRangeReference( pCode1, pCode2))
1280 PutCode(p);
1284 //---------------------------------------------------------------------------
1286 void FormulaCompiler::IntersectionLine()
1288 RangeLine();
1289 while (mpToken->GetOpCode() == ocIntersect)
1291 FormulaTokenRef p = mpToken;
1292 NextToken();
1293 RangeLine();
1294 PutCode(p);
1298 //---------------------------------------------------------------------------
1300 void FormulaCompiler::UnionLine()
1302 IntersectionLine();
1303 while (mpToken->GetOpCode() == ocUnion)
1305 FormulaTokenRef p = mpToken;
1306 NextToken();
1307 IntersectionLine();
1308 PutCode(p);
1312 //---------------------------------------------------------------------------
1314 void FormulaCompiler::UnaryLine()
1316 if( mpToken->GetOpCode() == ocAdd )
1317 GetToken();
1318 else if (SC_OPCODE_START_UN_OP <= mpToken->GetOpCode() &&
1319 mpToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
1321 FormulaTokenRef p = mpToken;
1322 NextToken();
1323 UnaryLine();
1324 PutCode( p );
1326 else
1327 UnionLine();
1330 //---------------------------------------------------------------------------
1332 void FormulaCompiler::PostOpLine()
1334 UnaryLine();
1335 while ( mpToken->GetOpCode() == ocPercentSign )
1336 { // this operator _follows_ its operand
1337 PutCode( mpToken );
1338 NextToken();
1342 //---------------------------------------------------------------------------
1344 void FormulaCompiler::PowLine()
1346 PostOpLine();
1347 while (mpToken->GetOpCode() == ocPow)
1349 FormulaTokenRef p = mpToken;
1350 NextToken();
1351 PostOpLine();
1352 PutCode(p);
1356 //---------------------------------------------------------------------------
1358 void FormulaCompiler::MulDivLine()
1360 PowLine();
1361 while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv)
1363 FormulaTokenRef p = mpToken;
1364 NextToken();
1365 PowLine();
1366 PutCode(p);
1370 //---------------------------------------------------------------------------
1372 void FormulaCompiler::AddSubLine()
1374 MulDivLine();
1375 while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub)
1377 FormulaTokenRef p = mpToken;
1378 NextToken();
1379 MulDivLine();
1380 PutCode(p);
1384 //---------------------------------------------------------------------------
1386 void FormulaCompiler::ConcatLine()
1388 AddSubLine();
1389 while (mpToken->GetOpCode() == ocAmpersand)
1391 FormulaTokenRef p = mpToken;
1392 NextToken();
1393 AddSubLine();
1394 PutCode(p);
1398 //---------------------------------------------------------------------------
1400 void FormulaCompiler::CompareLine()
1402 ConcatLine();
1403 while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual)
1405 FormulaTokenRef p = mpToken;
1406 NextToken();
1407 ConcatLine();
1408 PutCode(p);
1412 //---------------------------------------------------------------------------
1414 void FormulaCompiler::NotLine()
1416 CompareLine();
1417 while (mpToken->GetOpCode() == ocNot)
1419 FormulaTokenRef p = mpToken;
1420 NextToken();
1421 CompareLine();
1422 PutCode(p);
1426 //---------------------------------------------------------------------------
1428 OpCode FormulaCompiler::Expression()
1430 static const short nRecursionMax = 42;
1431 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
1432 if ( nRecursion > nRecursionMax )
1434 SetError( errStackOverflow );
1435 return ocStop; //! generate token instead?
1437 NotLine();
1438 while (mpToken->GetOpCode() == ocAnd || mpToken->GetOpCode() == ocOr)
1440 FormulaTokenRef p = mpToken;
1441 mpToken->SetByte( 2 ); // 2 parameters!
1442 NextToken();
1443 NotLine();
1444 PutCode(p);
1446 return mpToken->GetOpCode();
1448 // -----------------------------------------------------------------------------
1449 void FormulaCompiler::SetError(sal_uInt16 /*nError*/)
1452 // -----------------------------------------------------------------------------
1453 FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/, bool /*bReuseDoubleRef*/ )
1455 return FormulaTokenRef();
1457 // -----------------------------------------------------------------------------
1458 bool FormulaCompiler::MergeRangeReference(FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
1460 FormulaToken *p1, *p2;
1461 if (pc < 2 || !pCode1 || !pCode2 ||
1462 (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
1463 ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
1464 return false;
1466 FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
1467 if (!p)
1468 return false;
1470 p->IncRef();
1471 p1->DecRef();
1472 p2->DecRef();
1473 *pCode1 = p.get();
1474 --pCode, --pc;
1475 pArr->nRefs--;
1477 return true;
1479 // -----------------------------------------------------------------------------
1480 bool FormulaCompiler::CompileTokenArray()
1482 glSubTotal = false;
1483 bCorrected = false;
1484 if( !pArr->GetCodeError() || bIgnoreErrors )
1486 if ( bAutoCorrect )
1488 aCorrectedFormula.Erase();
1489 aCorrectedSymbol.Erase();
1491 pArr->nRefs = 0; // count from start
1492 pArr->DelRPN();
1493 pStack = NULL;
1494 FormulaToken* pData[ MAXCODE ];
1495 pCode = pData;
1496 bool bWasForced = pArr->IsRecalcModeForced();
1497 if ( bWasForced )
1499 if ( bAutoCorrect )
1500 aCorrectedFormula = '=';
1502 pArr->ClearRecalcMode();
1503 pArr->Reset();
1504 eLastOp = ocOpen;
1505 pc = 0;
1506 NextToken();
1507 OpCode eOp = Expression();
1508 // Some trailing garbage that doesn't form an expression?
1509 if (eOp != ocStop)
1510 SetError( errOperatorExpected);
1512 sal_uInt16 nErrorBeforePop = pArr->GetCodeError();
1514 while( pStack )
1515 PopTokenArray();
1516 if( pc )
1518 pArr->pRPN = new FormulaToken*[ pc ];
1519 pArr->nRPN = pc;
1520 memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
1523 // once an error, always an error
1524 if( !pArr->GetCodeError() && nErrorBeforePop )
1525 pArr->SetCodeError( nErrorBeforePop);
1527 if( pArr->GetCodeError() && !bIgnoreErrors )
1529 pArr->DelRPN();
1530 pArr->SetHyperLink(false);
1533 if ( bWasForced )
1534 pArr->SetRecalcModeForced();
1536 if( nNumFmt == NUMBERFORMAT_UNDEFINED )
1537 nNumFmt = NUMBERFORMAT_NUMBER;
1538 return glSubTotal;
1540 // -----------------------------------------------------------------------------
1541 void FormulaCompiler::PopTokenArray()
1543 if( pStack )
1545 FormulaArrayStack* p = pStack;
1546 pStack = p->pNext;
1547 p->pArr->nRefs = sal::static_int_cast<short>( p->pArr->nRefs + pArr->nRefs );
1548 // obtain special RecalcMode from SharedFormula
1549 if ( pArr->IsRecalcModeAlways() )
1550 p->pArr->SetRecalcModeAlways();
1551 else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
1552 p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
1553 p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
1554 if( p->bTemp )
1555 delete pArr;
1556 pArr = p->pArr;
1557 delete p;
1560 // -----------------------------------------------------------------------------
1561 void FormulaCompiler::CreateStringFromTokenArray( String& rFormula )
1563 rtl::OUStringBuffer aBuffer( pArr->GetLen() * 5 );
1564 CreateStringFromTokenArray( aBuffer );
1565 rFormula = aBuffer.makeStringAndClear();
1568 void FormulaCompiler::CreateStringFromTokenArray( rtl::OUStringBuffer& rBuffer )
1570 rBuffer.setLength(0);
1571 if( !pArr->GetLen() )
1572 return;
1574 FormulaTokenArray* pSaveArr = pArr;
1575 bool bODFF = FormulaGrammar::isODFF( meGrammar);
1576 if (bODFF || FormulaGrammar::isPODF( meGrammar) )
1578 // Scan token array for missing args and re-write if present.
1579 MissingConvention aConv( bODFF);
1580 if (pArr->NeedsPofRewrite( aConv))
1581 pArr = pArr->RewriteMissingToPof( aConv);
1584 // At least one character per token, plus some are references, some are
1585 // function names, some are numbers, ...
1586 rBuffer.ensureCapacity( pArr->GetLen() * 5 );
1588 if ( pArr->IsRecalcModeForced() )
1589 rBuffer.append(sal_Unicode('='));
1590 FormulaToken* t = pArr->First();
1591 while( t )
1592 t = CreateStringFromToken( rBuffer, t, true );
1594 if (pSaveArr != pArr)
1596 delete pArr;
1597 pArr = pSaveArr;
1600 // -----------------------------------------------------------------------------
1601 FormulaToken* FormulaCompiler::CreateStringFromToken( String& rFormula, FormulaToken* pTokenP,bool bAllowArrAdvance )
1603 rtl::OUStringBuffer aBuffer;
1604 FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
1605 rFormula += aBuffer.makeStringAndClear();
1606 return p;
1609 FormulaToken* FormulaCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP,bool bAllowArrAdvance )
1611 bool bNext = true;
1612 bool bSpaces = false;
1613 FormulaToken* t = pTokenP;
1614 OpCode eOp = t->GetOpCode();
1615 if( eOp >= ocAnd && eOp <= ocOr )
1617 // AND, OR infix?
1618 if ( bAllowArrAdvance )
1619 t = pArr->Next();
1620 else
1621 t = pArr->PeekNext();
1622 bNext = false;
1623 bSpaces = ( !t || t->GetOpCode() != ocOpen );
1625 if( bSpaces )
1626 rBuffer.append(sal_Unicode(' '));
1628 if( eOp == ocSpaces )
1630 bool bIntersectionOp = mxSymbols->isODFF();
1631 if (bIntersectionOp)
1633 const FormulaToken* p = pArr->PeekPrevNoSpaces();
1634 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1635 if (bIntersectionOp)
1637 p = pArr->PeekNextNoSpaces();
1638 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1641 if (bIntersectionOp)
1642 rBuffer.appendAscii( "!!");
1643 else
1645 // most times it's just one blank
1646 sal_uInt8 n = t->GetByte();
1647 for ( sal_uInt8 j=0; j<n; ++j )
1649 rBuffer.append(sal_Unicode(' '));
1653 else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1654 rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
1655 else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount()) // Keyword:
1656 rBuffer.append(mxSymbols->getSymbol(eOp));
1657 else
1659 SAL_WARN( "formula.core","unknown OpCode");
1660 rBuffer.append(GetNativeSymbol( ocErrName ));
1662 if( bNext )
1664 if (t->IsExternalRef())
1666 CreateStringFromExternal(rBuffer, pTokenP);
1668 else
1670 switch( t->GetType() )
1672 case svDouble:
1673 AppendDouble( rBuffer, t->GetDouble() );
1674 break;
1676 case svString:
1677 if( eOp == ocBad || eOp == ocStringXML )
1678 rBuffer.append(t->GetString());
1679 else
1680 AppendString( rBuffer, t->GetString() );
1681 break;
1682 case svSingleRef:
1683 CreateStringFromSingleRef(rBuffer,t);
1684 break;
1685 case svDoubleRef:
1686 CreateStringFromDoubleRef(rBuffer,t);
1687 break;
1688 case svMatrix:
1689 CreateStringFromMatrix( rBuffer, t );
1690 break;
1692 case svIndex:
1693 CreateStringFromIndex( rBuffer, t );
1694 break;
1695 case svExternal:
1697 // mapped or translated name of AddIns
1698 String aAddIn( t->GetExternal() );
1699 bool bMapped = mxSymbols->isPODF(); // ODF 1.1 directly uses programmatical name
1700 if (!bMapped && mxSymbols->hasExternals())
1702 ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
1703 if (iLook != mxSymbols->getReverseExternalHashMap()->end())
1705 aAddIn = (*iLook).second;
1706 bMapped = true;
1709 if (!bMapped && !mxSymbols->isEnglish())
1710 LocalizeString( aAddIn );
1711 rBuffer.append(aAddIn);
1713 break;
1714 case svError:
1715 AppendErrorConstant( rBuffer, t->GetError());
1716 break;
1717 case svByte:
1718 case svJump:
1719 case svFAP:
1720 case svMissing:
1721 case svSep:
1722 break; // Opcodes
1723 default:
1724 OSL_FAIL("FormulaCompiler:: GetStringFromToken errUnknownVariable");
1725 } // of switch
1728 if( bSpaces )
1729 rBuffer.append(sal_Unicode(' '));
1730 if ( bAllowArrAdvance )
1732 if( bNext )
1733 t = pArr->Next();
1734 return t;
1736 return pTokenP;
1738 // -----------------------------------------------------------------------------
1740 void FormulaCompiler::AppendDouble( rtl::OUStringBuffer& rBuffer, double fVal )
1742 if ( mxSymbols->isEnglish() )
1744 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1745 rtl_math_StringFormat_Automatic,
1746 rtl_math_DecimalPlaces_Max, '.', true );
1748 else
1750 SvtSysLocale aSysLocale;
1751 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1752 rtl_math_StringFormat_Automatic,
1753 rtl_math_DecimalPlaces_Max,
1754 aSysLocale.GetLocaleDataPtr()->getNumDecimalSep()[0],
1755 true );
1758 // -----------------------------------------------------------------------------
1759 void FormulaCompiler::AppendBoolean( rtl::OUStringBuffer& rBuffer, bool bVal )
1761 rBuffer.append( mxSymbols->getSymbol(static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
1763 // -----------------------------------------------------------------------------
1764 void FormulaCompiler::AppendString( rtl::OUStringBuffer& rBuffer, const String & rStr )
1766 rBuffer.append(sal_Unicode('"'));
1767 if ( lcl_UnicodeStrChr( rStr.GetBuffer(), '"' ) == NULL )
1768 rBuffer.append( rStr );
1769 else
1771 String aStr( rStr );
1772 aStr.SearchAndReplaceAll( rtl::OUString('"'), rtl::OUString("\"\"") );
1773 rBuffer.append(aStr);
1775 rBuffer.append(sal_Unicode('"'));
1778 void FormulaCompiler::UpdateSeparatorsNative(
1779 const rtl::OUString& rSep, const rtl::OUString& rArrayColSep, const rtl::OUString& rArrayRowSep )
1781 NonConstOpCodeMapPtr xSymbolsNative;
1782 lcl_fillNativeSymbols(xSymbolsNative);
1783 xSymbolsNative->putOpCode(rSep, ocSep);
1784 xSymbolsNative->putOpCode(rArrayColSep, ocArrayColSep);
1785 xSymbolsNative->putOpCode(rArrayRowSep, ocArrayRowSep);
1788 void FormulaCompiler::ResetNativeSymbols()
1790 NonConstOpCodeMapPtr xSymbolsNative;
1791 lcl_fillNativeSymbols(xSymbolsNative, true);
1792 lcl_fillNativeSymbols(xSymbolsNative);
1795 void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr& xMap )
1797 NonConstOpCodeMapPtr xSymbolsNative;
1798 lcl_fillNativeSymbols(xSymbolsNative);
1799 xSymbolsNative->copyFrom(*xMap);
1802 // -----------------------------------------------------------------------------
1803 OpCode FormulaCompiler::NextToken()
1805 if( !GetToken() )
1806 return ocStop;
1807 OpCode eOp = mpToken->GetOpCode();
1808 // There must be an operator before a push
1809 if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
1810 !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
1811 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
1812 SetError(errOperatorExpected);
1813 // Operator and Plus => operator
1814 if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
1815 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
1816 eOp = NextToken();
1817 else
1819 // Before an operator there must not be another operator, with the
1820 // exception of AND and OR.
1821 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)))
1826 SetError(errVariableExpected);
1827 if ( bAutoCorrect && !pStack )
1829 if ( eOp == eLastOp || eLastOp == ocOpen )
1830 { // throw away duplicated operator
1831 aCorrectedSymbol.Erase();
1832 bCorrected = true;
1834 else
1836 xub_StrLen nPos = aCorrectedFormula.Len();
1837 if ( nPos )
1839 nPos--;
1840 sal_Unicode c = aCorrectedFormula.GetChar( nPos );
1841 switch ( eOp )
1842 { // swap operators
1843 case ocGreater:
1844 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
1845 { // >= instead of =>
1846 aCorrectedFormula.SetChar( nPos,
1847 mxSymbols->getSymbol(ocGreater).GetChar(0) );
1848 aCorrectedSymbol = c;
1849 bCorrected = true;
1851 break;
1852 case ocLess:
1853 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
1854 { // <= instead of =<
1855 aCorrectedFormula.SetChar( nPos,
1856 mxSymbols->getSymbol(ocLess).GetChar(0) );
1857 aCorrectedSymbol = c;
1858 bCorrected = true;
1860 else if ( c == mxSymbols->getSymbol(ocGreater).GetChar(0) )
1861 { // <> instead of ><
1862 aCorrectedFormula.SetChar( nPos,
1863 mxSymbols->getSymbol(ocLess).GetChar(0) );
1864 aCorrectedSymbol = c;
1865 bCorrected = true;
1867 break;
1868 case ocMul:
1869 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
1870 { // *- instead of -*
1871 aCorrectedFormula.SetChar( nPos,
1872 mxSymbols->getSymbol(ocMul).GetChar(0) );
1873 aCorrectedSymbol = c;
1874 bCorrected = true;
1876 break;
1877 case ocDiv:
1878 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
1879 { // /- instead of -/
1880 aCorrectedFormula.SetChar( nPos,
1881 mxSymbols->getSymbol(ocDiv).GetChar(0) );
1882 aCorrectedSymbol = c;
1883 bCorrected = true;
1885 break;
1886 default:
1887 ; // nothing
1893 eLastOp = eOp;
1895 return eOp;
1897 void FormulaCompiler::PutCode( FormulaTokenRef& p )
1899 if( pc >= MAXCODE-1 )
1901 if ( pc == MAXCODE-1 )
1903 p = new FormulaByteToken( ocStop );
1904 p->IncRef();
1905 *pCode++ = p.get();
1906 ++pc;
1908 SetError(errCodeOverflow);
1909 return;
1911 if( pArr->GetCodeError() && !bCompileForFAP )
1912 return;
1913 ForceArrayOperator( p, pCurrentFactorToken);
1914 p->IncRef();
1915 *pCode++ = p.get();
1916 pc++;
1919 // -----------------------------------------------------------------------------
1920 bool FormulaCompiler::HandleExternalReference(const FormulaToken& /*_aToken*/)
1922 return true;
1924 // -----------------------------------------------------------------------------
1925 bool FormulaCompiler::HandleRange()
1927 return true;
1929 // -----------------------------------------------------------------------------
1930 bool FormulaCompiler::HandleSingleRef()
1932 return true;
1934 // -----------------------------------------------------------------------------
1935 bool FormulaCompiler::HandleDbData()
1937 return true;
1939 // -----------------------------------------------------------------------------
1940 void FormulaCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1943 // -----------------------------------------------------------------------------
1944 void FormulaCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1947 // -----------------------------------------------------------------------------
1948 void FormulaCompiler::CreateStringFromIndex(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1951 // -----------------------------------------------------------------------------
1952 void FormulaCompiler::CreateStringFromMatrix(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1955 // -----------------------------------------------------------------------------
1956 void FormulaCompiler::CreateStringFromExternal(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1959 // -----------------------------------------------------------------------------
1960 void FormulaCompiler::LocalizeString( String& /*rName*/ )
1963 void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
1965 if ( bAutoCorrect && !pStack )
1966 { // don't merge stacked subroutine code into entered formula
1967 aCorrectedFormula += aCorrectedSymbol;
1968 aCorrectedSymbol.Erase();
1970 FormulaArrayStack* p = new FormulaArrayStack;
1971 p->pNext = pStack;
1972 p->pArr = pArr;
1973 p->bTemp = bTemp;
1974 pStack = p;
1975 pArr = pa;
1978 // =============================================================================
1979 } // formula
1980 // =============================================================================
1982 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */