sync master with lastest vba changes
[ooovba.git] / formula / source / core / api / FormulaCompiler.cxx
blob72e6409d3c0f6aa3611380254d8e9271e7cca40e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tokenuno.hxx,v $
10 * $Revision: 1.4 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 #include "precompiled_formula.hxx"
31 #include "formula/FormulaCompiler.hxx"
32 #include "formula/errorcodes.hxx"
33 #include "formula/token.hxx"
34 #include "formula/tokenarray.hxx"
35 #include "core_resource.hxx"
36 #include "core_resource.hrc"
38 #include <svtools/zforlist.hxx>
39 #include <tools/rc.hxx>
40 #include <tools/rcid.h>
41 #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
42 #include <com/sun/star/sheet/FormulaMapGroup.hpp>
43 #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
44 #include <stdio.h>
46 // =============================================================================
47 namespace formula
49 // =============================================================================
50 using namespace ::com::sun::star;
52 static const sal_Char* pInternal[ 5 ] = { "GAME", "SPEW", "TTT", "STARCALCTEAM", "ANTWORT" };
54 // =============================================================================
55 namespace
57 // =============================================================================
58 class FormulaCompilerRecursionGuard
60 private:
61 short& rRecursion;
62 public:
63 FormulaCompilerRecursionGuard( short& rRec )
64 : rRecursion( rRec ) { ++rRecursion; }
65 ~FormulaCompilerRecursionGuard() { --rRecursion; }
68 short lcl_GetRetFormat( OpCode eOpCode )
70 switch (eOpCode)
72 case ocEqual:
73 case ocNotEqual:
74 case ocLess:
75 case ocGreater:
76 case ocLessEqual:
77 case ocGreaterEqual:
78 case ocAnd:
79 case ocOr:
80 case ocNot:
81 case ocTrue:
82 case ocFalse:
83 case ocIsEmpty:
84 case ocIsString:
85 case ocIsNonString:
86 case ocIsLogical:
87 case ocIsRef:
88 case ocIsValue:
89 case ocIsFormula:
90 case ocIsNA:
91 case ocIsErr:
92 case ocIsError:
93 case ocIsEven:
94 case ocIsOdd:
95 case ocExact:
96 return NUMBERFORMAT_LOGICAL;
97 case ocGetActDate:
98 case ocGetDate:
99 case ocEasterSunday :
100 return NUMBERFORMAT_DATE;
101 case ocGetActTime:
102 return NUMBERFORMAT_DATETIME;
103 case ocGetTime:
104 return NUMBERFORMAT_TIME;
105 case ocNPV:
106 case ocBW:
107 case ocDIA:
108 case ocGDA:
109 case ocGDA2:
110 case ocVBD:
111 case ocLIA:
112 case ocRMZ:
113 case ocZW:
114 case ocZinsZ:
115 case ocKapz:
116 case ocKumZinsZ:
117 case ocKumKapZ:
118 return NUMBERFORMAT_CURRENCY;
119 case ocZins:
120 case ocIRR:
121 case ocMIRR:
122 case ocZGZ:
123 case ocEffektiv:
124 case ocNominal:
125 case ocPercentSign:
126 return NUMBERFORMAT_PERCENT;
127 // case ocSum:
128 // case ocSumSQ:
129 // case ocProduct:
130 // case ocAverage:
131 // return -1;
132 default:
133 return NUMBERFORMAT_NUMBER;
135 return NUMBERFORMAT_NUMBER;
138 inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, USHORT nOpCode )
140 sheet::FormulaOpCodeMapEntry aEntry;
141 aEntry.Token.OpCode = nOpCode;
142 aEntry.Name = pTable[nOpCode];
143 rVec.push_back( aEntry);
146 void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, USHORT nOpCodeBeg, USHORT nOpCodeEnd )
148 for (USHORT nOpCode = nOpCodeBeg; nOpCode < nOpCodeEnd; ++nOpCode)
149 lclPushOpCodeMapEntry( rVec, pTable, nOpCode );
152 void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, const USHORT* pnOpCodes, size_t nCount )
154 for (const USHORT* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes)
155 lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes );
158 class OpCodeList : public Resource // temp object for resource
160 public:
162 OpCodeList( USHORT, FormulaCompiler::NonConstOpCodeMapPtr );
164 private:
165 bool getOpCodeString( String& rStr, USHORT nOp );
166 void putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, USHORT nOp );
168 private:
169 enum SeparatorType
171 SEMICOLON_BASE,
172 COMMA_BASE
174 SeparatorType meSepType;
177 OpCodeList::OpCodeList( USHORT nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap ) :
178 Resource( ResId(nRID,*ResourceManager::getResManager()) )
179 ,meSepType(SEMICOLON_BASE)
181 for (USHORT i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
183 String aOpStr;
184 if ( getOpCodeString(aOpStr, i) )
185 xMap->putOpCode(aOpStr, OpCode(i));
186 else
187 putDefaultOpCode(xMap, i);
190 FreeResource();
193 bool OpCodeList::getOpCodeString( String& rStr, USHORT nOp )
195 switch (nOp)
197 case SC_OPCODE_SEP:
199 if (meSepType == COMMA_BASE)
201 rStr = String::CreateFromAscii(",");
202 return true;
204 else if (meSepType == SEMICOLON_BASE)
206 rStr = String::CreateFromAscii(";");
207 return true;
210 break;
211 case SC_OPCODE_ARRAY_COL_SEP:
213 if (meSepType == COMMA_BASE)
215 rStr = String::CreateFromAscii(",");
216 return true;
218 else if (meSepType == SEMICOLON_BASE)
220 rStr = String::CreateFromAscii(";");
221 return true;
224 break;
225 case SC_OPCODE_ARRAY_ROW_SEP:
227 if (meSepType == COMMA_BASE)
229 rStr = String::CreateFromAscii(";");
230 return true;
232 else if (meSepType == SEMICOLON_BASE)
234 rStr = String::CreateFromAscii("|");
235 return true;
238 break;
241 return false;
244 void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, USHORT nOp )
246 ResId aRes(nOp,*ResourceManager::getResManager());
247 aRes.SetRT(RSC_STRING);
248 if (IsAvailableRes(aRes))
249 xMap->putOpCode(aRes, OpCode(nOp));
251 // -----------------------------------------------------------------------------
252 // static
253 const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,sal_Unicode c )
255 if ( !pStr )
256 return NULL;
257 while ( *pStr )
259 if ( *pStr == c )
260 return pStr;
261 pStr++;
263 return NULL;
265 // =============================================================================
266 } // empty
267 // =============================================================================
269 void FormulaCompiler::OpCodeMap::putExternal( const String & rSymbol, const String & rAddIn )
271 bool bOk = mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second;
272 if (bOk)
273 bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
274 DBG_ASSERT( bOk, "OpCodeMap::putExternal: symbol not inserted");
277 void FormulaCompiler::OpCodeMap::putExternalSoftly( const String & rSymbol, const String & rAddIn )
279 bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
280 if (bOk)
281 mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second;
283 uno::Sequence< sheet::FormulaToken > FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(const FormulaCompiler& _rCompiler,const uno::Sequence< ::rtl::OUString >& rNames ) const
285 const sal_Int32 nLen = rNames.getLength();
286 uno::Sequence< sheet::FormulaToken > aTokens( nLen);
287 sheet::FormulaToken* pToken = aTokens.getArray();
288 ::rtl::OUString const * pName = rNames.getConstArray();
289 ::rtl::OUString const * const pStop = pName + nLen;
290 for ( ; pName < pStop; ++pName, ++pToken)
292 OpCodeHashMap::const_iterator iLook( mpHashMap->find( *pName));
293 if (iLook != mpHashMap->end())
294 pToken->OpCode = (*iLook).second;
295 else
297 ::rtl::OUString aIntName;
298 if (hasExternals())
300 ExternalHashMap::const_iterator iExt( mpExternalHashMap->find( *pName));
301 if (iExt != mpExternalHashMap->end())
302 aIntName = (*iExt).second;
303 // Check for existence not needed here, only name-mapping is of
304 // interest.
306 if (!aIntName.getLength())
307 aIntName = _rCompiler.FindAddInFunction(*pName, !isEnglish()); // bLocalFirst=FALSE for english
308 if (!aIntName.getLength())
309 pToken->OpCode = getOpCodeUnknown();
310 else
312 pToken->OpCode = ocExternal;
313 pToken->Data <<= aIntName;
317 return aTokens;
319 uno::Sequence< sheet::FormulaOpCodeMapEntry > FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(const FormulaCompiler& _rCompiler,const sal_Int32 nGroups ) const
321 using namespace sheet;
323 // Unfortunately uno::Sequence can't grow without cumbersome reallocs. As
324 // we don't know in advance how many elements it will have we use a
325 // temporary vector to add elements and then copy to Sequence :-(
326 ::std::vector< FormulaOpCodeMapEntry > aVec;
328 if (nGroups == FormulaMapGroup::SPECIAL)
330 // Use specific order, keep in sync with
331 // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl
332 static const struct
334 sal_Int32 nOff;
335 OpCode eOp;
336 } aMap[] = {
337 { FormulaMapGroupSpecialOffset::PUSH , ocPush } ,
338 { FormulaMapGroupSpecialOffset::CALL , ocCall } ,
339 { FormulaMapGroupSpecialOffset::STOP , ocStop } ,
340 { FormulaMapGroupSpecialOffset::EXTERNAL , ocExternal } ,
341 { FormulaMapGroupSpecialOffset::NAME , ocName } ,
342 { FormulaMapGroupSpecialOffset::NO_NAME , ocNoName } ,
343 { FormulaMapGroupSpecialOffset::MISSING , ocMissing } ,
344 { FormulaMapGroupSpecialOffset::BAD , ocBad } ,
345 { FormulaMapGroupSpecialOffset::SPACES , ocSpaces } ,
346 { FormulaMapGroupSpecialOffset::MAT_REF , ocMatRef } ,
347 { FormulaMapGroupSpecialOffset::DB_AREA , ocDBArea } ,
348 { FormulaMapGroupSpecialOffset::MACRO , ocMacro } ,
349 { FormulaMapGroupSpecialOffset::COL_ROW_NAME , ocColRowName }
351 const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
352 // Preallocate vector elements.
353 if (aVec.size() < nCount)
355 FormulaOpCodeMapEntry aEntry;
356 aEntry.Token.OpCode = getOpCodeUnknown();
357 aVec.resize( nCount, aEntry);
358 } // if (aVec.size() < nCount)
360 FormulaOpCodeMapEntry aEntry;
361 for (size_t i=0; i < nCount; ++i)
363 size_t nIndex = static_cast< size_t >( aMap[i].nOff );
364 if (aVec.size() <= nIndex)
366 // The offsets really should be aligned with the size, so if
367 // the vector was preallocated above this code to resize it is
368 // just a measure in case the table isn't in sync with the API,
369 // usually it isn't executed.
370 aEntry.Token.OpCode = getOpCodeUnknown();
371 aVec.resize( nIndex + 1, aEntry );
373 aEntry.Token.OpCode = aMap[i].eOp;
374 aVec[nIndex] = aEntry;
377 else
379 /* FIXME: Once we support error constants in formulas we'll need a map
380 * group for that, e.g. FormulaMapGroup::ERROR_CONSTANTS, and fill
381 * SC_OPCODE_START_ERRORS to SC_OPCODE_STOP_ERRORS. */
383 // Anything else but SPECIAL.
384 if ((nGroups & FormulaMapGroup::SEPARATORS) != 0)
386 static const USHORT aOpCodes[] = {
387 SC_OPCODE_OPEN,
388 SC_OPCODE_CLOSE,
389 SC_OPCODE_SEP,
391 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
393 if ((nGroups & FormulaMapGroup::ARRAY_SEPARATORS) != 0)
395 static const USHORT aOpCodes[] = {
396 SC_OPCODE_ARRAY_OPEN,
397 SC_OPCODE_ARRAY_CLOSE,
398 SC_OPCODE_ARRAY_ROW_SEP,
399 SC_OPCODE_ARRAY_COL_SEP
401 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
403 if ((nGroups & FormulaMapGroup::UNARY_OPERATORS) != 0)
405 // Due to the nature of the percent operator following its operand
406 // it isn't sorted into unary operators for compiler interna.
407 lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
408 // "+" can be used as unary operator too, push only if binary group is not set
409 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
410 lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
411 // regular unary operators
412 for (USHORT nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
414 switch (nOp)
416 // NOT and NEG in fact are functions but for legacy reasons
417 // are sorted into unary operators for compiler interna.
418 case SC_OPCODE_NOT :
419 case SC_OPCODE_NEG :
420 break; // nothing,
421 default:
422 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
426 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
428 for (USHORT nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
430 switch (nOp)
432 // AND and OR in fact are functions but for legacy reasons
433 // are sorted into binary operators for compiler interna.
434 case SC_OPCODE_AND :
435 case SC_OPCODE_OR :
436 break; // nothing,
437 default:
438 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
442 if ((nGroups & FormulaMapGroup::FUNCTIONS) != 0)
444 // Function names are not consecutive, skip the gaps between
445 // functions with no parameter, functions with 1 parameter
446 lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_NO_PAR, ::std::min< USHORT >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
447 lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_1_PAR, ::std::min< USHORT >( SC_OPCODE_STOP_1_PAR, mnSymbols ) );
448 // Additional functions not within range of functions.
449 static const USHORT aOpCodes[] = {
450 SC_OPCODE_IF,
451 SC_OPCODE_CHOSE,
452 SC_OPCODE_AND,
453 SC_OPCODE_OR,
454 SC_OPCODE_NOT,
455 SC_OPCODE_NEG
457 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
458 // functions with 2 or more parameters.
459 for (USHORT nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
461 switch (nOp)
463 // NO_NAME is in SPECIAL.
464 case SC_OPCODE_NO_NAME :
465 break; // nothing,
466 default:
467 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
470 // If AddIn functions are present in this mapping, use them, and only those.
471 if (hasExternals())
473 for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
475 FormulaOpCodeMapEntry aEntry;
476 aEntry.Name = (*it).first;
477 aEntry.Token.Data <<= ::rtl::OUString( (*it).second);
478 aEntry.Token.OpCode = ocExternal;
479 aVec.push_back( aEntry);
482 else
484 //DBG_ASSERT( isCore(), "FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings: AddIn mapping from collection only implemented for core languages");
485 _rCompiler.fillAddInToken(aVec,isEnglish());
489 const FormulaOpCodeMapEntry* pRet = aVec.empty() ? 0 : &aVec[0];
490 return uno::Sequence< FormulaOpCodeMapEntry >(pRet, aVec.size());
492 //-----------------------------------------------------------------------------
494 void FormulaCompiler::OpCodeMap::putOpCode( const String & rStr, const OpCode eOp )
496 DBG_ASSERT( 0 < eOp && USHORT(eOp) < mnSymbols, "OpCodeMap::putOpCode: OpCode out of range");
497 if (0 < eOp && USHORT(eOp) < mnSymbols)
499 DBG_ASSERT( (mpTable[eOp].Len() == 0) || (mpTable[eOp] == rStr),
500 ByteString( "OpCodeMap::putOpCode: reusing OpCode ").
501 Append( ByteString::CreateFromInt32( sal_Int32( eOp))).Append( " (").
502 Append( ByteString( rStr, RTL_TEXTENCODING_ASCII_US)).Append( ')').GetBuffer());
503 mpTable[eOp] = rStr;
504 mpHashMap->insert( OpCodeHashMap::value_type( rStr, eOp));
507 // -----------------------------------------------------------------------------
508 // class FormulaCompiler
509 // -----------------------------------------------------------------------------
510 DBG_NAME(FormulaCompiler)
511 FormulaCompiler::FormulaCompiler(FormulaTokenArray& _rArr)
513 pArr( &_rArr ),
514 pExternalRef(NULL),
515 pStack( NULL ),
516 nRecursion(0),
517 nNumFmt( NUMBERFORMAT_UNDEFINED ),
518 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
519 bAutoCorrect( FALSE ),
520 bCorrected( FALSE ),
521 bCompileForFAP( FALSE ),
522 bIgnoreErrors( FALSE )
525 DBG_CTOR(FormulaCompiler,NULL);
527 FormulaCompiler::FormulaCompiler()
529 pArr( NULL ),
530 pExternalRef(NULL),
531 pStack( NULL ),
532 nRecursion(0),
533 nNumFmt( NUMBERFORMAT_UNDEFINED ),
534 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
535 bAutoCorrect( FALSE ),
536 bCorrected( FALSE ),
537 bCompileForFAP( FALSE ),
538 bIgnoreErrors( FALSE )
541 DBG_CTOR(FormulaCompiler,NULL);
543 FormulaCompiler::~FormulaCompiler()
545 DBG_DTOR(FormulaCompiler,NULL);
548 FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
550 FormulaCompiler::OpCodeMapPtr xMap;
551 using namespace sheet;
552 switch (nLanguage)
554 case FormulaLanguage::ODFF :
555 if (!mxSymbolsODFF)
556 InitSymbolsODFF();
557 xMap = mxSymbolsODFF;
558 break;
559 case FormulaLanguage::ODF_11 :
560 if (!mxSymbolsPODF)
561 InitSymbolsPODF();
562 xMap = mxSymbolsPODF;
563 break;
564 case FormulaLanguage::ENGLISH :
565 if (!mxSymbolsEnglish)
566 InitSymbolsEnglish();
567 xMap = mxSymbolsEnglish;
568 break;
569 case FormulaLanguage::NATIVE :
570 if (!mxSymbolsNative)
571 InitSymbolsNative();
572 xMap = mxSymbolsNative;
573 break;
574 case FormulaLanguage::XL_ENGLISH:
575 if (!mxSymbolsEnglishXL)
576 InitSymbolsEnglishXL();
577 xMap = mxSymbolsEnglishXL;
578 break;
579 default:
580 ; // nothing, NULL map returned
582 return xMap;
584 // -----------------------------------------------------------------------------
586 String FormulaCompiler::FindAddInFunction( const String& /*rUpperName*/, BOOL /*bLocalFirst*/ ) const
588 return String();
590 // -----------------------------------------------------------------------------
591 FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
592 const uno::Sequence<
593 const sheet::FormulaOpCodeMapEntry > & rMapping,
594 bool bEnglish )
596 using sheet::FormulaOpCodeMapEntry;
597 // Filter / API maps are never Core
598 NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1,false, FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(FormulaGrammar::GRAM_EXTERNAL, bEnglish),FormulaGrammar::CONV_UNSPECIFIED)));
599 FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
600 FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
601 for ( ; pArr2 < pStop; ++pArr2)
603 OpCode eOp = OpCode(pArr2->Token.OpCode);
604 if (eOp != ocExternal)
605 xMap->putOpCode( pArr2->Name, eOp);
606 else
608 ::rtl::OUString aExternalName;
609 if (pArr2->Token.Data >>= aExternalName)
610 xMap->putExternal( pArr2->Name, aExternalName);
611 else
613 DBG_ERRORFILE( "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
617 return xMap;
620 // -----------------------------------------------------------------------------
621 void lcl_fillNativeSymbols(FormulaCompiler::NonConstOpCodeMapPtr& _xMap,bool _destroy = false)
623 static FormulaCompiler::NonConstOpCodeMapPtr s_SymbolMap;
624 if ( _destroy )
626 s_SymbolMap.reset();
627 } // if ( _destroy )
628 else if ( !s_SymbolMap.get() )
630 // Core
631 s_SymbolMap.reset( new FormulaCompiler::OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
632 OModuleClient aModuleClient;
633 OpCodeList aOpCodeListNative( RID_STRLIST_FUNCTION_NAMES, s_SymbolMap );
634 // No AddInMap for native core mapping.
635 } // if ( !s_SymbolMap.get() )
636 _xMap = s_SymbolMap;
638 // -----------------------------------------------------------------------------
639 const String& FormulaCompiler::GetNativeSymbol( OpCode eOp )
641 NonConstOpCodeMapPtr xSymbolsNative;
642 lcl_fillNativeSymbols(xSymbolsNative);
643 return xSymbolsNative->getSymbol( eOp );
645 // -----------------------------------------------------------------------------
646 void FormulaCompiler::InitSymbolsNative() const
648 if (mxSymbolsNative.get())
649 return;
650 //! Experimental!
651 // Use English function names and separators instead of native in UI.
652 static const sal_Char aEnvVarName[] = "OOO_CALC_USE_ENGLISH_FORMULAS";
653 const char* pEnv = getenv( aEnvVarName);
654 if (pEnv && (*pEnv == 'Y' || *pEnv == 'y' || *pEnv == '1') )
656 fprintf( stderr, "%s=%s => UI uses English function names and separators in formulas.\n",
657 aEnvVarName, pEnv);
658 InitSymbolsEnglish();
659 mxSymbolsNative = mxSymbolsEnglish;
660 return;
662 static NonConstOpCodeMapPtr s_sSymbol;
663 if ( !s_sSymbol.get() )
664 lcl_fillNativeSymbols(s_sSymbol);
665 mxSymbolsNative = s_sSymbol;
667 // -----------------------------------------------------------------------------
668 void FormulaCompiler::InitSymbolsEnglish() const
670 static NonConstOpCodeMapPtr s_sSymbol;
671 if ( !s_sSymbol.get() )
672 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
673 mxSymbolsEnglish = s_sSymbol;
675 // -----------------------------------------------------------------------------
676 void FormulaCompiler::InitSymbolsPODF() const
678 static NonConstOpCodeMapPtr s_sSymbol;
679 if ( !s_sSymbol.get() )
680 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_PODF,s_sSymbol);
681 mxSymbolsPODF = s_sSymbol;
683 // -----------------------------------------------------------------------------
684 void FormulaCompiler::InitSymbolsODFF() const
686 static NonConstOpCodeMapPtr s_sSymbol;
687 if ( !s_sSymbol.get() )
688 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF,FormulaGrammar::GRAM_ODFF,s_sSymbol);
689 mxSymbolsODFF = s_sSymbol;
691 // -----------------------------------------------------------------------------
692 void FormulaCompiler::InitSymbolsEnglishXL() const
694 static NonConstOpCodeMapPtr s_sSymbol;
695 if ( !s_sSymbol.get() )
696 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
697 mxSymbolsEnglishXL = s_sSymbol;
699 // TODO: For now, just replace the separators to the Excel English
700 // variants. Later, if we want to properly map Excel functions with Calc
701 // functions, we'll need to do a little more work here.
702 mxSymbolsEnglishXL->putOpCode(sal_Unicode(','), ocSep);
703 mxSymbolsEnglishXL->putOpCode(sal_Unicode(','), ocArrayColSep);
704 mxSymbolsEnglishXL->putOpCode(sal_Unicode(';'), ocArrayRowSep);
707 // -----------------------------------------------------------------------------
708 void FormulaCompiler::loadSymbols(USHORT _nSymbols,FormulaGrammar::Grammar _eGrammar,NonConstOpCodeMapPtr& _xMap) const
710 if ( !_xMap.get() )
712 // not Core
713 _xMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, _eGrammar != FormulaGrammar::GRAM_ODFF, _eGrammar ));
714 OModuleClient aModuleClient;
715 OpCodeList aOpCodeList( _nSymbols, _xMap );
717 fillFromAddInMap( _xMap, _eGrammar);
718 // Fill from collection for AddIns not already present.
719 if ( FormulaGrammar::GRAM_ENGLISH != _eGrammar )
720 fillFromAddInCollectionUpperName( _xMap);
721 else
722 fillFromAddInCollectionEnglishName( _xMap);
725 // -----------------------------------------------------------------------------
726 void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const
729 // -----------------------------------------------------------------------------
730 void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const
733 // -----------------------------------------------------------------------------
734 void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const
737 // -----------------------------------------------------------------------------
738 OpCode FormulaCompiler::GetEnglishOpCode( const String& rName ) const
740 FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap(sheet::FormulaLanguage::ENGLISH);
742 formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) );
743 bool bFound = (iLook != xMap->getHashMap()->end());
744 return bFound ? (*iLook).second : OpCode(ocNone);
747 bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
749 switch (eOp)
751 // no parameters:
752 case ocRandom:
753 case ocGetActDate:
754 case ocGetActTime:
755 // one parameter:
756 case ocFormula:
757 case ocInfo:
758 // more than one parameters:
759 // ocIndirect/ocIndirectXL otherwise would have to do
760 // StopListening and StartListening on a reference for every
761 // interpreted value.
762 case ocIndirect:
763 case ocIndirectXL:
764 // ocOffset results in indirect references.
765 case ocOffset:
766 return true;
768 return false;
771 // Remove quotes, escaped quotes are unescaped.
772 BOOL FormulaCompiler::DeQuote( String& rStr )
774 xub_StrLen nLen = rStr.Len();
775 if ( nLen > 1 && rStr.GetChar(0) == '\'' && rStr.GetChar( nLen-1 ) == '\'' )
777 rStr.Erase( nLen-1, 1 );
778 rStr.Erase( 0, 1 );
779 xub_StrLen nPos = 0;
780 while ( (nPos = rStr.SearchAscii( "\\\'", nPos)) != STRING_NOTFOUND )
782 rStr.Erase( nPos, 1 );
783 ++nPos;
785 return TRUE;
787 return FALSE;
789 // -----------------------------------------------------------------------------
790 void FormulaCompiler::fillAddInToken(::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,bool /*_bIsEnglish*/) const
793 // -----------------------------------------------------------------------------
794 BOOL FormulaCompiler::IsMatrixFunction(OpCode _eOpCode)
796 switch ( _eOpCode )
798 case ocDde :
799 case ocGrowth :
800 case ocTrend :
801 case ocRKP :
802 case ocRGP :
803 case ocFrequency :
804 case ocMatTrans :
805 case ocMatMult :
806 case ocMatInv :
807 case ocMatrixUnit :
808 return TRUE;
809 default:
811 // added to avoid warnings
814 return FALSE;
817 // -----------------------------------------------------------------------------
818 FormulaCompiler::OpCodeMap::~OpCodeMap()
820 delete mpReverseExternalHashMap;
821 delete mpExternalHashMap;
822 delete [] mpTable;
823 delete mpHashMap;
825 // -----------------------------------------------------------------------------
826 sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
828 static const sal_Int32 kOpCodeUnknown = -1;
829 return kOpCodeUnknown;
831 // -----------------------------------------------------------------------------
832 BOOL FormulaCompiler::GetToken()
834 static const short nRecursionMax = 42;
835 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
836 if ( nRecursion > nRecursionMax )
838 SetError( errStackOverflow );
839 pToken = new FormulaByteToken( ocStop );
840 return FALSE;
842 if ( bAutoCorrect && !pStack )
843 { // #61426# don't merge stacked subroutine code into entered formula
844 aCorrectedFormula += aCorrectedSymbol;
845 aCorrectedSymbol.Erase();
847 BOOL bStop = FALSE;
848 if( pArr->GetCodeError() && !bIgnoreErrors )
849 bStop = TRUE;
850 else
852 short nWasColRowName;
853 if ( pArr->nIndex
854 && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
855 nWasColRowName = 1;
856 else
857 nWasColRowName = 0;
858 pToken = pArr->Next();
859 while( pToken && pToken->GetOpCode() == ocSpaces )
861 if ( nWasColRowName )
862 nWasColRowName++;
863 if ( bAutoCorrect && !pStack )
864 CreateStringFromToken( aCorrectedFormula, pToken, FALSE );
865 pToken = pArr->Next();
867 if ( bAutoCorrect && !pStack && pToken )
868 CreateStringFromToken( aCorrectedSymbol, pToken, FALSE );
869 if( !pToken )
871 if( pStack )
873 PopTokenArray();
874 return GetToken();
876 else
877 bStop = TRUE;
879 else
881 if ( nWasColRowName >= 2 && pToken->GetOpCode() == ocColRowName )
882 { // convert an ocSpaces to ocIntersect in RPN
883 pToken = new FormulaByteToken( ocIntersect );
884 pArr->nIndex--; // we advanced to the second ocColRowName, step back
888 if( bStop )
890 pToken = new FormulaByteToken( ocStop );
891 return FALSE;
893 if( pToken->GetOpCode() == ocSubTotal )
894 glSubTotal = TRUE;
895 else if ( pToken->GetOpCode() == ocExternalRef )
897 return HandleExternalReference(*pToken);
899 else if( pToken->GetOpCode() == ocName )
901 return HandleRange();
903 else if( pToken->GetOpCode() == ocColRowName )
905 return HandleSingleRef();
907 else if( pToken->GetOpCode() == ocDBArea )
909 return HandleDbData();
911 else if( pToken->GetType() == svSingleRef )
913 pArr->nRefs++;
915 else if( pToken->GetType() == svDoubleRef )
917 pArr->nRefs++;
919 return TRUE;
921 //---------------------------------------------------------------------------
922 // RPN creation by recursion
923 //---------------------------------------------------------------------------
925 void FormulaCompiler::Factor()
927 if ( pArr->GetCodeError() && !bIgnoreErrors )
928 return;
930 CurrentFactor pFacToken( this );
932 OpCode eOp = pToken->GetOpCode();
933 if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
934 eOp == ocDBArea
935 || (bCompileForFAP && ((eOp == ocName) || (eOp == ocDBArea)
936 || (eOp == ocColRowName) || (eOp == ocBad)))
939 PutCode( pToken );
940 eOp = NextToken();
941 if( eOp == ocOpen )
943 // PUSH( is an error that may be caused by an unknown function.
944 SetError(
945 ( pToken->GetType() == svString
946 || pToken->GetType() == svSingleRef )
947 ? errNoName : errOperatorExpected );
948 if ( bAutoCorrect && !pStack )
949 { // assume multiplication
950 aCorrectedFormula += mxSymbols->getSymbol(ocMul);
951 bCorrected = TRUE;
952 NextToken();
953 eOp = Expression();
954 if( eOp != ocClose )
955 SetError(errPairExpected);
956 else
957 eOp = NextToken();
961 else if( eOp == ocOpen )
963 NextToken();
964 eOp = Expression();
965 while ((eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors))
966 { // range list (A1;A2) converted to (A1~A2)
967 pFacToken = pToken;
968 NextToken();
969 eOp = Expression();
970 // Do not ignore error here, regardless of bIgnoreErrors, otherwise
971 // errors like =(1;) would also result in display of =(1~)
972 if (!pArr->GetCodeError())
974 pFacToken->NewOpCode( ocUnion,FormulaToken::PrivateAccess());
975 PutCode( pFacToken);
978 if (eOp != ocClose)
979 SetError(errPairExpected);
980 else
981 eOp = NextToken();
983 else
985 if( nNumFmt == NUMBERFORMAT_UNDEFINED )
986 nNumFmt = lcl_GetRetFormat( eOp );
988 if ( IsOpCodeVolatile(eOp) )
989 pArr->SetRecalcModeAlways();
990 else
992 switch( eOp )
994 // Functions recalculated on every document load.
995 // Don't use SetRecalcModeOnLoad() which would override
996 // ModeAlways.
997 case ocConvert :
998 pArr->AddRecalcMode( RECALCMODE_ONLOAD );
999 break;
1000 // If the referred cell is moved the value changes.
1001 case ocColumn :
1002 case ocRow :
1003 // ocCell needs recalc on move for some possible type values.
1004 case ocCell :
1005 pArr->SetRecalcModeOnRefMove();
1006 break;
1007 case ocHyperLink :
1008 pArr->SetHyperLink(TRUE);
1009 break;
1010 default:
1011 ; // nothing
1014 if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
1016 pFacToken = pToken;
1017 eOp = NextToken();
1018 if (eOp != ocOpen)
1020 SetError(errPairExpected);
1021 PutCode( pFacToken );
1023 else
1025 eOp = NextToken();
1026 if (eOp != ocClose)
1027 SetError(errPairExpected);
1028 PutCode(pFacToken);
1029 eOp = NextToken();
1032 // special cases NOT() and NEG()
1033 else if( eOp == ocNot || eOp == ocNeg
1034 || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
1036 pFacToken = pToken;
1037 eOp = NextToken();
1038 if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot )
1039 nNumFmt = NUMBERFORMAT_LOGICAL;
1040 if (eOp == ocOpen)
1042 NextToken();
1043 eOp = Expression();
1045 else
1046 SetError(errPairExpected);
1047 if (eOp != ocClose)
1048 SetError(errPairExpected);
1049 else if ( !pArr->GetCodeError() )
1050 pFacToken->SetByte( 1 );
1051 PutCode( pFacToken );
1052 eOp = NextToken();
1054 else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
1055 || eOp == ocExternal
1056 || eOp == ocMacro
1057 || eOp == ocAnd
1058 || eOp == ocOr
1059 || eOp == ocBad
1060 || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1061 || (bCompileForFAP && ((eOp == ocIf) || (eOp == ocChose)))
1064 pFacToken = pToken;
1065 OpCode eMyLastOp = eOp;
1066 eOp = NextToken();
1067 bool bNoParam = false;
1068 bool bBadName = false;
1069 if (eOp == ocOpen)
1071 eOp = NextToken();
1072 if (eOp == ocClose)
1073 bNoParam = true;
1074 else
1075 eOp = Expression();
1077 else if (eMyLastOp == ocBad)
1079 // Just a bad name, not an unknown function, no parameters, no
1080 // closing expected.
1081 bBadName = true;
1082 bNoParam = true;
1084 else
1085 SetError(errPairExpected);
1086 BYTE nSepCount = 0;
1087 if( !bNoParam )
1089 nSepCount++;
1090 while ( (eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors) )
1092 nSepCount++;
1093 NextToken();
1094 eOp = Expression();
1097 if (bBadName)
1098 ; // nothing, keep current token for return
1099 else if (eOp != ocClose)
1100 SetError(errPairExpected);
1101 else
1102 eOp = NextToken();
1103 // Jumps are just normal functions for the FunctionAutoPilot tree view
1104 if ( bCompileForFAP && pFacToken->GetType() == svJump )
1105 pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
1106 else
1107 pFacToken->SetByte( nSepCount );
1108 PutCode( pFacToken );
1110 else if (eOp == ocIf || eOp == ocChose)
1112 // the PC counters are -1
1113 pFacToken = pToken;
1114 if ( eOp == ocIf )
1115 pFacToken->GetJump()[ 0 ] = 3; // if, else, behind
1116 else
1117 pFacToken->GetJump()[ 0 ] = MAXJUMPCOUNT+1;
1118 eOp = NextToken();
1119 if (eOp == ocOpen)
1121 NextToken();
1122 eOp = Expression();
1124 else
1125 SetError(errPairExpected);
1126 short nJumpCount = 0;
1127 PutCode( pFacToken );
1128 // #36253# during AutoCorrect (since pArr->GetCodeError() is
1129 // ignored) an unlimited ocIf would crash because
1130 // ScRawToken::Clone() allocates the JumpBuffer according to
1131 // nJump[0]*2+2, which is 3*2+2 on ocIf.
1132 const short nJumpMax =
1133 (pFacToken->GetOpCode() == ocIf ? 3 : MAXJUMPCOUNT);
1134 while ( (nJumpCount < (MAXJUMPCOUNT - 1)) && (eOp == ocSep)
1135 && (!pArr->GetCodeError() || bIgnoreErrors) )
1137 if ( ++nJumpCount <= nJumpMax )
1138 pFacToken->GetJump()[nJumpCount] = pc-1;
1139 NextToken();
1140 eOp = Expression();
1141 // ocSep or ocClose terminate the subexpression
1142 PutCode( pToken );
1144 if (eOp != ocClose)
1145 SetError(errPairExpected);
1146 else
1148 eOp = NextToken();
1149 // always limit to nJumpMax, no arbitrary overwrites
1150 if ( ++nJumpCount <= nJumpMax )
1151 pFacToken->GetJump()[ nJumpCount ] = pc-1;
1152 if ((pFacToken->GetOpCode() == ocIf && (nJumpCount > 3)) ||
1153 (nJumpCount >= MAXJUMPCOUNT))
1154 SetError(errIllegalParameter);
1155 else
1156 pFacToken->GetJump()[ 0 ] = nJumpCount;
1159 else if ( eOp == ocMissing )
1161 PutCode( pToken );
1162 eOp = NextToken();
1164 else if ( eOp == ocClose )
1166 SetError( errParameterExpected );
1168 else if ( eOp == ocSep )
1169 { // Subsequent ocSep
1170 SetError( errParameterExpected );
1171 if ( bAutoCorrect && !pStack )
1173 aCorrectedSymbol.Erase();
1174 bCorrected = TRUE;
1177 else if ( eOp == ocExternalRef )
1179 PutCode(pToken);
1180 eOp = NextToken();
1182 else
1184 SetError( errUnknownToken );
1185 if ( bAutoCorrect && !pStack )
1187 if ( eOp == ocStop )
1188 { // trailing operator w/o operand
1189 xub_StrLen nLen = aCorrectedFormula.Len();
1190 if ( nLen )
1191 aCorrectedFormula.Erase( nLen - 1 );
1192 aCorrectedSymbol.Erase();
1193 bCorrected = TRUE;
1200 //---------------------------------------------------------------------------
1202 void FormulaCompiler::RangeLine()
1204 Factor();
1205 while (pToken->GetOpCode() == ocRange)
1207 FormulaToken** pCode1 = pCode - 1;
1208 FormulaTokenRef p = pToken;
1209 NextToken();
1210 Factor();
1211 FormulaToken** pCode2 = pCode - 1;
1212 if (!MergeRangeReference( pCode1, pCode2))
1213 PutCode(p);
1217 //---------------------------------------------------------------------------
1219 void FormulaCompiler::UnionLine()
1221 RangeLine();
1222 while (pToken->GetOpCode() == ocUnion)
1224 FormulaTokenRef p = pToken;
1225 NextToken();
1226 RangeLine();
1227 PutCode(p);
1231 //---------------------------------------------------------------------------
1233 void FormulaCompiler::IntersectionLine()
1235 UnionLine();
1236 while (pToken->GetOpCode() == ocIntersect)
1238 FormulaTokenRef p = pToken;
1239 NextToken();
1240 UnionLine();
1241 PutCode(p);
1245 //---------------------------------------------------------------------------
1247 void FormulaCompiler::UnaryLine()
1249 if( pToken->GetOpCode() == ocAdd )
1250 GetToken();
1251 else if (SC_OPCODE_START_UN_OP <= pToken->GetOpCode() &&
1252 pToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
1254 FormulaTokenRef p = pToken;
1255 NextToken();
1256 UnaryLine();
1257 PutCode( p );
1259 else
1260 IntersectionLine();
1263 //---------------------------------------------------------------------------
1265 void FormulaCompiler::PostOpLine()
1267 UnaryLine();
1268 while ( pToken->GetOpCode() == ocPercentSign )
1269 { // this operator _follows_ its operand
1270 PutCode( pToken );
1271 NextToken();
1275 //---------------------------------------------------------------------------
1277 void FormulaCompiler::PowLine()
1279 PostOpLine();
1280 while (pToken->GetOpCode() == ocPow)
1282 FormulaTokenRef p = pToken;
1283 NextToken();
1284 PostOpLine();
1285 PutCode(p);
1289 //---------------------------------------------------------------------------
1291 void FormulaCompiler::MulDivLine()
1293 PowLine();
1294 while (pToken->GetOpCode() == ocMul || pToken->GetOpCode() == ocDiv)
1296 FormulaTokenRef p = pToken;
1297 NextToken();
1298 PowLine();
1299 PutCode(p);
1303 //---------------------------------------------------------------------------
1305 void FormulaCompiler::AddSubLine()
1307 MulDivLine();
1308 while (pToken->GetOpCode() == ocAdd || pToken->GetOpCode() == ocSub)
1310 FormulaTokenRef p = pToken;
1311 NextToken();
1312 MulDivLine();
1313 PutCode(p);
1317 //---------------------------------------------------------------------------
1319 void FormulaCompiler::ConcatLine()
1321 AddSubLine();
1322 while (pToken->GetOpCode() == ocAmpersand)
1324 FormulaTokenRef p = pToken;
1325 NextToken();
1326 AddSubLine();
1327 PutCode(p);
1331 //---------------------------------------------------------------------------
1333 void FormulaCompiler::CompareLine()
1335 ConcatLine();
1336 while (pToken->GetOpCode() >= ocEqual && pToken->GetOpCode() <= ocGreaterEqual)
1338 FormulaTokenRef p = pToken;
1339 NextToken();
1340 ConcatLine();
1341 PutCode(p);
1345 //---------------------------------------------------------------------------
1347 void FormulaCompiler::NotLine()
1349 CompareLine();
1350 while (pToken->GetOpCode() == ocNot)
1352 FormulaTokenRef p = pToken;
1353 NextToken();
1354 CompareLine();
1355 PutCode(p);
1359 //---------------------------------------------------------------------------
1361 OpCode FormulaCompiler::Expression()
1363 static const short nRecursionMax = 42;
1364 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
1365 if ( nRecursion > nRecursionMax )
1367 SetError( errStackOverflow );
1368 return ocStop; //! generate token instead?
1370 NotLine();
1371 while (pToken->GetOpCode() == ocAnd || pToken->GetOpCode() == ocOr)
1373 FormulaTokenRef p = pToken;
1374 pToken->SetByte( 2 ); // 2 parameters!
1375 NextToken();
1376 NotLine();
1377 PutCode(p);
1379 return pToken->GetOpCode();
1381 // -----------------------------------------------------------------------------
1382 void FormulaCompiler::SetError(USHORT /*nError*/)
1385 // -----------------------------------------------------------------------------
1386 FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/, bool /*bReuseDoubleRef*/ )
1388 return FormulaTokenRef();
1390 // -----------------------------------------------------------------------------
1391 bool FormulaCompiler::MergeRangeReference(FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
1393 FormulaToken *p1, *p2;
1394 if (pc < 2 || !pCode1 || !pCode2 ||
1395 (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
1396 ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
1397 return false;
1399 FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
1400 if (!p)
1401 return false;
1403 p->IncRef();
1404 p1->DecRef();
1405 p2->DecRef();
1406 *pCode1 = p;
1407 --pCode, --pc;
1408 pArr->nRefs--;
1410 return true;
1412 // -----------------------------------------------------------------------------
1413 BOOL FormulaCompiler::CompileTokenArray()
1415 glSubTotal = FALSE;
1416 bCorrected = FALSE;
1417 if( !pArr->GetCodeError() || bIgnoreErrors )
1419 if ( bAutoCorrect )
1421 aCorrectedFormula.Erase();
1422 aCorrectedSymbol.Erase();
1424 pArr->nRefs = 0; // count from start
1425 pArr->DelRPN();
1426 pStack = NULL;
1427 FormulaToken* pData[ MAXCODE ];
1428 pCode = pData;
1429 BOOL bWasForced = pArr->IsRecalcModeForced();
1430 if ( bWasForced )
1432 if ( bAutoCorrect )
1433 aCorrectedFormula = '=';
1435 pArr->ClearRecalcMode();
1436 pArr->Reset();
1437 eLastOp = ocOpen;
1438 pc = 0;
1439 NextToken();
1440 OpCode eOp = Expression();
1441 // Some trailing garbage that doesn't form an expression?
1442 if (eOp != ocStop)
1443 SetError( errOperatorExpected);
1445 USHORT nErrorBeforePop = pArr->GetCodeError();
1447 while( pStack )
1448 PopTokenArray();
1449 if( pc )
1451 pArr->pRPN = new FormulaToken*[ pc ];
1452 pArr->nRPN = pc;
1453 memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
1456 // once an error, always an error
1457 if( !pArr->GetCodeError() && nErrorBeforePop )
1458 pArr->SetCodeError( nErrorBeforePop);
1460 if( pArr->GetCodeError() && !bIgnoreErrors )
1462 pArr->DelRPN();
1463 pArr->SetHyperLink(FALSE);
1466 if ( bWasForced )
1467 pArr->SetRecalcModeForced();
1469 if( nNumFmt == NUMBERFORMAT_UNDEFINED )
1470 nNumFmt = NUMBERFORMAT_NUMBER;
1471 return glSubTotal;
1473 // -----------------------------------------------------------------------------
1474 void FormulaCompiler::PopTokenArray()
1476 if( pStack )
1478 FormulaArrayStack* p = pStack;
1479 pStack = p->pNext;
1480 p->pArr->nRefs = sal::static_int_cast<short>( p->pArr->nRefs + pArr->nRefs );
1481 // obtain special RecalcMode from SharedFormula
1482 if ( pArr->IsRecalcModeAlways() )
1483 p->pArr->SetRecalcModeAlways();
1484 else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
1485 p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
1486 p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
1487 if( p->bTemp )
1488 delete pArr;
1489 pArr = p->pArr;
1490 delete p;
1493 // -----------------------------------------------------------------------------
1494 void FormulaCompiler::CreateStringFromTokenArray( String& rFormula )
1496 rtl::OUStringBuffer aBuffer( pArr->GetLen() * 5 );
1497 CreateStringFromTokenArray( aBuffer );
1498 rFormula = aBuffer;
1501 void FormulaCompiler::CreateStringFromTokenArray( rtl::OUStringBuffer& rBuffer )
1503 rBuffer.setLength(0);
1504 if( !pArr->GetLen() )
1505 return;
1507 FormulaTokenArray* pSaveArr = pArr;
1508 bool bODFF = FormulaGrammar::isODFF( meGrammar);
1509 if (bODFF || FormulaGrammar::isPODF( meGrammar) )
1511 // Scan token array for missing args and re-write if present.
1512 MissingConvention aConv( bODFF);
1513 if (pArr->NeedsPofRewrite( aConv))
1514 pArr = pArr->RewriteMissingToPof( aConv);
1517 // At least one character per token, plus some are references, some are
1518 // function names, some are numbers, ...
1519 rBuffer.ensureCapacity( pArr->GetLen() * 5 );
1521 if ( pArr->IsRecalcModeForced() )
1522 rBuffer.append(sal_Unicode('='));
1523 FormulaToken* t = pArr->First();
1524 while( t )
1525 t = CreateStringFromToken( rBuffer, t, TRUE );
1527 if (pSaveArr != pArr)
1529 delete pArr;
1530 pArr = pSaveArr;
1533 // -----------------------------------------------------------------------------
1534 FormulaToken* FormulaCompiler::CreateStringFromToken( String& rFormula, FormulaToken* pTokenP,BOOL bAllowArrAdvance )
1536 rtl::OUStringBuffer aBuffer;
1537 FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
1538 rFormula += aBuffer;
1539 return p;
1542 FormulaToken* FormulaCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP,BOOL bAllowArrAdvance )
1544 BOOL bNext = TRUE;
1545 BOOL bSpaces = FALSE;
1546 FormulaToken* t = pTokenP;
1547 OpCode eOp = t->GetOpCode();
1548 if( eOp >= ocAnd && eOp <= ocOr )
1550 // AND, OR infix?
1551 if ( bAllowArrAdvance )
1552 t = pArr->Next();
1553 else
1554 t = pArr->PeekNext();
1555 bNext = FALSE;
1556 bSpaces = ( !t || t->GetOpCode() != ocOpen );
1558 if( bSpaces )
1559 rBuffer.append(sal_Unicode(' '));
1561 if( eOp == ocSpaces )
1563 bool bIntersectionOp = mxSymbols->isODFF();
1564 if (bIntersectionOp)
1566 const FormulaToken* p = pArr->PeekPrevNoSpaces();
1567 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1568 if (bIntersectionOp)
1570 p = pArr->PeekNextNoSpaces();
1571 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1574 if (bIntersectionOp)
1575 rBuffer.appendAscii( "!!");
1576 else
1578 // most times it's just one blank
1579 BYTE n = t->GetByte();
1580 for ( BYTE j=0; j<n; ++j )
1582 rBuffer.append(sal_Unicode(' '));
1586 else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1587 rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
1588 else if( (USHORT) eOp < mxSymbols->getSymbolCount()) // Keyword:
1589 rBuffer.append(mxSymbols->getSymbol(eOp));
1590 else
1592 DBG_ERRORFILE("unknown OpCode");
1593 rBuffer.append(GetNativeSymbol( ocErrName ));
1595 if( bNext )
1597 if (eOp == ocExternalRef)
1599 CreateStringFromExternal(rBuffer, pTokenP);
1601 else
1603 switch( t->GetType() )
1605 case svDouble:
1606 AppendDouble( rBuffer, t->GetDouble() );
1607 break;
1609 case svString:
1610 if( eOp == ocBad )
1611 rBuffer.append(t->GetString());
1612 else
1613 AppendString( rBuffer, t->GetString() );
1614 break;
1615 case svSingleRef:
1616 CreateStringFromSingleRef(rBuffer,t);
1617 break;
1618 case svDoubleRef:
1619 CreateStringFromDoubleRef(rBuffer,t);
1620 break;
1621 case svMatrix:
1622 CreateStringFromMatrix( rBuffer, t );
1623 break;
1625 case svIndex:
1626 CreateStringFromIndex( rBuffer, t );
1627 break;
1628 case svExternal:
1630 // mapped or translated name of AddIns
1631 String aAddIn( t->GetExternal() );
1632 bool bMapped = mxSymbols->isPODF(); // ODF 1.1 directly uses programmatical name
1633 if (!bMapped && mxSymbols->hasExternals())
1635 ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
1636 if (iLook != mxSymbols->getReverseExternalHashMap()->end())
1638 aAddIn = (*iLook).second;
1639 bMapped = true;
1642 if (!bMapped && !mxSymbols->isEnglish())
1643 LocalizeString( aAddIn );
1644 rBuffer.append(aAddIn);
1646 break;
1647 case svByte:
1648 case svJump:
1649 case svFAP:
1650 case svMissing:
1651 case svSep:
1652 break; // Opcodes
1653 default:
1654 DBG_ERROR("FormulaCompiler:: GetStringFromToken errUnknownVariable");
1655 } // of switch
1658 if( bSpaces )
1659 rBuffer.append(sal_Unicode(' '));
1660 if ( bAllowArrAdvance )
1662 if( bNext )
1663 t = pArr->Next();
1664 return t;
1666 return pTokenP;
1668 // -----------------------------------------------------------------------------
1670 void FormulaCompiler::AppendDouble( rtl::OUStringBuffer& rBuffer, double fVal )
1672 if ( mxSymbols->isEnglish() )
1674 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1675 rtl_math_StringFormat_Automatic,
1676 rtl_math_DecimalPlaces_Max, '.', TRUE );
1678 else
1680 SvtSysLocale aSysLocale;
1681 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1682 rtl_math_StringFormat_Automatic,
1683 rtl_math_DecimalPlaces_Max,
1684 aSysLocale.GetLocaleDataPtr()->getNumDecimalSep().GetChar(0),
1685 TRUE );
1688 // -----------------------------------------------------------------------------
1689 void FormulaCompiler::AppendBoolean( rtl::OUStringBuffer& rBuffer, bool bVal )
1691 rBuffer.append( mxSymbols->getSymbol(static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
1693 // -----------------------------------------------------------------------------
1694 BOOL FormulaCompiler::IsImportingXML() const
1696 return FALSE;
1698 // -----------------------------------------------------------------------------
1699 void FormulaCompiler::AppendString( rtl::OUStringBuffer& rBuffer, const String & rStr )
1701 if (IsImportingXML())
1702 rBuffer.append( rStr );
1703 else
1705 rBuffer.append(sal_Unicode('"'));
1706 if ( lcl_UnicodeStrChr( rStr.GetBuffer(), '"' ) == NULL )
1707 rBuffer.append( rStr );
1708 else
1710 String aStr( rStr );
1711 aStr.SearchAndReplaceAll( '"', String( RTL_CONSTASCII_USTRINGPARAM( "\"\"")));
1712 rBuffer.append(aStr);
1714 rBuffer.append(sal_Unicode('"'));
1718 void FormulaCompiler::UpdateSeparatorsNative(
1719 const rtl::OUString& rSep, const rtl::OUString& rArrayColSep, const rtl::OUString& rArrayRowSep )
1721 NonConstOpCodeMapPtr xSymbolsNative;
1722 lcl_fillNativeSymbols(xSymbolsNative);
1723 xSymbolsNative->putOpCode(rSep, ocSep);
1724 xSymbolsNative->putOpCode(rArrayColSep, ocArrayColSep);
1725 xSymbolsNative->putOpCode(rArrayRowSep, ocArrayRowSep);
1728 // -----------------------------------------------------------------------------
1729 OpCode FormulaCompiler::NextToken()
1731 if( !GetToken() )
1732 return ocStop;
1733 OpCode eOp = pToken->GetOpCode();
1734 // There must be an operator before a push
1735 if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
1736 !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
1737 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
1738 SetError(errOperatorExpected);
1739 // Operator and Plus => operator
1740 if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
1741 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
1742 eOp = NextToken();
1743 else
1745 // Before an operator there must not be another operator, with the
1746 // exception of AND and OR.
1747 if ( eOp != ocAnd && eOp != ocOr &&
1748 (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP )
1749 && (eLastOp == ocOpen || eLastOp == ocSep ||
1750 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
1752 SetError(errVariableExpected);
1753 if ( bAutoCorrect && !pStack )
1755 if ( eOp == eLastOp || eLastOp == ocOpen )
1756 { // throw away duplicated operator
1757 aCorrectedSymbol.Erase();
1758 bCorrected = TRUE;
1760 else
1762 xub_StrLen nPos = aCorrectedFormula.Len();
1763 if ( nPos )
1765 nPos--;
1766 sal_Unicode c = aCorrectedFormula.GetChar( nPos );
1767 switch ( eOp )
1768 { // swap operators
1769 case ocGreater:
1770 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
1771 { // >= instead of =>
1772 aCorrectedFormula.SetChar( nPos,
1773 mxSymbols->getSymbol(ocGreater).GetChar(0) );
1774 aCorrectedSymbol = c;
1775 bCorrected = TRUE;
1777 break;
1778 case ocLess:
1779 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
1780 { // <= instead of =<
1781 aCorrectedFormula.SetChar( nPos,
1782 mxSymbols->getSymbol(ocLess).GetChar(0) );
1783 aCorrectedSymbol = c;
1784 bCorrected = TRUE;
1786 else if ( c == mxSymbols->getSymbol(ocGreater).GetChar(0) )
1787 { // <> instead of ><
1788 aCorrectedFormula.SetChar( nPos,
1789 mxSymbols->getSymbol(ocLess).GetChar(0) );
1790 aCorrectedSymbol = c;
1791 bCorrected = TRUE;
1793 break;
1794 case ocMul:
1795 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
1796 { // *- instead of -*
1797 aCorrectedFormula.SetChar( nPos,
1798 mxSymbols->getSymbol(ocMul).GetChar(0) );
1799 aCorrectedSymbol = c;
1800 bCorrected = TRUE;
1802 break;
1803 case ocDiv:
1804 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
1805 { // /- instead of -/
1806 aCorrectedFormula.SetChar( nPos,
1807 mxSymbols->getSymbol(ocDiv).GetChar(0) );
1808 aCorrectedSymbol = c;
1809 bCorrected = TRUE;
1811 break;
1812 default:
1813 ; // nothing
1819 eLastOp = eOp;
1821 return eOp;
1823 void FormulaCompiler::PutCode( FormulaTokenRef& p )
1825 if( pc >= MAXCODE-1 )
1827 if ( pc == MAXCODE-1 )
1829 p = new FormulaByteToken( ocStop );
1830 p->IncRef();
1831 *pCode++ = p;
1832 ++pc;
1834 SetError(errCodeOverflow);
1835 return;
1837 if( pArr->GetCodeError() && !bCompileForFAP )
1838 return;
1839 ForceArrayOperator( p, pCurrentFactorToken);
1840 p->IncRef();
1841 *pCode++ = p;
1842 pc++;
1845 // -----------------------------------------------------------------------------
1846 BOOL FormulaCompiler::HandleExternalReference(const FormulaToken& /*_aToken*/)
1848 return TRUE;
1850 // -----------------------------------------------------------------------------
1851 BOOL FormulaCompiler::HandleRange()
1853 return TRUE;
1855 // -----------------------------------------------------------------------------
1856 BOOL FormulaCompiler::HandleSingleRef()
1858 return TRUE;
1860 // -----------------------------------------------------------------------------
1861 BOOL FormulaCompiler::HandleDbData()
1863 return TRUE;
1865 // -----------------------------------------------------------------------------
1866 void FormulaCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1869 // -----------------------------------------------------------------------------
1870 void FormulaCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1873 // -----------------------------------------------------------------------------
1874 void FormulaCompiler::CreateStringFromIndex(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1877 // -----------------------------------------------------------------------------
1878 void FormulaCompiler::CreateStringFromMatrix(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1881 // -----------------------------------------------------------------------------
1882 void FormulaCompiler::CreateStringFromExternal(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
1885 // -----------------------------------------------------------------------------
1886 void FormulaCompiler::LocalizeString( String& /*rName*/ )
1889 void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, BOOL bTemp )
1891 if ( bAutoCorrect && !pStack )
1892 { // #61426# don't merge stacked subroutine code into entered formula
1893 aCorrectedFormula += aCorrectedSymbol;
1894 aCorrectedSymbol.Erase();
1896 FormulaArrayStack* p = new FormulaArrayStack;
1897 p->pNext = pStack;
1898 p->pArr = pArr;
1899 p->bTemp = bTemp;
1900 pStack = p;
1901 pArr = pa;
1904 // =============================================================================
1905 } // formula
1906 // =============================================================================