fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / formula / source / core / api / FormulaCompiler.cxx
blob3d0a415897947539e857d4941ec206e6c6b1e421
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 "osl/mutex.hxx"
29 #include <svl/zforlist.hxx>
30 #include <tools/rc.hxx>
31 #include <tools/rcid.h>
32 #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
33 #include <com/sun/star/sheet/FormulaMapGroup.hpp>
34 #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
35 #include <rtl/strbuf.hxx>
36 #include <algorithm>
38 namespace formula
40 using namespace ::com::sun::star;
42 static const sal_Char* pInternal[2] = { "TTT", "__DEBUG_VAR" };
44 namespace {
46 class FormulaCompilerRecursionGuard
48 private:
49 short& rRecursion;
50 public:
51 FormulaCompilerRecursionGuard( short& rRec )
52 : rRecursion( rRec ) { ++rRecursion; }
53 ~FormulaCompilerRecursionGuard() { --rRecursion; }
56 short lcl_GetRetFormat( OpCode eOpCode )
58 switch (eOpCode)
60 case ocEqual:
61 case ocNotEqual:
62 case ocLess:
63 case ocGreater:
64 case ocLessEqual:
65 case ocGreaterEqual:
66 case ocAnd:
67 case ocOr:
68 case ocXor:
69 case ocNot:
70 case ocTrue:
71 case ocFalse:
72 case ocIsEmpty:
73 case ocIsString:
74 case ocIsNonString:
75 case ocIsLogical:
76 case ocIsRef:
77 case ocIsValue:
78 case ocIsFormula:
79 case ocIsNA:
80 case ocIsErr:
81 case ocIsError:
82 case ocIsEven:
83 case ocIsOdd:
84 case ocExact:
85 return css::util::NumberFormat::LOGICAL;
86 case ocGetActDate:
87 case ocGetDate:
88 case ocEasterSunday :
89 return css::util::NumberFormat::DATE;
90 case ocGetActTime:
91 return css::util::NumberFormat::DATETIME;
92 case ocGetTime:
93 return css::util::NumberFormat::TIME;
94 case ocNPV:
95 case ocPV:
96 case ocSYD:
97 case ocDDB:
98 case ocDB:
99 case ocVBD:
100 case ocSLN:
101 case ocPMT:
102 case ocFV:
103 case ocIpmt:
104 case ocPpmt:
105 case ocCumIpmt:
106 case ocCumPrinc:
107 return css::util::NumberFormat::CURRENCY;
108 case ocRate:
109 case ocIRR:
110 case ocMIRR:
111 case ocRRI:
112 case ocEffective:
113 case ocNominal:
114 case ocPercentSign:
115 return css::util::NumberFormat::PERCENT;
116 default:
117 return css::util::NumberFormat::NUMBER;
121 inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
122 const OUString* pTable, sal_uInt16 nOpCode )
124 sheet::FormulaOpCodeMapEntry aEntry;
125 aEntry.Token.OpCode = nOpCode;
126 aEntry.Name = pTable[nOpCode];
127 rVec.push_back( aEntry);
130 void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
131 const OUString* 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,
138 const OUString* pTable, const sal_uInt16* pnOpCodes, size_t nCount )
140 for (const sal_uInt16* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes)
141 lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes );
144 class OpCodeList : public Resource // temp object for resource
146 public:
148 OpCodeList( sal_uInt16, FormulaCompiler::NonConstOpCodeMapPtr,
149 FormulaCompiler::SeparatorType = FormulaCompiler::SEMICOLON_BASE );
151 private:
152 bool getOpCodeString( OUString& rStr, sal_uInt16 nOp );
153 void putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp, const CharClass* pCharClass );
155 private:
156 FormulaCompiler::SeparatorType meSepType;
159 OpCodeList::OpCodeList( sal_uInt16 nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap,
160 FormulaCompiler::SeparatorType eSepType ) :
161 Resource( ResId( nRID, *ResourceManager::getResManager()))
162 , meSepType( eSepType)
164 SvtSysLocale aSysLocale;
165 const CharClass* pCharClass = (xMap->isEnglish() ? NULL : aSysLocale.GetCharClassPtr());
166 if (meSepType == FormulaCompiler::RESOURCE_BASE)
168 for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
170 putDefaultOpCode( xMap, i, pCharClass);
173 else
175 for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
177 OUString aOpStr;
178 if ( getOpCodeString( aOpStr, i) )
179 xMap->putOpCode( aOpStr, OpCode(i), pCharClass);
180 else
181 putDefaultOpCode( xMap, i, pCharClass);
185 FreeResource();
188 bool OpCodeList::getOpCodeString( OUString& rStr, sal_uInt16 nOp )
190 switch (nOp)
192 case SC_OPCODE_SEP:
194 if (meSepType == FormulaCompiler::COMMA_BASE)
196 rStr = ",";
197 return true;
199 else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
201 rStr = ";";
202 return true;
205 break;
206 case SC_OPCODE_ARRAY_COL_SEP:
208 if (meSepType == FormulaCompiler::COMMA_BASE)
210 rStr = ",";
211 return true;
213 else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
215 rStr = ";";
216 return true;
219 break;
220 case SC_OPCODE_ARRAY_ROW_SEP:
222 if (meSepType == FormulaCompiler::COMMA_BASE)
224 rStr = ";";
225 return true;
227 else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
229 rStr = "|";
230 return true;
233 break;
236 return false;
239 void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp,
240 const CharClass* pCharClass )
242 ResId aRes( nOp, *ResourceManager::getResManager());
243 aRes.SetRT( RSC_STRING);
244 if (IsAvailableRes( aRes))
245 xMap->putOpCode( aRes.toString(), OpCode( nOp), pCharClass);
248 // static
249 const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr, sal_Unicode c )
251 if ( !pStr )
252 return NULL;
253 while ( *pStr )
255 if ( *pStr == c )
256 return pStr;
257 pStr++;
259 return NULL;
262 struct OpCodeMapData
264 FormulaCompiler::NonConstOpCodeMapPtr mxSymbolMap;
265 osl::Mutex maMtx;
269 } // namespace
272 void FormulaCompiler::OpCodeMap::putExternal( const OUString & rSymbol, const OUString & rAddIn )
274 // Different symbols may map to the same AddIn, but the same AddIn may not
275 // map to different symbols, the first pair wins. Same symbol of course may
276 // not map to different AddIns, again the first pair wins and also the
277 // AddIn->symbol mapping is not inserted in other cases.
278 bool bOk = mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second;
279 SAL_WARN_IF( !bOk, "formula.core", "OpCodeMap::putExternal: symbol not inserted, " << rSymbol << " -> " << rAddIn);
280 if (bOk)
282 bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
283 // Failed insertion of the AddIn is ok for different symbols mapping to
284 // the same AddIn. Make this INFO only.
285 SAL_INFO_IF( !bOk, "formula.core", "OpCodeMap::putExternal: AddIn not inserted, " << rAddIn << " -> " << rSymbol);
289 void FormulaCompiler::OpCodeMap::putExternalSoftly( const OUString & rSymbol, const OUString & rAddIn )
291 bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
292 if (bOk)
293 mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn));
296 uno::Sequence< sheet::FormulaToken > FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(
297 const FormulaCompiler& rCompiler, const uno::Sequence< OUString >& rNames ) const
299 const sal_Int32 nLen = rNames.getLength();
300 uno::Sequence< sheet::FormulaToken > aTokens( nLen);
301 sheet::FormulaToken* pToken = aTokens.getArray();
302 OUString const * pName = rNames.getConstArray();
303 OUString const * const pStop = pName + nLen;
304 for ( ; pName < pStop; ++pName, ++pToken)
306 OpCodeHashMap::const_iterator iLook( mpHashMap->find( *pName));
307 if (iLook != mpHashMap->end())
308 pToken->OpCode = (*iLook).second;
309 else
311 OUString aIntName;
312 if (hasExternals())
314 ExternalHashMap::const_iterator iExt( mpExternalHashMap->find( *pName));
315 if (iExt != mpExternalHashMap->end())
316 aIntName = (*iExt).second;
317 // Check for existence not needed here, only name-mapping is of
318 // interest.
320 if (aIntName.isEmpty())
321 aIntName = rCompiler.FindAddInFunction(*pName, !isEnglish()); // bLocalFirst=false for english
322 if (aIntName.isEmpty())
323 pToken->OpCode = getOpCodeUnknown();
324 else
326 pToken->OpCode = ocExternal;
327 pToken->Data <<= aIntName;
331 return aTokens;
334 uno::Sequence< sheet::FormulaOpCodeMapEntry > FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(
335 const FormulaCompiler& rCompiler, const sal_Int32 nGroups ) const
337 using namespace sheet;
339 // Unfortunately uno::Sequence can't grow without cumbersome reallocs. As
340 // we don't know in advance how many elements it will have we use a
341 // temporary vector to add elements and then copy to Sequence :-(
342 ::std::vector< FormulaOpCodeMapEntry > aVec;
344 if (nGroups == FormulaMapGroup::SPECIAL)
346 // Use specific order, keep in sync with
347 // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl
348 static const struct
350 sal_Int32 nOff;
351 OpCode eOp;
352 } aMap[] = {
353 { FormulaMapGroupSpecialOffset::PUSH , ocPush } ,
354 { FormulaMapGroupSpecialOffset::CALL , ocCall } ,
355 { FormulaMapGroupSpecialOffset::STOP , ocStop } ,
356 { FormulaMapGroupSpecialOffset::EXTERNAL , ocExternal } ,
357 { FormulaMapGroupSpecialOffset::NAME , ocName } ,
358 { FormulaMapGroupSpecialOffset::NO_NAME , ocNoName } ,
359 { FormulaMapGroupSpecialOffset::MISSING , ocMissing } ,
360 { FormulaMapGroupSpecialOffset::BAD , ocBad } ,
361 { FormulaMapGroupSpecialOffset::SPACES , ocSpaces } ,
362 { FormulaMapGroupSpecialOffset::MAT_REF , ocMatRef } ,
363 { FormulaMapGroupSpecialOffset::DB_AREA , ocDBArea } ,
364 /* TODO: { FormulaMapGroupSpecialOffset::TABLE_REF , ocTableRef } , */
365 { FormulaMapGroupSpecialOffset::MACRO , ocMacro } ,
366 { FormulaMapGroupSpecialOffset::COL_ROW_NAME , ocColRowName }
368 const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
369 // Preallocate vector elements.
370 if (aVec.size() < nCount)
372 FormulaOpCodeMapEntry aEntry;
373 aEntry.Token.OpCode = getOpCodeUnknown();
374 aVec.resize( nCount, aEntry);
375 } // if (aVec.size() < nCount)
377 FormulaOpCodeMapEntry aEntry;
378 for (size_t i=0; i < nCount; ++i)
380 size_t nIndex = static_cast< size_t >( aMap[i].nOff );
381 if (aVec.size() <= nIndex)
383 // The offsets really should be aligned with the size, so if
384 // the vector was preallocated above this code to resize it is
385 // just a measure in case the table isn't in sync with the API,
386 // usually it isn't executed.
387 aEntry.Token.OpCode = getOpCodeUnknown();
388 aVec.resize( nIndex + 1, aEntry );
390 aEntry.Token.OpCode = aMap[i].eOp;
391 aVec[nIndex] = aEntry;
394 else
396 /* FIXME: Once we support error constants in formulas we'll need a map
397 * group for that, e.g. FormulaMapGroup::ERROR_CONSTANTS, and fill
398 * SC_OPCODE_START_ERRORS to SC_OPCODE_STOP_ERRORS. */
400 // Anything else but SPECIAL.
401 if ((nGroups & FormulaMapGroup::SEPARATORS) != 0)
403 static const sal_uInt16 aOpCodes[] = {
404 SC_OPCODE_OPEN,
405 SC_OPCODE_CLOSE,
406 SC_OPCODE_SEP,
408 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
410 if ((nGroups & FormulaMapGroup::ARRAY_SEPARATORS) != 0)
412 static const sal_uInt16 aOpCodes[] = {
413 SC_OPCODE_ARRAY_OPEN,
414 SC_OPCODE_ARRAY_CLOSE,
415 SC_OPCODE_ARRAY_ROW_SEP,
416 SC_OPCODE_ARRAY_COL_SEP
418 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
420 if ((nGroups & FormulaMapGroup::UNARY_OPERATORS) != 0)
422 // Due to the nature of the percent operator following its operand
423 // it isn't sorted into unary operators for compiler interna.
424 lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
425 // "+" can be used as unary operator too, push only if binary group is not set
426 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
427 lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
428 // regular unary operators
429 for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
431 switch (nOp)
433 // NOT and NEG in fact are functions but for legacy reasons
434 // are sorted into unary operators for compiler interna.
435 case SC_OPCODE_NOT :
436 case SC_OPCODE_NEG :
437 break; // nothing,
438 default:
439 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
443 if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
445 for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
447 switch (nOp)
449 // AND and OR in fact are functions but for legacy reasons
450 // are sorted into binary operators for compiler interna.
451 case SC_OPCODE_AND :
452 case SC_OPCODE_OR :
453 break; // nothing,
454 default:
455 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
459 if ((nGroups & FormulaMapGroup::FUNCTIONS) != 0)
461 // Function names are not consecutive, skip the gaps between
462 // functions with no parameter, functions with 1 parameter
463 lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_NO_PAR,
464 ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
465 lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_1_PAR,
466 ::std::min< sal_uInt16 >( SC_OPCODE_STOP_1_PAR, mnSymbols ) );
467 // Additional functions not within range of functions.
468 static const sal_uInt16 aOpCodes[] = {
469 SC_OPCODE_IF,
470 SC_OPCODE_IF_ERROR,
471 SC_OPCODE_IF_NA,
472 SC_OPCODE_CHOOSE,
473 SC_OPCODE_AND,
474 SC_OPCODE_OR,
475 SC_OPCODE_NOT,
476 SC_OPCODE_NEG
478 lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
479 // functions with 2 or more parameters.
480 for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
482 switch (nOp)
484 // NO_NAME is in SPECIAL.
485 case SC_OPCODE_NO_NAME :
486 break; // nothing,
487 default:
488 lclPushOpCodeMapEntry( aVec, mpTable, nOp );
491 // If AddIn functions are present in this mapping, use them, and only those.
492 if (hasExternals())
494 for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
496 FormulaOpCodeMapEntry aEntry;
497 aEntry.Name = (*it).first;
498 aEntry.Token.Data <<= OUString( (*it).second);
499 aEntry.Token.OpCode = ocExternal;
500 aVec.push_back( aEntry);
503 else
505 rCompiler.fillAddInToken( aVec, isEnglish());
509 return uno::Sequence< FormulaOpCodeMapEntry >(aVec.data(), aVec.size());
513 void FormulaCompiler::OpCodeMap::putOpCode( const OUString & rStr, const OpCode eOp, const CharClass* pCharClass )
515 DBG_ASSERT( 0 < eOp && sal_uInt16(eOp) < mnSymbols, "OpCodeMap::putOpCode: OpCode out of range");
516 if (0 < eOp && sal_uInt16(eOp) < mnSymbols)
518 SAL_WARN_IF( !(mpTable[eOp].isEmpty() || (mpTable[eOp] == rStr) ||
519 (eOp == ocCurrency) || (eOp == ocSep) || (eOp == ocArrayColSep) ||
520 (eOp == ocArrayRowSep)), "formula.core",
521 "OpCodeMap::putOpCode: reusing OpCode " << static_cast<sal_uInt16>(eOp)
522 << ", replacing '" << mpTable[eOp] << "' with '" << rStr << "' in "
523 << (mbEnglish ? "" : "non-") << "English map 0x" << ::std::hex << meGrammar);
524 // Case preserving opcode -> string, upper string -> opcode
525 mpTable[eOp] = rStr;
526 OUString aUpper( pCharClass ? pCharClass->uppercase( rStr) : rStr.toAsciiUpperCase());
527 mpHashMap->insert( OpCodeHashMap::value_type( aUpper, eOp));
531 // class FormulaCompiler
533 FormulaCompiler::FormulaCompiler( FormulaTokenArray& rArr )
535 nCurrentFactorParam(0),
536 pArr( &rArr ),
537 pCode( NULL ),
538 pStack( NULL ),
539 eLastOp( ocPush ),
540 nRecursion( 0 ),
541 nNumFmt( css::util::NumberFormat::UNDEFINED ),
542 pc( 0 ),
543 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
544 bAutoCorrect( false ),
545 bCorrected( false ),
546 glSubTotal( false ),
547 mbJumpCommandReorder(true),
548 mbStopOnError(true)
552 FormulaCompiler::FormulaCompiler()
554 nCurrentFactorParam(0),
555 pArr( NULL ),
556 pCode( NULL ),
557 pStack( NULL ),
558 eLastOp( ocPush ),
559 nRecursion(0),
560 nNumFmt( css::util::NumberFormat::UNDEFINED ),
561 pc( 0 ),
562 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
563 bAutoCorrect( false ),
564 bCorrected( false ),
565 glSubTotal( false ),
566 mbJumpCommandReorder(true),
567 mbStopOnError(true)
571 FormulaCompiler::~FormulaCompiler()
575 FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
577 FormulaCompiler::OpCodeMapPtr xMap;
578 using namespace sheet;
579 switch (nLanguage)
581 case FormulaLanguage::ODFF :
582 if (!mxSymbolsODFF)
583 InitSymbolsODFF();
584 xMap = mxSymbolsODFF;
585 break;
586 case FormulaLanguage::ODF_11 :
587 if (!mxSymbolsPODF)
588 InitSymbolsPODF();
589 xMap = mxSymbolsPODF;
590 break;
591 case FormulaLanguage::ENGLISH :
592 if (!mxSymbolsEnglish)
593 InitSymbolsEnglish();
594 xMap = mxSymbolsEnglish;
595 break;
596 case FormulaLanguage::NATIVE :
597 if (!mxSymbolsNative)
598 InitSymbolsNative();
599 xMap = mxSymbolsNative;
600 break;
601 case FormulaLanguage::XL_ENGLISH:
602 if (!mxSymbolsEnglishXL)
603 InitSymbolsEnglishXL();
604 xMap = mxSymbolsEnglishXL;
605 break;
606 case FormulaLanguage::OOXML:
607 if (!mxSymbolsOOXML)
608 InitSymbolsOOXML();
609 xMap = mxSymbolsOOXML;
610 break;
611 default:
612 ; // nothing, NULL map returned
614 return xMap;
617 OUString FormulaCompiler::FindAddInFunction( const OUString& /*rUpperName*/, bool /*bLocalFirst*/ ) const
619 return OUString();
622 FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
623 const uno::Sequence<
624 const sheet::FormulaOpCodeMapEntry > & rMapping,
625 bool bEnglish )
627 using sheet::FormulaOpCodeMapEntry;
628 // Filter / API maps are never Core
629 NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, false,
630 FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(
631 FormulaGrammar::GRAM_EXTERNAL, bEnglish), FormulaGrammar::CONV_UNSPECIFIED)));
632 SvtSysLocale aSysLocale;
633 const CharClass* pCharClass = (xMap->isEnglish() ? NULL : aSysLocale.GetCharClassPtr());
634 FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
635 FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
636 for ( ; pArr2 < pStop; ++pArr2)
638 OpCode eOp = OpCode(pArr2->Token.OpCode);
639 if (eOp != ocExternal)
640 xMap->putOpCode( pArr2->Name, eOp, pCharClass);
641 else
643 OUString aExternalName;
644 if (pArr2->Token.Data >>= aExternalName)
645 xMap->putExternal( pArr2->Name, aExternalName);
646 else
648 SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
652 return xMap;
655 void lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& xMap, bool bDestroy = false )
657 static OpCodeMapData aSymbolMap;
658 osl::MutexGuard aGuard(&aSymbolMap.maMtx);
660 if ( bDestroy )
662 aSymbolMap.mxSymbolMap.reset();
664 else if (!aSymbolMap.mxSymbolMap)
666 // Core
667 aSymbolMap.mxSymbolMap.reset(
668 new FormulaCompiler::OpCodeMap(
669 SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
670 OModuleClient aModuleClient;
671 OpCodeList aOpCodeListNative(RID_STRLIST_FUNCTION_NAMES, aSymbolMap.mxSymbolMap);
672 // No AddInMap for native core mapping.
675 xMap = aSymbolMap.mxSymbolMap;
678 const OUString& FormulaCompiler::GetNativeSymbol( OpCode eOp )
680 NonConstOpCodeMapPtr xSymbolsNative;
681 lcl_fillNativeSymbols( xSymbolsNative);
682 return xSymbolsNative->getSymbol( eOp );
685 sal_Unicode FormulaCompiler::GetNativeSymbolChar( OpCode eOp )
687 return GetNativeSymbol(eOp)[0];
690 void FormulaCompiler::InitSymbolsNative() const
692 lcl_fillNativeSymbols( mxSymbolsNative);
695 void FormulaCompiler::InitSymbolsEnglish() const
697 static OpCodeMapData aMap;
698 osl::MutexGuard aGuard(&aMap.maMtx);
699 if (!aMap.mxSymbolMap)
700 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
701 mxSymbolsEnglish = aMap.mxSymbolMap;
704 void FormulaCompiler::InitSymbolsPODF() const
706 static OpCodeMapData aMap;
707 osl::MutexGuard aGuard(&aMap.maMtx);
708 if (!aMap.mxSymbolMap)
709 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_PODF, aMap.mxSymbolMap, RESOURCE_BASE);
710 mxSymbolsPODF = aMap.mxSymbolMap;
713 void FormulaCompiler::InitSymbolsODFF() const
715 static OpCodeMapData aMap;
716 osl::MutexGuard aGuard(&aMap.maMtx);
717 if (!aMap.mxSymbolMap)
718 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF, FormulaGrammar::GRAM_ODFF, aMap.mxSymbolMap, RESOURCE_BASE);
719 mxSymbolsODFF = aMap.mxSymbolMap;
722 void FormulaCompiler::InitSymbolsEnglishXL() const
724 static OpCodeMapData aMap;
725 osl::MutexGuard aGuard(&aMap.maMtx);
726 if (!aMap.mxSymbolMap)
727 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
728 mxSymbolsEnglishXL = aMap.mxSymbolMap;
730 // TODO: For now, just replace the separators to the Excel English
731 // variants. Later, if we want to properly map Excel functions with Calc
732 // functions, we'll need to do a little more work here.
733 mxSymbolsEnglishXL->putOpCode( OUString(','), ocSep, NULL);
734 mxSymbolsEnglishXL->putOpCode( OUString(','), ocArrayColSep, NULL);
735 mxSymbolsEnglishXL->putOpCode( OUString(';'), ocArrayRowSep, NULL);
738 void FormulaCompiler::InitSymbolsOOXML() const
740 static OpCodeMapData aMap;
741 osl::MutexGuard aGuard(&aMap.maMtx);
742 if (!aMap.mxSymbolMap)
743 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML, FormulaGrammar::GRAM_OOXML, aMap.mxSymbolMap, RESOURCE_BASE);
744 mxSymbolsOOXML = aMap.mxSymbolMap;
748 void FormulaCompiler::loadSymbols( sal_uInt16 nSymbols, FormulaGrammar::Grammar eGrammar,
749 NonConstOpCodeMapPtr& rxMap, SeparatorType eSepType) const
751 if ( !rxMap.get() )
753 // not Core
754 rxMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, eGrammar != FormulaGrammar::GRAM_ODFF, eGrammar ));
755 OModuleClient aModuleClient;
756 OpCodeList aOpCodeList( nSymbols, rxMap, eSepType);
758 fillFromAddInMap( rxMap, eGrammar);
759 // Fill from collection for AddIns not already present.
760 if ( FormulaGrammar::GRAM_ENGLISH != eGrammar )
761 fillFromAddInCollectionUpperName( rxMap);
762 else
763 fillFromAddInCollectionEnglishName( rxMap);
767 void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const
771 void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const
775 void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const
779 OpCode FormulaCompiler::GetEnglishOpCode( const OUString& rName ) const
781 FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap( sheet::FormulaLanguage::ENGLISH);
783 formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) );
784 bool bFound = (iLook != xMap->getHashMap()->end());
785 return bFound ? (*iLook).second : OpCode(ocNone);
788 bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
790 bool bRet = false;
791 switch (eOp)
793 // no parameters:
794 case ocRandom:
795 case ocGetActDate:
796 case ocGetActTime:
797 // one parameter:
798 case ocFormula:
799 case ocInfo:
800 // more than one parameters:
801 // ocIndirect/ocIndirectXL otherwise would have to do
802 // StopListening and StartListening on a reference for every
803 // interpreted value.
804 case ocIndirect:
805 case ocIndirectXL:
806 // ocOffset results in indirect references.
807 case ocOffset:
808 // ocDebugVar shows internal value that may change as the internal state changes.
809 case ocDebugVar:
810 bRet = true;
811 break;
812 default:
813 bRet = false;
814 break;
816 return bRet;
819 bool FormulaCompiler::IsOpCodeJumpCommand( OpCode eOp )
821 switch (eOp)
823 case ocIf:
824 case ocIfError:
825 case ocIfNA:
826 case ocChoose:
827 return true;
828 default:
831 return false;
834 // Remove quotes, escaped quotes are unescaped.
835 bool FormulaCompiler::DeQuote( OUString& rStr )
837 sal_Int32 nLen = rStr.getLength();
838 if ( nLen > 1 && rStr[0] == '\'' && rStr[ nLen-1 ] == '\'' )
840 rStr = rStr.copy( 1, nLen-2 );
841 rStr = rStr.replaceAll( "\\\'", "\'" );
842 return true;
844 return false;
847 void FormulaCompiler::fillAddInToken(
848 ::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,
849 bool /*_bIsEnglish*/) const
853 bool FormulaCompiler::IsMatrixFunction( OpCode eOpCode )
855 switch (eOpCode)
857 case ocDde :
858 case ocGrowth :
859 case ocTrend :
860 case ocLogest :
861 case ocLinest :
862 case ocFrequency :
863 case ocMatTrans :
864 case ocMatMult :
865 case ocMatInv :
866 case ocMatrixUnit :
867 case ocModalValue_Multi :
868 return true;
869 default:
871 // added to avoid warnings
874 return false;
878 FormulaCompiler::OpCodeMap::~OpCodeMap()
880 delete mpReverseExternalHashMap;
881 delete mpExternalHashMap;
882 delete [] mpTable;
883 delete mpHashMap;
886 void FormulaCompiler::OpCodeMap::putCopyOpCode( const OUString& rSymbol, OpCode eOp )
888 SAL_WARN_IF( !mpTable[eOp].isEmpty() && rSymbol.isEmpty(), "formula.core",
889 "OpCodeMap::putCopyOpCode: NOT replacing OpCode " << static_cast<sal_uInt16>(eOp)
890 << " '" << mpTable[eOp] << "' with empty name!");
891 if (!mpTable[eOp].isEmpty() && rSymbol.isEmpty())
892 mpHashMap->insert( OpCodeHashMap::value_type( mpTable[eOp], eOp));
893 else
895 mpTable[eOp] = rSymbol;
896 mpHashMap->insert( OpCodeHashMap::value_type( rSymbol, eOp));
900 void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap& r, bool bOverrideKnownBad )
902 delete mpHashMap;
903 mpHashMap = new OpCodeHashMap( mnSymbols);
905 sal_uInt16 n = r.getSymbolCount();
906 SAL_WARN_IF( n != mnSymbols, "formula.core",
907 "OpCodeMap::copyFrom: unequal size, this: " << mnSymbols << " that: " << n);
908 if (n > mnSymbols)
909 n = mnSymbols;
911 // OpCode 0 (ocPush) should never be in a map.
912 SAL_WARN_IF( !mpTable[0].isEmpty() || !r.mpTable[0].isEmpty(), "formula.core",
913 "OpCodeMap::copyFrom: OpCode 0 assigned, this: '"
914 << mpTable[0] << "' that: '" << r.mpTable[0] << "'");
916 // For bOverrideKnownBad when copying from the English core map (ODF 1.1
917 // and API) to the native map (UI "use English function names") replace the
918 // known bad legacy function names with correct ones.
919 if (bOverrideKnownBad && r.mbCore &&
920 FormulaGrammar::extractFormulaLanguage( meGrammar) == sheet::FormulaLanguage::NATIVE &&
921 FormulaGrammar::extractFormulaLanguage( r.meGrammar) == sheet::FormulaLanguage::ENGLISH)
923 for (sal_uInt16 i = 1; i < n; ++i)
925 OUString aSymbol;
926 OpCode eOp = OpCode(i);
927 switch (eOp)
929 case ocRRI:
930 aSymbol = "RRI";
931 break;
932 case ocTableOp:
933 aSymbol = "MULTIPLE.OPERATIONS";
934 break;
935 default:
936 aSymbol = r.mpTable[i];
938 putCopyOpCode( aSymbol, eOp);
941 else
943 for (sal_uInt16 i = 1; i < n; ++i)
945 OpCode eOp = OpCode(i);
946 const OUString& rSymbol = r.mpTable[i];
947 putCopyOpCode( rSymbol, eOp);
951 // TODO: maybe copy the external maps too?
955 sal_uInt16 FormulaCompiler::GetErrorConstant( const OUString& rName ) const
957 sal_uInt16 nError = 0;
958 OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
959 if (iLook != mxSymbols->getHashMap()->end())
961 switch ((*iLook).second)
963 // Not all may make sense in a formula, but these we know as
964 // opcodes.
965 case ocErrNull:
966 nError = errNoCode;
967 break;
968 case ocErrDivZero:
969 nError = errDivisionByZero;
970 break;
971 case ocErrValue:
972 nError = errNoValue;
973 break;
974 case ocErrRef:
975 nError = errNoRef;
976 break;
977 case ocErrName:
978 nError = errNoName;
979 break;
980 case ocErrNum:
981 nError = errIllegalFPOperation;
982 break;
983 case ocErrNA:
984 nError = NOTAVAILABLE;
985 break;
986 default:
987 ; // nothing
990 return nError;
993 void FormulaCompiler::EnableJumpCommandReorder( bool bEnable )
995 mbJumpCommandReorder = bEnable;
998 void FormulaCompiler::EnableStopOnError( bool bEnable )
1000 mbStopOnError = bEnable;
1003 void FormulaCompiler::AppendErrorConstant( OUStringBuffer& rBuffer, sal_uInt16 nError ) const
1005 OpCode eOp;
1006 switch (nError)
1008 default:
1009 case errNoCode:
1010 eOp = ocErrNull;
1011 break;
1012 case errDivisionByZero:
1013 eOp = ocErrDivZero;
1014 break;
1015 case errNoValue:
1016 eOp = ocErrValue;
1017 break;
1018 case errNoRef:
1019 eOp = ocErrRef;
1020 break;
1021 case errNoName:
1022 eOp = ocErrName;
1023 break;
1024 case errIllegalFPOperation:
1025 eOp = ocErrNum;
1026 break;
1027 case NOTAVAILABLE:
1028 eOp = ocErrNA;
1029 break;
1031 rBuffer.append( mxSymbols->getSymbol( eOp));
1035 sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
1037 static const sal_Int32 kOpCodeUnknown = -1;
1038 return kOpCodeUnknown;
1041 bool FormulaCompiler::GetToken()
1043 static const short nRecursionMax = 42;
1044 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
1045 if ( nRecursion > nRecursionMax )
1047 SetError( errStackOverflow );
1048 mpToken = new FormulaByteToken( ocStop );
1049 return false;
1051 if ( bAutoCorrect && !pStack )
1052 { // don't merge stacked subroutine code into entered formula
1053 aCorrectedFormula += aCorrectedSymbol;
1054 aCorrectedSymbol.clear();
1056 bool bStop = false;
1057 if (pArr->GetCodeError() && mbStopOnError)
1058 bStop = true;
1059 else
1061 short nWasColRowName;
1062 if ( pArr->nIndex
1063 && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
1064 nWasColRowName = 1;
1065 else
1066 nWasColRowName = 0;
1067 mpToken = pArr->Next();
1068 while( mpToken && mpToken->GetOpCode() == ocSpaces )
1070 if ( nWasColRowName )
1071 nWasColRowName++;
1072 if ( bAutoCorrect && !pStack )
1073 CreateStringFromToken( aCorrectedFormula, mpToken.get(), false );
1074 mpToken = pArr->Next();
1076 if ( bAutoCorrect && !pStack && mpToken )
1077 CreateStringFromToken( aCorrectedSymbol, mpToken.get(), false );
1078 if( !mpToken )
1080 if( pStack )
1082 PopTokenArray();
1083 return GetToken();
1085 else
1086 bStop = true;
1088 else
1090 if ( nWasColRowName >= 2 && mpToken->GetOpCode() == ocColRowName )
1091 { // convert an ocSpaces to ocIntersect in RPN
1092 mpToken = new FormulaByteToken( ocIntersect );
1093 pArr->nIndex--; // we advanced to the second ocColRowName, step back
1097 if( bStop )
1099 mpToken = new FormulaByteToken( ocStop );
1100 return false;
1102 if ( mpToken->GetOpCode() == ocSubTotal ||
1103 mpToken->GetOpCode() == ocAggregate )
1104 glSubTotal = true;
1105 else if ( mpToken->IsExternalRef() )
1107 return HandleExternalReference(*mpToken);
1109 else if( mpToken->GetOpCode() == ocName )
1111 return HandleRange();
1113 else if( mpToken->GetOpCode() == ocColRowName )
1115 return HandleColRowName();
1117 else if( mpToken->GetOpCode() == ocDBArea )
1119 return HandleDbData();
1121 else if( mpToken->GetOpCode() == ocTableRef )
1123 return HandleTableRef();
1125 return true;
1129 // RPN creation by recursion
1130 void FormulaCompiler::Factor()
1132 if (pArr->GetCodeError() && mbStopOnError)
1133 return;
1135 CurrentFactor pFacToken( this );
1137 OpCode eOp = mpToken->GetOpCode();
1138 if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
1139 eOp == ocDBArea || eOp == ocTableRef
1140 || (!mbJumpCommandReorder && ((eOp == ocName) || (eOp == ocDBArea)
1141 || (eOp == ocTableRef) || (eOp == ocColRowName) || (eOp == ocBad)))
1144 PutCode( mpToken );
1145 eOp = NextToken();
1146 if( eOp == ocOpen )
1148 // PUSH( is an error that may be caused by an unknown function.
1149 SetError(
1150 ( mpToken->GetType() == svString
1151 || mpToken->GetType() == svSingleRef )
1152 ? errNoName : errOperatorExpected );
1153 if ( bAutoCorrect && !pStack )
1154 { // assume multiplication
1155 aCorrectedFormula += mxSymbols->getSymbol( ocMul);
1156 bCorrected = true;
1157 NextToken();
1158 eOp = Expression();
1159 if( eOp != ocClose )
1160 SetError( errPairExpected);
1161 else
1162 eOp = NextToken();
1166 else if( eOp == ocOpen )
1168 NextToken();
1169 eOp = Expression();
1170 while ((eOp == ocSep) && (!pArr->GetCodeError() || !mbStopOnError))
1171 { // range list (A1;A2) converted to (A1~A2)
1172 pFacToken = mpToken;
1173 NextToken();
1174 CheckSetForceArrayParameter( mpToken, 0);
1175 eOp = Expression();
1176 // Do not ignore error here, regardless of bIgnoreErrors, otherwise
1177 // errors like =(1;) would also result in display of =(1~)
1178 if (!pArr->GetCodeError())
1180 pFacToken->NewOpCode( ocUnion, FormulaToken::PrivateAccess());
1181 PutCode( pFacToken);
1184 if (eOp != ocClose)
1185 SetError( errPairExpected);
1186 else
1187 eOp = NextToken();
1189 else
1191 if( nNumFmt == css::util::NumberFormat::UNDEFINED )
1192 nNumFmt = lcl_GetRetFormat( eOp );
1194 if ( IsOpCodeVolatile( eOp) )
1195 pArr->SetExclusiveRecalcModeAlways();
1196 else
1198 switch( eOp )
1200 // Functions recalculated on every document load.
1201 // Don't use SetExclusiveRecalcModeOnLoad() which would
1202 // override ModeAlways, use
1203 // AddRecalcMode(ScRecalcMode::ONLOAD) instead.
1204 case ocConvert :
1205 case ocDde:
1206 case ocMacro:
1207 case ocExternal:
1208 pArr->AddRecalcMode( ScRecalcMode::ONLOAD );
1209 break;
1210 // If the referred cell is moved the value changes.
1211 case ocColumn :
1212 case ocRow :
1213 pArr->SetRecalcModeOnRefMove();
1214 break;
1215 // ocCell needs recalc on move for some possible type values.
1216 // and recalc mode on load, fdo#60646
1217 case ocCell :
1218 pArr->SetRecalcModeOnRefMove();
1219 pArr->AddRecalcMode( ScRecalcMode::ONLOAD );
1220 break;
1221 case ocHyperLink :
1222 // cell with hyperlink needs to be calculated on load to
1223 // get its matrix result generated.
1224 pArr->AddRecalcMode( ScRecalcMode::ONLOAD );
1225 pArr->SetHyperLink( true);
1226 break;
1227 default:
1228 ; // nothing
1231 if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
1233 pFacToken = mpToken;
1234 eOp = NextToken();
1235 if (eOp != ocOpen)
1237 SetError( errPairExpected);
1238 PutCode( pFacToken );
1240 else
1242 eOp = NextToken();
1243 if (eOp != ocClose)
1244 SetError( errPairExpected);
1245 PutCode( pFacToken);
1246 eOp = NextToken();
1249 // special cases NOT() and NEG()
1250 else if( eOp == ocNot || eOp == ocNeg
1251 || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
1253 pFacToken = mpToken;
1254 eOp = NextToken();
1255 if( nNumFmt == css::util::NumberFormat::UNDEFINED && eOp == ocNot )
1256 nNumFmt = css::util::NumberFormat::LOGICAL;
1257 if (eOp == ocOpen)
1259 NextToken();
1260 CheckSetForceArrayParameter( mpToken, 0);
1261 eOp = Expression();
1263 else
1264 SetError( errPairExpected);
1265 if (eOp != ocClose)
1266 SetError( errPairExpected);
1267 else if ( !pArr->GetCodeError() )
1268 pFacToken->SetByte( 1 );
1269 PutCode( pFacToken );
1270 eOp = NextToken();
1272 else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
1273 || eOp == ocExternal
1274 || eOp == ocMacro
1275 || eOp == ocAnd
1276 || eOp == ocOr
1277 || eOp == ocBad
1278 || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1279 || (!mbJumpCommandReorder && IsOpCodeJumpCommand(eOp)))
1281 pFacToken = mpToken;
1282 OpCode eMyLastOp = eOp;
1283 eOp = NextToken();
1284 bool bNoParam = false;
1285 bool bBadName = false;
1286 if (eOp == ocOpen)
1288 eOp = NextToken();
1289 if (eOp == ocClose)
1290 bNoParam = true;
1291 else
1293 CheckSetForceArrayParameter( mpToken, 0);
1294 eOp = Expression();
1297 else if (eMyLastOp == ocBad)
1299 // Just a bad name, not an unknown function, no parameters, no
1300 // closing expected.
1301 bBadName = true;
1302 bNoParam = true;
1304 else
1305 SetError( errPairExpected);
1306 sal_uInt8 nSepCount = 0;
1307 if( !bNoParam )
1309 nSepCount++;
1310 while ((eOp == ocSep) && (!pArr->GetCodeError() || !mbStopOnError))
1312 NextToken();
1313 CheckSetForceArrayParameter( mpToken, nSepCount);
1314 nSepCount++;
1315 eOp = Expression();
1318 if (bBadName)
1319 ; // nothing, keep current token for return
1320 else if (eOp != ocClose)
1321 SetError( errPairExpected);
1322 else
1323 eOp = NextToken();
1324 // Jumps are just normal functions for the FunctionAutoPilot tree view
1325 if (!mbJumpCommandReorder && pFacToken->GetType() == svJump)
1326 pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
1327 else
1328 pFacToken->SetByte( nSepCount );
1329 PutCode( pFacToken );
1331 else if (IsOpCodeJumpCommand(eOp))
1333 // the PC counters are -1
1334 pFacToken = mpToken;
1335 switch (eOp)
1337 case ocIf:
1338 pFacToken->GetJump()[ 0 ] = 3; // if, else, behind
1339 break;
1340 case ocChoose:
1341 pFacToken->GetJump()[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
1342 break;
1343 case ocIfError:
1344 case ocIfNA:
1345 pFacToken->GetJump()[ 0 ] = 2; // if, behind
1346 break;
1347 default:
1348 SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump count case?");
1350 eOp = NextToken();
1351 if (eOp == ocOpen)
1353 NextToken();
1354 CheckSetForceArrayParameter( mpToken, 0);
1355 eOp = Expression();
1357 else
1358 SetError( errPairExpected);
1359 PutCode( pFacToken );
1360 // During AutoCorrect (since pArr->GetCodeError() is
1361 // ignored) an unlimited ocIf would crash because
1362 // ScRawToken::Clone() allocates the JumpBuffer according to
1363 // nJump[0]*2+2, which is 3*2+2 on ocIf and 2*2+2 ocIfError and ocIfNA.
1364 short nJumpMax;
1365 OpCode eFacOpCode = pFacToken->GetOpCode();
1366 switch (eFacOpCode)
1368 case ocIf:
1369 nJumpMax = 3;
1370 break;
1371 case ocChoose:
1372 nJumpMax = FORMULA_MAXJUMPCOUNT;
1373 break;
1374 case ocIfError:
1375 case ocIfNA:
1376 nJumpMax = 2;
1377 break;
1378 default:
1379 nJumpMax = 0;
1380 SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump max case?");
1382 short nJumpCount = 0;
1383 while ( (nJumpCount < (FORMULA_MAXJUMPCOUNT - 1)) && (eOp == ocSep)
1384 && (!pArr->GetCodeError() || !mbStopOnError))
1386 if ( ++nJumpCount <= nJumpMax )
1387 pFacToken->GetJump()[nJumpCount] = pc-1;
1388 NextToken();
1389 CheckSetForceArrayParameter( mpToken, nJumpCount - 1);
1390 eOp = Expression();
1391 // ocSep or ocClose terminate the subexpression
1392 PutCode( mpToken );
1394 if (eOp != ocClose)
1395 SetError( errPairExpected);
1396 else
1398 eOp = NextToken();
1399 // always limit to nJumpMax, no arbitrary overwrites
1400 if ( ++nJumpCount <= nJumpMax )
1401 pFacToken->GetJump()[ nJumpCount ] = pc-1;
1402 eFacOpCode = pFacToken->GetOpCode();
1403 bool bLimitOk;
1404 switch (eFacOpCode)
1406 case ocIf:
1407 bLimitOk = (nJumpCount <= 3);
1408 break;
1409 case ocChoose:
1410 bLimitOk = (nJumpCount < FORMULA_MAXJUMPCOUNT); /* TODO: check, really <, not <=? */
1411 break;
1412 case ocIfError:
1413 case ocIfNA:
1414 bLimitOk = (nJumpCount <= 2);
1415 break;
1416 default:
1417 bLimitOk = false;
1418 SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump limit case?");
1420 if (bLimitOk)
1421 pFacToken->GetJump()[ 0 ] = nJumpCount;
1422 else
1423 SetError( errIllegalParameter);
1426 else if ( eOp == ocMissing )
1428 PutCode( mpToken );
1429 eOp = NextToken();
1431 else if ( eOp == ocClose )
1433 SetError( errParameterExpected );
1435 else if ( eOp == ocSep )
1436 { // Subsequent ocSep
1437 SetError( errParameterExpected );
1438 if ( bAutoCorrect && !pStack )
1440 aCorrectedSymbol.clear();
1441 bCorrected = true;
1444 else if ( mpToken->IsExternalRef() )
1446 PutCode( mpToken);
1447 eOp = NextToken();
1449 else
1451 SetError( errUnknownToken );
1452 if ( bAutoCorrect && !pStack )
1454 if ( eOp == ocStop )
1455 { // trailing operator w/o operand
1456 sal_Int32 nLen = aCorrectedFormula.getLength();
1457 if ( nLen )
1458 aCorrectedFormula = aCorrectedFormula.copy( 0, nLen - 1 );
1459 aCorrectedSymbol.clear();
1460 bCorrected = true;
1467 void FormulaCompiler::RangeLine()
1469 Factor();
1470 while (mpToken->GetOpCode() == ocRange)
1472 FormulaToken** pCode1 = pCode - 1;
1473 FormulaTokenRef p = mpToken;
1474 NextToken();
1475 Factor();
1476 FormulaToken** pCode2 = pCode - 1;
1477 if (!MergeRangeReference( pCode1, pCode2))
1478 PutCode(p);
1482 void FormulaCompiler::IntersectionLine()
1484 RangeLine();
1485 while (mpToken->GetOpCode() == ocIntersect)
1487 FormulaTokenRef p = mpToken;
1488 NextToken();
1489 RangeLine();
1490 PutCode(p);
1494 void FormulaCompiler::UnionLine()
1496 IntersectionLine();
1497 while (mpToken->GetOpCode() == ocUnion)
1499 FormulaTokenRef p = mpToken;
1500 NextToken();
1501 IntersectionLine();
1502 PutCode(p);
1506 void FormulaCompiler::UnaryLine()
1508 if( mpToken->GetOpCode() == ocAdd )
1509 GetToken();
1510 else if (SC_OPCODE_START_UN_OP <= mpToken->GetOpCode() &&
1511 mpToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
1513 FormulaTokenRef p = mpToken;
1514 NextToken();
1515 UnaryLine();
1516 PutCode( p );
1518 else
1519 UnionLine();
1522 void FormulaCompiler::PostOpLine()
1524 UnaryLine();
1525 while ( mpToken->GetOpCode() == ocPercentSign )
1526 { // this operator _follows_ its operand
1527 PutCode( mpToken );
1528 NextToken();
1532 void FormulaCompiler::PowLine()
1534 PostOpLine();
1535 while (mpToken->GetOpCode() == ocPow)
1537 FormulaTokenRef p = mpToken;
1538 NextToken();
1539 PostOpLine();
1540 PutCode(p);
1544 void FormulaCompiler::MulDivLine()
1546 PowLine();
1547 while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv)
1549 FormulaTokenRef p = mpToken;
1550 NextToken();
1551 PowLine();
1552 PutCode(p);
1556 void FormulaCompiler::AddSubLine()
1558 MulDivLine();
1559 while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub)
1561 FormulaTokenRef p = mpToken;
1562 NextToken();
1563 MulDivLine();
1564 PutCode(p);
1568 void FormulaCompiler::ConcatLine()
1570 AddSubLine();
1571 while (mpToken->GetOpCode() == ocAmpersand)
1573 FormulaTokenRef p = mpToken;
1574 NextToken();
1575 AddSubLine();
1576 PutCode(p);
1580 void FormulaCompiler::CompareLine()
1582 ConcatLine();
1583 while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual)
1585 FormulaTokenRef p = mpToken;
1586 NextToken();
1587 ConcatLine();
1588 PutCode(p);
1592 void FormulaCompiler::NotLine()
1594 CompareLine();
1595 while (mpToken->GetOpCode() == ocNot)
1597 FormulaTokenRef p = mpToken;
1598 NextToken();
1599 CompareLine();
1600 PutCode(p);
1604 OpCode FormulaCompiler::Expression()
1606 static const short nRecursionMax = 42;
1607 FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
1608 if ( nRecursion > nRecursionMax )
1610 SetError( errStackOverflow );
1611 return ocStop; //! generate token instead?
1613 NotLine();
1614 while (mpToken->GetOpCode() == ocAnd || mpToken->GetOpCode() == ocOr)
1616 FormulaTokenRef p = mpToken;
1617 mpToken->SetByte( 2 ); // 2 parameters!
1618 NextToken();
1619 NotLine();
1620 PutCode(p);
1622 return mpToken->GetOpCode();
1626 void FormulaCompiler::SetError( sal_uInt16 /*nError*/ )
1630 FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/,
1631 bool /*bReuseDoubleRef*/ )
1633 return FormulaTokenRef();
1636 bool FormulaCompiler::MergeRangeReference( FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
1638 FormulaToken *p1, *p2;
1639 if (pc < 2 || !pCode1 || !pCode2 ||
1640 (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
1641 ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
1642 return false;
1644 FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
1645 if (!p)
1646 return false;
1648 p->IncRef();
1649 p1->DecRef();
1650 p2->DecRef();
1651 *pCode1 = p.get();
1652 --pCode, --pc;
1654 return true;
1657 bool FormulaCompiler::CompileTokenArray()
1659 glSubTotal = false;
1660 bCorrected = false;
1661 if (!pArr->GetCodeError() || !mbStopOnError)
1663 if ( bAutoCorrect )
1665 aCorrectedFormula.clear();
1666 aCorrectedSymbol.clear();
1668 pArr->DelRPN();
1669 pStack = NULL;
1670 FormulaToken* pData[ FORMULA_MAXTOKENS ];
1671 pCode = pData;
1672 bool bWasForced = pArr->IsRecalcModeForced();
1673 if ( bWasForced )
1675 if ( bAutoCorrect )
1676 aCorrectedFormula = "=";
1678 pArr->ClearRecalcMode();
1679 pArr->Reset();
1680 eLastOp = ocOpen;
1681 pc = 0;
1682 NextToken();
1683 OpCode eOp = Expression();
1684 // Some trailing garbage that doesn't form an expression?
1685 if (eOp != ocStop)
1686 SetError( errOperatorExpected);
1688 sal_uInt16 nErrorBeforePop = pArr->GetCodeError();
1690 while( pStack )
1691 PopTokenArray();
1692 if( pc )
1694 pArr->pRPN = new FormulaToken*[ pc ];
1695 pArr->nRPN = pc;
1696 memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
1699 // once an error, always an error
1700 if( !pArr->GetCodeError() && nErrorBeforePop )
1701 pArr->SetCodeError( nErrorBeforePop);
1703 if (pArr->GetCodeError() && mbStopOnError)
1705 pArr->DelRPN();
1706 pArr->SetHyperLink( false);
1709 if ( bWasForced )
1710 pArr->SetRecalcModeForced();
1712 if( nNumFmt == css::util::NumberFormat::UNDEFINED )
1713 nNumFmt = css::util::NumberFormat::NUMBER;
1714 return glSubTotal;
1717 void FormulaCompiler::PopTokenArray()
1719 if( pStack )
1721 FormulaArrayStack* p = pStack;
1722 pStack = p->pNext;
1723 // obtain special RecalcMode from SharedFormula
1724 if ( pArr->IsRecalcModeAlways() )
1725 p->pArr->SetExclusiveRecalcModeAlways();
1726 else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
1727 p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
1728 p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
1729 if ( pArr->IsHyperLink() ) // fdo 87534
1730 p->pArr->SetHyperLink( true );
1731 if( p->bTemp )
1732 delete pArr;
1733 pArr = p->pArr;
1734 delete p;
1738 void FormulaCompiler::CreateStringFromTokenArray( OUString& rFormula )
1740 OUStringBuffer aBuffer( pArr->GetLen() * 5 );
1741 CreateStringFromTokenArray( aBuffer );
1742 rFormula = aBuffer.makeStringAndClear();
1745 void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer )
1747 rBuffer.setLength(0);
1748 if( !pArr->GetLen() )
1749 return;
1751 FormulaTokenArray* pSaveArr = pArr;
1752 bool bODFF = FormulaGrammar::isODFF( meGrammar);
1753 if (bODFF || FormulaGrammar::isPODF( meGrammar) )
1755 // Scan token array for missing args and re-write if present.
1756 MissingConventionODF aConv( bODFF);
1757 if (pArr->NeedsPodfRewrite( aConv))
1758 pArr = pArr->RewriteMissing( aConv );
1760 else if ( FormulaGrammar::isOOXML( meGrammar ) )
1762 // Scan token array for missing args and rewrite if present.
1763 MissingConventionOOXML aConv;
1764 if (pArr->NeedsOoxmlRewrite())
1765 pArr = pArr->RewriteMissing( aConv );
1768 // At least one character per token, plus some are references, some are
1769 // function names, some are numbers, ...
1770 rBuffer.ensureCapacity( pArr->GetLen() * 5 );
1772 if ( pArr->IsRecalcModeForced() )
1773 rBuffer.append( '=');
1774 const FormulaToken* t = pArr->First();
1775 while( t )
1776 t = CreateStringFromToken( rBuffer, t, true );
1778 if (pSaveArr != pArr)
1780 delete pArr;
1781 pArr = pSaveArr;
1785 const FormulaToken* FormulaCompiler::CreateStringFromToken( OUString& rFormula, const FormulaToken* pTokenP,
1786 bool bAllowArrAdvance )
1788 OUStringBuffer aBuffer;
1789 const FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
1790 rFormula += aBuffer.makeStringAndClear();
1791 return p;
1794 const FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuffer, const FormulaToken* pTokenP,
1795 bool bAllowArrAdvance )
1797 bool bNext = true;
1798 bool bSpaces = false;
1799 const FormulaToken* t = pTokenP;
1800 OpCode eOp = t->GetOpCode();
1801 if( eOp >= ocAnd && eOp <= ocOr )
1803 // AND, OR infix?
1804 if ( bAllowArrAdvance )
1805 t = pArr->Next();
1806 else
1807 t = pArr->PeekNext();
1808 bNext = false;
1809 bSpaces = ( !t || t->GetOpCode() != ocOpen );
1811 if( bSpaces )
1812 rBuffer.append( ' ');
1814 if( eOp == ocSpaces )
1816 bool bIntersectionOp = mxSymbols->isODFF();
1817 if (bIntersectionOp)
1819 const FormulaToken* p = pArr->PeekPrevNoSpaces();
1820 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1821 if (bIntersectionOp)
1823 p = pArr->PeekNextNoSpaces();
1824 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
1827 if (bIntersectionOp)
1828 rBuffer.appendAscii( "!!");
1829 else
1831 // most times it's just one blank
1832 sal_uInt8 n = t->GetByte();
1833 for ( sal_uInt8 j=0; j<n; ++j )
1835 rBuffer.append( ' ');
1839 else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
1840 rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
1841 else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount()) // Keyword:
1842 rBuffer.append( mxSymbols->getSymbol( eOp));
1843 else
1845 SAL_WARN( "formula.core","unknown OpCode");
1846 rBuffer.append( GetNativeSymbol( ocErrName ));
1848 if( bNext )
1850 if (t->IsExternalRef())
1852 CreateStringFromExternal( rBuffer, pTokenP);
1854 else
1856 switch( t->GetType() )
1858 case svDouble:
1859 AppendDouble( rBuffer, t->GetDouble() );
1860 break;
1862 case svString:
1863 if( eOp == ocBad || eOp == ocStringXML )
1864 rBuffer.append( t->GetString().getString());
1865 else
1866 AppendString( rBuffer, t->GetString().getString() );
1867 break;
1868 case svSingleRef:
1869 CreateStringFromSingleRef( rBuffer, t);
1870 break;
1871 case svDoubleRef:
1872 CreateStringFromDoubleRef( rBuffer, t);
1873 break;
1874 case svMatrix:
1875 CreateStringFromMatrix( rBuffer, t );
1876 break;
1878 case svIndex:
1879 CreateStringFromIndex( rBuffer, t );
1880 if (t->GetOpCode() == ocTableRef && bAllowArrAdvance && NeedsTableRefTransformation())
1882 // Suppress all TableRef related tokens, the resulting
1883 // range was written by CreateStringFromIndex().
1884 const FormulaToken* const p = pArr->PeekNext();
1885 if (p && p->GetOpCode() == ocTableRefOpen)
1887 int nLevel = 0;
1890 t = pArr->Next();
1891 if (!t)
1892 break;
1894 // Switch cases correspond with those in
1895 // ScCompiler::HandleTableRef()
1896 switch (t->GetOpCode())
1898 case ocTableRefOpen:
1899 ++nLevel;
1900 break;
1901 case ocTableRefClose:
1902 --nLevel;
1903 break;
1904 case ocTableRefItemAll:
1905 case ocTableRefItemHeaders:
1906 case ocTableRefItemData:
1907 case ocTableRefItemTotals:
1908 case ocTableRefItemThisRow:
1909 case ocSep:
1910 case ocPush:
1911 case ocRange:
1912 case ocSpaces:
1913 break;
1914 default:
1915 nLevel = 0;
1916 bNext = false;
1918 } while (nLevel);
1921 break;
1922 case svExternal:
1924 // mapped or translated name of AddIns
1925 OUString aAddIn( t->GetExternal() );
1926 bool bMapped = mxSymbols->isPODF(); // ODF 1.1 directly uses programmatical name
1927 if (!bMapped && mxSymbols->hasExternals())
1929 ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
1930 if (iLook != mxSymbols->getReverseExternalHashMap()->end())
1932 aAddIn = (*iLook).second;
1933 bMapped = true;
1936 if (!bMapped && !mxSymbols->isEnglish())
1937 LocalizeString( aAddIn );
1938 rBuffer.append( aAddIn);
1940 break;
1941 case svError:
1942 AppendErrorConstant( rBuffer, t->GetError());
1943 break;
1944 case svByte:
1945 case svJump:
1946 case svFAP:
1947 case svMissing:
1948 case svSep:
1949 break; // Opcodes
1950 default:
1951 SAL_WARN("formula.core", "FormulaCompiler::GetStringFromToken: unknown token type " << t->GetType());
1952 } // of switch
1955 if( bSpaces )
1956 rBuffer.append( ' ');
1957 if ( bAllowArrAdvance )
1959 if( bNext )
1960 t = pArr->Next();
1961 return t;
1963 return pTokenP;
1967 void FormulaCompiler::AppendDouble( OUStringBuffer& rBuffer, double fVal ) const
1969 if ( mxSymbols->isEnglish() )
1971 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1972 rtl_math_StringFormat_Automatic,
1973 rtl_math_DecimalPlaces_Max, '.', true );
1975 else
1977 SvtSysLocale aSysLocale;
1978 ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
1979 rtl_math_StringFormat_Automatic,
1980 rtl_math_DecimalPlaces_Max,
1981 aSysLocale.GetLocaleDataPtr()->getNumDecimalSep()[0],
1982 true );
1986 void FormulaCompiler::AppendBoolean( OUStringBuffer& rBuffer, bool bVal ) const
1988 rBuffer.append( mxSymbols->getSymbol( static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
1991 void FormulaCompiler::AppendString( OUStringBuffer& rBuffer, const OUString & rStr )
1993 rBuffer.append( '"');
1994 if ( lcl_UnicodeStrChr( rStr.getStr(), '"' ) == NULL )
1995 rBuffer.append( rStr );
1996 else
1998 OUString aStr = rStr.replaceAll( "\"", "\"\"" );
1999 rBuffer.append(aStr);
2001 rBuffer.append( '"');
2004 bool FormulaCompiler::NeedsTableRefTransformation() const
2006 /* TODO: currently only UI representations use Table structured
2007 * references. Not defined in ODFF, and not implemented yet for OOXML
2008 * export. Change this once OOXML export is implemented, until then write
2009 * A1 style references also for OOXML to not lose functionality. */
2010 // Unnecessary to explicitly check for ODFF grammar as the ocTableRefOpen
2011 // symbol is not defined there.
2012 return mxSymbols->getSymbol( ocTableRefOpen).isEmpty() || FormulaGrammar::isPODF( meGrammar)
2013 || FormulaGrammar::isOOXML( meGrammar);
2016 void FormulaCompiler::UpdateSeparatorsNative(
2017 const OUString& rSep, const OUString& rArrayColSep, const OUString& rArrayRowSep )
2019 NonConstOpCodeMapPtr xSymbolsNative;
2020 lcl_fillNativeSymbols( xSymbolsNative);
2021 xSymbolsNative->putOpCode( rSep, ocSep, NULL);
2022 xSymbolsNative->putOpCode( rArrayColSep, ocArrayColSep, NULL);
2023 xSymbolsNative->putOpCode( rArrayRowSep, ocArrayRowSep, NULL);
2026 void FormulaCompiler::ResetNativeSymbols()
2028 NonConstOpCodeMapPtr xSymbolsNative;
2029 lcl_fillNativeSymbols( xSymbolsNative, true);
2030 lcl_fillNativeSymbols( xSymbolsNative);
2033 void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr& xMap )
2035 NonConstOpCodeMapPtr xSymbolsNative;
2036 lcl_fillNativeSymbols( xSymbolsNative);
2037 xSymbolsNative->copyFrom( *xMap, true);
2041 OpCode FormulaCompiler::NextToken()
2043 if( !GetToken() )
2044 return ocStop;
2045 OpCode eOp = mpToken->GetOpCode();
2046 // There must be an operator before a push
2047 if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
2048 !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
2049 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
2050 SetError( errOperatorExpected);
2051 // Operator and Plus => operator
2052 if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
2053 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
2054 eOp = NextToken();
2055 else
2057 // Before an operator there must not be another operator, with the
2058 // exception of AND and OR.
2059 if ( eOp != ocAnd && eOp != ocOr &&
2060 (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP )
2061 && (eLastOp == ocOpen || eLastOp == ocSep ||
2062 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
2064 SetError( errVariableExpected);
2065 if ( bAutoCorrect && !pStack )
2067 if ( eOp == eLastOp || eLastOp == ocOpen )
2068 { // throw away duplicated operator
2069 aCorrectedSymbol.clear();
2070 bCorrected = true;
2072 else
2074 sal_Int32 nPos = aCorrectedFormula.getLength();
2075 if ( nPos )
2077 nPos--;
2078 sal_Unicode c = aCorrectedFormula[ nPos ];
2079 switch ( eOp )
2080 { // swap operators
2081 case ocGreater:
2082 if ( c == mxSymbols->getSymbolChar( ocEqual) )
2083 { // >= instead of =>
2084 aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2085 OUString( mxSymbols->getSymbolChar(ocGreater) ) );
2086 aCorrectedSymbol = OUString(c);
2087 bCorrected = true;
2089 break;
2090 case ocLess:
2091 if ( c == mxSymbols->getSymbolChar( ocEqual) )
2092 { // <= instead of =<
2093 aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2094 OUString( mxSymbols->getSymbolChar(ocLess) ) );
2095 aCorrectedSymbol = OUString(c);
2096 bCorrected = true;
2098 else if ( c == mxSymbols->getSymbolChar( ocGreater) )
2099 { // <> instead of ><
2100 aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2101 OUString( mxSymbols->getSymbolChar(ocLess) ) );
2102 aCorrectedSymbol = OUString(c);
2103 bCorrected = true;
2105 break;
2106 case ocMul:
2107 if ( c == mxSymbols->getSymbolChar( ocSub) )
2108 { // *- instead of -*
2109 aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2110 OUString( mxSymbols->getSymbolChar(ocMul) ) );
2111 aCorrectedSymbol = OUString(c);
2112 bCorrected = true;
2114 break;
2115 case ocDiv:
2116 if ( c == mxSymbols->getSymbolChar( ocSub) )
2117 { // /- instead of -/
2118 aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
2119 OUString( mxSymbols->getSymbolChar(ocDiv) ) );
2120 aCorrectedSymbol = OUString(c);
2121 bCorrected = true;
2123 break;
2124 default:
2125 ; // nothing
2131 eLastOp = eOp;
2133 return eOp;
2135 void FormulaCompiler::PutCode( FormulaTokenRef& p )
2137 if( pc >= FORMULA_MAXTOKENS - 1 )
2139 if ( pc == FORMULA_MAXTOKENS - 1 )
2141 p = new FormulaByteToken( ocStop );
2142 p->IncRef();
2143 *pCode++ = p.get();
2144 ++pc;
2146 SetError( errCodeOverflow);
2147 return;
2149 if (pArr->GetCodeError() && mbJumpCommandReorder)
2150 return;
2151 ForceArrayOperator( p);
2152 p->IncRef();
2153 *pCode++ = p.get();
2154 pc++;
2158 bool FormulaCompiler::HandleExternalReference( const FormulaToken& /*_aToken*/)
2160 return true;
2163 bool FormulaCompiler::HandleRange()
2165 return true;
2168 bool FormulaCompiler::HandleColRowName()
2170 return true;
2173 bool FormulaCompiler::HandleDbData()
2175 return true;
2178 bool FormulaCompiler::HandleTableRef()
2180 return true;
2183 void FormulaCompiler::CreateStringFromSingleRef( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
2187 void FormulaCompiler::CreateStringFromDoubleRef( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
2191 void FormulaCompiler::CreateStringFromIndex( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
2195 void FormulaCompiler::CreateStringFromMatrix( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
2199 void FormulaCompiler::CreateStringFromExternal( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
2203 void FormulaCompiler::LocalizeString( OUString& /*rName*/ ) const
2207 bool FormulaCompiler::IsForceArrayParameter( const FormulaToken* /*pToken*/, sal_uInt16 /*nParam*/ ) const
2209 return false;
2212 void FormulaCompiler::ForceArrayOperator( FormulaTokenRef& rCurr )
2214 if (!pCurrentFactorToken || (pCurrentFactorToken.get() == rCurr.get()))
2215 return;
2217 if (!(rCurr->GetOpCode() != ocPush && (rCurr->GetType() == svByte || rCurr->GetType() == svJump)))
2218 return;
2220 if (pCurrentFactorToken->HasForceArray())
2222 rCurr->SetForceArray( true);
2223 return;
2226 if (nCurrentFactorParam && IsForceArrayParameter( pCurrentFactorToken.get(),
2227 static_cast<sal_uInt8>(nCurrentFactorParam - 1)))
2228 rCurr->SetForceArray( true);
2231 void FormulaCompiler::CheckSetForceArrayParameter( FormulaTokenRef& rCurr, sal_uInt8 nParam )
2233 if (!pCurrentFactorToken)
2234 return;
2236 nCurrentFactorParam = nParam + 1;
2238 ForceArrayOperator( rCurr);
2241 void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
2243 if ( bAutoCorrect && !pStack )
2244 { // don't merge stacked subroutine code into entered formula
2245 aCorrectedFormula += aCorrectedSymbol;
2246 aCorrectedSymbol.clear();
2248 FormulaArrayStack* p = new FormulaArrayStack;
2249 p->pNext = pStack;
2250 p->pArr = pArr;
2251 p->bTemp = bTemp;
2252 pStack = p;
2253 pArr = pa;
2256 } // namespace formula
2258 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */