LCOV - code coverage report
Current view: top level - formula/source/core/api - FormulaCompiler.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 758 1098 69.0 %
Date: 2015-06-13 12:38:46 Functions: 71 97 73.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : #include <sal/macros.h>
      20             : #include "formula/FormulaCompiler.hxx"
      21             : #include "formula/errorcodes.hxx"
      22             : #include "formula/token.hxx"
      23             : #include "formula/tokenarray.hxx"
      24             : #include "core_resource.hxx"
      25             : #include "core_resource.hrc"
      26             : 
      27             : #include "osl/mutex.hxx"
      28             : 
      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>
      37             : 
      38             : namespace formula
      39             : {
      40             :     using namespace ::com::sun::star;
      41             : 
      42             :     static const sal_Char* pInternal[2] = { "TTT", "__DEBUG_VAR" };
      43             : 
      44             : namespace {
      45             : 
      46             : class FormulaCompilerRecursionGuard
      47             : {
      48             : private:
      49             :             short&              rRecursion;
      50             : public:
      51       95140 :                                 FormulaCompilerRecursionGuard( short& rRec )
      52       95140 :                                     : rRecursion( rRec ) { ++rRecursion; }
      53       95140 :                                 ~FormulaCompilerRecursionGuard() { --rRecursion; }
      54             : };
      55             : 
      56        5705 : short lcl_GetRetFormat( OpCode eOpCode )
      57             : {
      58        5705 :     switch (eOpCode)
      59             :     {
      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         195 :             return css::util::NumberFormat::LOGICAL;
      86             :         case ocGetActDate:
      87             :         case ocGetDate:
      88             :         case ocEasterSunday :
      89           4 :             return css::util::NumberFormat::DATE;
      90             :         case ocGetActTime:
      91           3 :             return css::util::NumberFormat::DATETIME;
      92             :         case ocGetTime:
      93           0 :             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          36 :             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          16 :             return css::util::NumberFormat::PERCENT;
     116             :         default:
     117        5451 :             return css::util::NumberFormat::NUMBER;
     118             :     }
     119             : }
     120             : 
     121      188069 : inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
     122             :         const OUString* pTable, sal_uInt16 nOpCode )
     123             : {
     124      188069 :     sheet::FormulaOpCodeMapEntry aEntry;
     125      188069 :     aEntry.Token.OpCode = nOpCode;
     126      188069 :     aEntry.Name = pTable[nOpCode];
     127      188069 :     rVec.push_back( aEntry);
     128      188069 : }
     129             : 
     130         938 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
     131             :         const OUString* pTable, sal_uInt16 nOpCodeBeg, sal_uInt16 nOpCodeEnd )
     132             : {
     133       45493 :     for (sal_uInt16 nOpCode = nOpCodeBeg; nOpCode < nOpCodeEnd; ++nOpCode)
     134       44555 :         lclPushOpCodeMapEntry( rVec, pTable, nOpCode );
     135         938 : }
     136             : 
     137        1407 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
     138             :         const OUString* pTable, const sal_uInt16* pnOpCodes, size_t nCount )
     139             : {
     140        8442 :     for (const sal_uInt16* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes)
     141        7035 :         lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes );
     142        1407 : }
     143             : 
     144         153 : class OpCodeList : public Resource        // temp object for resource
     145             : {
     146             : public:
     147             : 
     148             :     OpCodeList( sal_uInt16, FormulaCompiler::NonConstOpCodeMapPtr,
     149             :             FormulaCompiler::SeparatorType = FormulaCompiler::SEMICOLON_BASE );
     150             : 
     151             : private:
     152             :     bool getOpCodeString( OUString& rStr, sal_uInt16 nOp );
     153             :     void putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp, const CharClass* pCharClass );
     154             : 
     155             : private:
     156             :     FormulaCompiler::SeparatorType meSepType;
     157             : };
     158             : 
     159         153 : OpCodeList::OpCodeList( sal_uInt16 nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap,
     160             :         FormulaCompiler::SeparatorType eSepType ) :
     161         153 :     Resource( ResId( nRID, *ResourceManager::getResManager()))
     162         153 :     , meSepType( eSepType)
     163             : {
     164         153 :     SvtSysLocale aSysLocale;
     165         153 :     const CharClass* pCharClass = (xMap->isEnglish() ? NULL : aSysLocale.GetCharClassPtr());
     166         153 :     if (meSepType == FormulaCompiler::RESOURCE_BASE)
     167             :     {
     168       24276 :         for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
     169             :         {
     170       24225 :             putDefaultOpCode( xMap, i, pCharClass);
     171             :         }
     172             :     }
     173             :     else
     174             :     {
     175       48552 :         for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
     176             :         {
     177       48450 :             OUString aOpStr;
     178       48450 :             if ( getOpCodeString( aOpStr, i) )
     179         306 :                 xMap->putOpCode( aOpStr, OpCode(i), pCharClass);
     180             :             else
     181       48144 :                 putDefaultOpCode( xMap, i, pCharClass);
     182       48450 :         }
     183             :     }
     184             : 
     185         153 :     FreeResource();
     186         153 : }
     187             : 
     188       48450 : bool OpCodeList::getOpCodeString( OUString& rStr, sal_uInt16 nOp )
     189             : {
     190       48450 :     switch (nOp)
     191             :     {
     192             :         case SC_OPCODE_SEP:
     193             :         {
     194         102 :             if (meSepType == FormulaCompiler::COMMA_BASE)
     195             :             {
     196           0 :                 rStr = ",";
     197           0 :                 return true;
     198             :             }
     199         102 :             else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
     200             :             {
     201         102 :                 rStr = ";";
     202         102 :                 return true;
     203             :             }
     204             :         }
     205           0 :         break;
     206             :         case SC_OPCODE_ARRAY_COL_SEP:
     207             :         {
     208         102 :             if (meSepType == FormulaCompiler::COMMA_BASE)
     209             :             {
     210           0 :                 rStr = ",";
     211           0 :                 return true;
     212             :             }
     213         102 :             else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
     214             :             {
     215         102 :                 rStr = ";";
     216         102 :                 return true;
     217             :             }
     218             :         }
     219           0 :         break;
     220             :         case SC_OPCODE_ARRAY_ROW_SEP:
     221             :         {
     222         102 :             if (meSepType == FormulaCompiler::COMMA_BASE)
     223             :             {
     224           0 :                 rStr = ";";
     225           0 :                 return true;
     226             :             }
     227         102 :             else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
     228             :             {
     229         102 :                 rStr = "|";
     230         102 :                 return true;
     231             :             }
     232             :         }
     233           0 :         break;
     234             :     }
     235             : 
     236       48144 :     return false;
     237             : }
     238             : 
     239       72369 : void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp,
     240             :         const CharClass* pCharClass )
     241             : {
     242       72369 :     ResId aRes( nOp, *ResourceManager::getResManager());
     243       72369 :     aRes.SetRT( RSC_STRING);
     244       72369 :     if (IsAvailableRes( aRes))
     245       62485 :         xMap->putOpCode( aRes.toString(), OpCode( nOp), pCharClass);
     246       72369 : }
     247             : 
     248             : // static
     249         347 : const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr, sal_Unicode c )
     250             : {
     251         347 :     if ( !pStr )
     252           0 :         return NULL;
     253        2582 :     while ( *pStr )
     254             :     {
     255        1888 :         if ( *pStr == c )
     256           0 :             return pStr;
     257        1888 :         pStr++;
     258             :     }
     259         347 :     return NULL;
     260             : }
     261             : 
     262         304 : struct OpCodeMapData
     263             : {
     264             :     FormulaCompiler::NonConstOpCodeMapPtr mxSymbolMap;
     265             :     osl::Mutex maMtx;
     266             : };
     267             : 
     268             : 
     269             : } // namespace
     270             : 
     271             : 
     272       60428 : void FormulaCompiler::OpCodeMap::putExternal( const OUString & rSymbol, const OUString & rAddIn )
     273             : {
     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       60428 :     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       60428 :     if (bOk)
     281             :     {
     282       60428 :         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);
     286             :     }
     287       60428 : }
     288             : 
     289        3156 : void FormulaCompiler::OpCodeMap::putExternalSoftly( const OUString & rSymbol, const OUString & rAddIn )
     290             : {
     291        3156 :     bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
     292        3156 :     if (bOk)
     293          80 :         mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn));
     294        3156 : }
     295             : 
     296           0 : uno::Sequence< sheet::FormulaToken > FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(
     297             :         const FormulaCompiler& rCompiler, const uno::Sequence< OUString >& rNames ) const
     298             : {
     299           0 :     const sal_Int32 nLen = rNames.getLength();
     300           0 :     uno::Sequence< sheet::FormulaToken > aTokens( nLen);
     301           0 :     sheet::FormulaToken* pToken = aTokens.getArray();
     302           0 :     OUString const * pName = rNames.getConstArray();
     303           0 :     OUString const * const pStop = pName + nLen;
     304           0 :     for ( ; pName < pStop; ++pName, ++pToken)
     305             :     {
     306           0 :         OpCodeHashMap::const_iterator iLook( mpHashMap->find( *pName));
     307           0 :         if (iLook != mpHashMap->end())
     308           0 :             pToken->OpCode = (*iLook).second;
     309             :         else
     310             :         {
     311           0 :             OUString aIntName;
     312           0 :             if (hasExternals())
     313             :             {
     314           0 :                 ExternalHashMap::const_iterator iExt( mpExternalHashMap->find( *pName));
     315           0 :                 if (iExt != mpExternalHashMap->end())
     316           0 :                     aIntName = (*iExt).second;
     317             :                 // Check for existence not needed here, only name-mapping is of
     318             :                 // interest.
     319             :             }
     320           0 :             if (aIntName.isEmpty())
     321           0 :                 aIntName = rCompiler.FindAddInFunction(*pName, !isEnglish());    // bLocalFirst=false for english
     322           0 :             if (aIntName.isEmpty())
     323           0 :                 pToken->OpCode = getOpCodeUnknown();
     324             :             else
     325             :             {
     326           0 :                 pToken->OpCode = ocExternal;
     327           0 :                 pToken->Data <<= aIntName;
     328           0 :             }
     329             :         }
     330             :     }
     331           0 :     return aTokens;
     332             : }
     333             : 
     334        2814 : uno::Sequence< sheet::FormulaOpCodeMapEntry > FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(
     335             :         const FormulaCompiler& rCompiler, const sal_Int32 nGroups ) const
     336             : {
     337             :     using namespace sheet;
     338             : 
     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        2814 :     ::std::vector< FormulaOpCodeMapEntry > aVec;
     343             : 
     344        2814 :     if (nGroups == FormulaMapGroup::SPECIAL)
     345             :     {
     346             :         // Use specific order, keep in sync with
     347             :         // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl
     348             :         static const struct
     349             :         {
     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 }
     367             :         };
     368         469 :         const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
     369             :         // Preallocate vector elements.
     370         469 :         if (aVec.size() < nCount)
     371             :         {
     372         469 :             FormulaOpCodeMapEntry aEntry;
     373         469 :             aEntry.Token.OpCode = getOpCodeUnknown();
     374         469 :             aVec.resize( nCount, aEntry);
     375             :         } // if (aVec.size() < nCount)
     376             : 
     377         469 :         FormulaOpCodeMapEntry aEntry;
     378        6566 :         for (size_t i=0; i < nCount; ++i)
     379             :         {
     380        6097 :             size_t nIndex = static_cast< size_t >( aMap[i].nOff );
     381        6097 :             if (aVec.size() <= nIndex)
     382             :             {
     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           0 :                 aEntry.Token.OpCode = getOpCodeUnknown();
     388           0 :                 aVec.resize( nIndex + 1, aEntry );
     389             :             }
     390        6097 :             aEntry.Token.OpCode = aMap[i].eOp;
     391        6097 :             aVec[nIndex] = aEntry;
     392         469 :         }
     393             :     }
     394             :     else
     395             :     {
     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. */
     399             : 
     400             :         // Anything else but SPECIAL.
     401        2345 :         if ((nGroups & FormulaMapGroup::SEPARATORS) != 0)
     402             :         {
     403             :             static const sal_uInt16 aOpCodes[] = {
     404             :                 SC_OPCODE_OPEN,
     405             :                 SC_OPCODE_CLOSE,
     406             :                 SC_OPCODE_SEP,
     407             :             };
     408         469 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     409             :         }
     410        2345 :         if ((nGroups & FormulaMapGroup::ARRAY_SEPARATORS) != 0)
     411             :         {
     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
     417             :             };
     418         469 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     419             :         }
     420        2345 :         if ((nGroups & FormulaMapGroup::UNARY_OPERATORS) != 0)
     421             :         {
     422             :             // Due to the nature of the percent operator following its operand
     423             :             // it isn't sorted into unary operators for compiler interna.
     424         469 :             lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
     425             :             // "+" can be used as unary operator too, push only if binary group is not set
     426         469 :             if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
     427         469 :                 lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
     428             :             // regular unary operators
     429        1876 :             for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
     430             :             {
     431        1407 :                 switch (nOp)
     432             :                 {
     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         938 :                         break;   // nothing,
     438             :                     default:
     439         469 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     440             :                 }
     441             :             }
     442             :         }
     443        2345 :         if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
     444             :         {
     445        8442 :             for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
     446             :             {
     447        7973 :                 switch (nOp)
     448             :                 {
     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         938 :                         break;   // nothing,
     454             :                     default:
     455        7035 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     456             :                 }
     457             :             }
     458             :         }
     459        2345 :         if ((nGroups & FormulaMapGroup::FUNCTIONS) != 0)
     460             :         {
     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         469 :                     ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
     465             :             lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_1_PAR,
     466         469 :                     ::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
     477             :             };
     478         469 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     479             :             // functions with 2 or more parameters.
     480      128975 :             for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
     481             :             {
     482      128506 :                 switch (nOp)
     483             :                 {
     484             :                     // NO_NAME is in SPECIAL.
     485             :                     case SC_OPCODE_NO_NAME :
     486         469 :                         break;   // nothing,
     487             :                     default:
     488      128037 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     489             :                 }
     490             :             }
     491             :             // If AddIn functions are present in this mapping, use them, and only those.
     492         469 :             if (hasExternals())
     493             :             {
     494       51590 :                 for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
     495             :                 {
     496       51121 :                     FormulaOpCodeMapEntry aEntry;
     497       51121 :                     aEntry.Name = (*it).first;
     498       51121 :                     aEntry.Token.Data <<= OUString( (*it).second);
     499       51121 :                     aEntry.Token.OpCode = ocExternal;
     500       51121 :                     aVec.push_back( aEntry);
     501       51121 :                 }
     502             :             }
     503             :             else
     504             :             {
     505           0 :                 rCompiler.fillAddInToken( aVec, isEnglish());
     506             :             }
     507             :         }
     508             :     }
     509        2814 :     return uno::Sequence< FormulaOpCodeMapEntry >(aVec.data(), aVec.size());
     510             : }
     511             : 
     512             : 
     513      249841 : void FormulaCompiler::OpCodeMap::putOpCode( const OUString & rStr, const OpCode eOp, const CharClass* pCharClass )
     514             : {
     515             :     DBG_ASSERT( 0 < eOp && sal_uInt16(eOp) < mnSymbols, "OpCodeMap::putOpCode: OpCode out of range");
     516      249841 :     if (0 < eOp && sal_uInt16(eOp) < mnSymbols)
     517             :     {
     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      249841 :         mpTable[eOp] = rStr;
     526      249841 :         OUString aUpper( pCharClass ? pCharClass->uppercase( rStr) : rStr.toAsciiUpperCase());
     527      249841 :         mpHashMap->insert( OpCodeHashMap::value_type( aUpper, eOp));
     528             :     }
     529      249841 : }
     530             : 
     531             : // class FormulaCompiler
     532             : 
     533       11970 : FormulaCompiler::FormulaCompiler( FormulaTokenArray& rArr )
     534             :         :
     535             :         pArr( &rArr ),
     536             :         pCode( NULL ),
     537             :         pStack( NULL ),
     538             :         eLastOp( ocPush ),
     539             :         nRecursion( 0 ),
     540             :         nNumFmt( css::util::NumberFormat::UNDEFINED ),
     541             :         pc( 0 ),
     542             :         meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
     543             :         bAutoCorrect( false ),
     544             :         bCorrected( false ),
     545             :         glSubTotal( false ),
     546             :         mbJumpCommandReorder(true),
     547       11970 :         mbStopOnError(true)
     548             : {
     549       11970 : }
     550             : 
     551       32905 : FormulaCompiler::FormulaCompiler()
     552             :         :
     553             :         pArr( NULL ),
     554             :         pCode( NULL ),
     555             :         pStack( NULL ),
     556             :         eLastOp( ocPush ),
     557             :         nRecursion(0),
     558             :         nNumFmt( css::util::NumberFormat::UNDEFINED ),
     559             :         pc( 0 ),
     560             :         meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
     561             :         bAutoCorrect( false ),
     562             :         bCorrected( false ),
     563             :         glSubTotal( false ),
     564             :         mbJumpCommandReorder(true),
     565       32905 :         mbStopOnError(true)
     566             : {
     567       32905 : }
     568             : 
     569       44876 : FormulaCompiler::~FormulaCompiler()
     570             : {
     571       44876 : }
     572             : 
     573       48516 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
     574             : {
     575       48516 :     FormulaCompiler::OpCodeMapPtr xMap;
     576             :     using namespace sheet;
     577       48516 :     switch (nLanguage)
     578             :     {
     579             :         case FormulaLanguage::ODFF :
     580        8107 :             if (!mxSymbolsODFF)
     581        5762 :                 InitSymbolsODFF();
     582        8107 :             xMap = mxSymbolsODFF;
     583        8107 :             break;
     584             :         case FormulaLanguage::ODF_11 :
     585         350 :             if (!mxSymbolsPODF)
     586         350 :                 InitSymbolsPODF();
     587         350 :             xMap = mxSymbolsPODF;
     588         350 :             break;
     589             :         case FormulaLanguage::ENGLISH :
     590         273 :             if (!mxSymbolsEnglish)
     591         273 :                 InitSymbolsEnglish();
     592         273 :             xMap = mxSymbolsEnglish;
     593         273 :             break;
     594             :         case FormulaLanguage::NATIVE :
     595       38155 :             if (!mxSymbolsNative)
     596       37949 :                 InitSymbolsNative();
     597       38155 :             xMap = mxSymbolsNative;
     598       38155 :             break;
     599             :         case FormulaLanguage::XL_ENGLISH:
     600         306 :             if (!mxSymbolsEnglishXL)
     601         306 :                 InitSymbolsEnglishXL();
     602         306 :             xMap = mxSymbolsEnglishXL;
     603         306 :             break;
     604             :         case FormulaLanguage::OOXML:
     605        1325 :             if (!mxSymbolsOOXML)
     606        1325 :                 InitSymbolsOOXML();
     607        1325 :             xMap = mxSymbolsOOXML;
     608        1325 :             break;
     609             :         default:
     610             :             ;   // nothing, NULL map returned
     611             :     }
     612       48516 :     return xMap;
     613             : }
     614             : 
     615           0 : OUString FormulaCompiler::FindAddInFunction( const OUString& /*rUpperName*/, bool /*bLocalFirst*/ ) const
     616             : {
     617           0 :     return OUString();
     618             : }
     619             : 
     620         469 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
     621             :         const uno::Sequence<
     622             :         const sheet::FormulaOpCodeMapEntry > & rMapping,
     623             :         bool bEnglish )
     624             : {
     625             :     using sheet::FormulaOpCodeMapEntry;
     626             :     // Filter / API maps are never Core
     627             :     NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, false,
     628             :                 FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(
     629         469 :                         FormulaGrammar::GRAM_EXTERNAL, bEnglish), FormulaGrammar::CONV_UNSPECIFIED)));
     630         938 :     SvtSysLocale aSysLocale;
     631         469 :     const CharClass* pCharClass = (xMap->isEnglish() ? NULL : aSysLocale.GetCharClassPtr());
     632         469 :     FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
     633         469 :     FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
     634      239633 :     for ( ; pArr2 < pStop; ++pArr2)
     635             :     {
     636      239164 :         OpCode eOp = OpCode(pArr2->Token.OpCode);
     637      239164 :         if (eOp != ocExternal)
     638      184731 :             xMap->putOpCode( pArr2->Name, eOp, pCharClass);
     639             :         else
     640             :         {
     641       54433 :             OUString aExternalName;
     642       54433 :             if (pArr2->Token.Data >>= aExternalName)
     643       54433 :                 xMap->putExternal( pArr2->Name, aExternalName);
     644             :             else
     645             :             {
     646             :                 SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
     647       54433 :             }
     648             :         }
     649             :     }
     650         938 :     return xMap;
     651             : }
     652             : 
     653       70822 : void lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& xMap, bool bDestroy = false )
     654             : {
     655       70822 :     static OpCodeMapData aSymbolMap;
     656       70822 :     osl::MutexGuard aGuard(&aSymbolMap.maMtx);
     657             : 
     658       70822 :     if ( bDestroy )
     659             :     {
     660          49 :         aSymbolMap.mxSymbolMap.reset();
     661             :     }
     662       70773 :     else if (!aSymbolMap.mxSymbolMap)
     663             :     {
     664             :         // Core
     665             :         aSymbolMap.mxSymbolMap.reset(
     666             :             new FormulaCompiler::OpCodeMap(
     667          50 :                 SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
     668          50 :         OModuleClient aModuleClient;
     669          50 :         OpCodeList aOpCodeListNative(RID_STRLIST_FUNCTION_NAMES, aSymbolMap.mxSymbolMap);
     670             :         // No AddInMap for native core mapping.
     671             :     }
     672             : 
     673       70822 :     xMap = aSymbolMap.mxSymbolMap;
     674       70822 : }
     675             : 
     676       32308 : const OUString& FormulaCompiler::GetNativeSymbol( OpCode eOp )
     677             : {
     678       32308 :     NonConstOpCodeMapPtr xSymbolsNative;
     679       32308 :     lcl_fillNativeSymbols( xSymbolsNative);
     680       32308 :     return xSymbolsNative->getSymbol( eOp );
     681             : }
     682             : 
     683       29588 : sal_Unicode FormulaCompiler::GetNativeSymbolChar( OpCode eOp )
     684             : {
     685       29588 :     return GetNativeSymbol(eOp)[0];
     686             : }
     687             : 
     688       37949 : void FormulaCompiler::InitSymbolsNative() const
     689             : {
     690       37949 :     lcl_fillNativeSymbols( mxSymbolsNative);
     691       37949 : }
     692             : 
     693         273 : void FormulaCompiler::InitSymbolsEnglish() const
     694             : {
     695         273 :     static OpCodeMapData aMap;
     696         273 :     osl::MutexGuard aGuard(&aMap.maMtx);
     697         273 :     if (!aMap.mxSymbolMap)
     698          49 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
     699         273 :     mxSymbolsEnglish = aMap.mxSymbolMap;
     700         273 : }
     701             : 
     702         350 : void FormulaCompiler::InitSymbolsPODF() const
     703             : {
     704         350 :     static OpCodeMapData aMap;
     705         350 :     osl::MutexGuard aGuard(&aMap.maMtx);
     706         350 :     if (!aMap.mxSymbolMap)
     707          13 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_PODF, aMap.mxSymbolMap, RESOURCE_BASE);
     708         350 :     mxSymbolsPODF = aMap.mxSymbolMap;
     709         350 : }
     710             : 
     711        5762 : void FormulaCompiler::InitSymbolsODFF() const
     712             : {
     713        5762 :     static OpCodeMapData aMap;
     714        5762 :     osl::MutexGuard aGuard(&aMap.maMtx);
     715        5762 :     if (!aMap.mxSymbolMap)
     716          35 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF, FormulaGrammar::GRAM_ODFF, aMap.mxSymbolMap, RESOURCE_BASE);
     717        5762 :     mxSymbolsODFF = aMap.mxSymbolMap;
     718        5762 : }
     719             : 
     720         306 : void FormulaCompiler::InitSymbolsEnglishXL() const
     721             : {
     722         306 :     static OpCodeMapData aMap;
     723         306 :     osl::MutexGuard aGuard(&aMap.maMtx);
     724         306 :     if (!aMap.mxSymbolMap)
     725           3 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
     726         306 :     mxSymbolsEnglishXL = aMap.mxSymbolMap;
     727             : 
     728             :     // TODO: For now, just replace the separators to the Excel English
     729             :     // variants. Later, if we want to properly map Excel functions with Calc
     730             :     // functions, we'll need to do a little more work here.
     731         306 :     mxSymbolsEnglishXL->putOpCode( OUString(','), ocSep, NULL);
     732         306 :     mxSymbolsEnglishXL->putOpCode( OUString(','), ocArrayColSep, NULL);
     733         306 :     mxSymbolsEnglishXL->putOpCode( OUString(';'), ocArrayRowSep, NULL);
     734         306 : }
     735             : 
     736        1325 : void FormulaCompiler::InitSymbolsOOXML() const
     737             : {
     738        1325 :     static OpCodeMapData aMap;
     739        1325 :     osl::MutexGuard aGuard(&aMap.maMtx);
     740        1325 :     if (!aMap.mxSymbolMap)
     741           3 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML, FormulaGrammar::GRAM_OOXML, aMap.mxSymbolMap, RESOURCE_BASE);
     742        1325 :     mxSymbolsOOXML = aMap.mxSymbolMap;
     743        1325 : }
     744             : 
     745             : 
     746         103 : void FormulaCompiler::loadSymbols( sal_uInt16 nSymbols, FormulaGrammar::Grammar eGrammar,
     747             :         NonConstOpCodeMapPtr& rxMap, SeparatorType eSepType) const
     748             : {
     749         103 :     if ( !rxMap.get() )
     750             :     {
     751             :         // not Core
     752         103 :         rxMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, eGrammar != FormulaGrammar::GRAM_ODFF, eGrammar ));
     753         103 :         OModuleClient aModuleClient;
     754         206 :         OpCodeList aOpCodeList( nSymbols, rxMap, eSepType);
     755             : 
     756         103 :         fillFromAddInMap( rxMap, eGrammar);
     757             :         // Fill from collection for AddIns not already present.
     758         103 :         if ( FormulaGrammar::GRAM_ENGLISH != eGrammar )
     759          51 :             fillFromAddInCollectionUpperName( rxMap);
     760             :         else
     761         155 :             fillFromAddInCollectionEnglishName( rxMap);
     762             :     }
     763         103 : }
     764             : 
     765           0 : void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const
     766             : {
     767           0 : }
     768             : 
     769          48 : void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const
     770             : {
     771          48 : }
     772             : 
     773          48 : void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const
     774             : {
     775          48 : }
     776             : 
     777           0 : OpCode FormulaCompiler::GetEnglishOpCode( const OUString& rName ) const
     778             : {
     779           0 :     FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap( sheet::FormulaLanguage::ENGLISH);
     780             : 
     781           0 :     formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) );
     782           0 :     bool bFound = (iLook != xMap->getHashMap()->end());
     783           0 :     return bFound ? (*iLook).second : OpCode(ocNone);
     784             : }
     785             : 
     786       24707 : bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
     787             : {
     788       24707 :     bool bRet = false;
     789       24707 :     switch (eOp)
     790             :     {
     791             :         // no parameters:
     792             :         case ocRandom:
     793             :         case ocGetActDate:
     794             :         case ocGetActTime:
     795             :         // one parameter:
     796             :         case ocFormula:
     797             :         case ocInfo:
     798             :         // more than one parameters:
     799             :             // ocIndirect/ocIndirectXL otherwise would have to do
     800             :             // StopListening and StartListening on a reference for every
     801             :             // interpreted value.
     802             :         case ocIndirect:
     803             :         case ocIndirectXL:
     804             :             // ocOffset results in indirect references.
     805             :         case ocOffset:
     806             :             // ocDebugVar shows internal value that may change as the internal state changes.
     807             :         case ocDebugVar:
     808         101 :             bRet = true;
     809         101 :             break;
     810             :         default:
     811       24606 :             bRet = false;
     812       24606 :             break;
     813             :     }
     814       24707 :     return bRet;
     815             : }
     816             : 
     817        1611 : bool FormulaCompiler::IsOpCodeJumpCommand( OpCode eOp )
     818             : {
     819        1611 :     switch (eOp)
     820             :     {
     821             :         case ocIf:
     822             :         case ocIfError:
     823             :         case ocIfNA:
     824             :         case ocChoose:
     825          48 :             return true;
     826             :         default:
     827             :             ;
     828             :     }
     829        1563 :     return false;
     830             : }
     831             : 
     832             : // Remove quotes, escaped quotes are unescaped.
     833          16 : bool FormulaCompiler::DeQuote( OUString& rStr )
     834             : {
     835          16 :     sal_Int32 nLen = rStr.getLength();
     836          16 :     if ( nLen > 1 && rStr[0] == '\'' && rStr[ nLen-1 ] == '\'' )
     837             :     {
     838           0 :         rStr = rStr.copy( 1, nLen-2 );
     839           0 :         rStr = rStr.replaceAll( "\\\'", "\'" );
     840           0 :         return true;
     841             :     }
     842          16 :     return false;
     843             : }
     844             : 
     845           0 : void FormulaCompiler::fillAddInToken(
     846             :         ::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,
     847             :         bool /*_bIsEnglish*/) const
     848             : {
     849           0 : }
     850             : 
     851           0 : bool FormulaCompiler::IsMatrixFunction( OpCode eOpCode )
     852             : {
     853           0 :     switch (eOpCode)
     854             :     {
     855             :         case ocDde :
     856             :         case ocGrowth :
     857             :         case ocTrend :
     858             :         case ocLogest :
     859             :         case ocLinest :
     860             :         case ocFrequency :
     861             :         case ocMatTrans :
     862             :         case ocMatMult :
     863             :         case ocMatInv :
     864             :         case ocMatrixUnit :
     865             :         case ocModalValue_Multi :
     866           0 :             return true;
     867             :         default:
     868             :         {
     869             :             // added to avoid warnings
     870             :         }
     871             :     }
     872           0 :     return false;
     873             : }
     874             : 
     875             : 
     876        1244 : FormulaCompiler::OpCodeMap::~OpCodeMap()
     877             : {
     878         622 :     delete mpReverseExternalHashMap;
     879         622 :     delete mpExternalHashMap;
     880         622 :     delete [] mpTable;
     881         622 :     delete mpHashMap;
     882        1244 : }
     883             : 
     884           0 : void FormulaCompiler::OpCodeMap::putCopyOpCode( const OUString& rSymbol, OpCode eOp )
     885             : {
     886             :     SAL_WARN_IF( !mpTable[eOp].isEmpty() && rSymbol.isEmpty(), "formula.core",
     887             :             "OpCodeMap::putCopyOpCode: NOT replacing OpCode " << static_cast<sal_uInt16>(eOp)
     888             :             << " '" << mpTable[eOp] << "' with empty name!");
     889           0 :     if (!mpTable[eOp].isEmpty() && rSymbol.isEmpty())
     890           0 :         mpHashMap->insert( OpCodeHashMap::value_type( mpTable[eOp], eOp));
     891             :     else
     892             :     {
     893           0 :         mpTable[eOp] = rSymbol;
     894           0 :         mpHashMap->insert( OpCodeHashMap::value_type( rSymbol, eOp));
     895             :     }
     896           0 : }
     897             : 
     898           0 : void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap& r, bool bOverrideKnownBad )
     899             : {
     900           0 :     delete mpHashMap;
     901           0 :     mpHashMap = new OpCodeHashMap( mnSymbols);
     902             : 
     903           0 :     sal_uInt16 n = r.getSymbolCount();
     904             :     SAL_WARN_IF( n != mnSymbols, "formula.core",
     905             :             "OpCodeMap::copyFrom: unequal size, this: " << mnSymbols << "  that: " << n);
     906           0 :     if (n > mnSymbols)
     907           0 :         n = mnSymbols;
     908             : 
     909             :     // OpCode 0 (ocPush) should never be in a map.
     910             :     SAL_WARN_IF( !mpTable[0].isEmpty() || !r.mpTable[0].isEmpty(), "formula.core",
     911             :             "OpCodeMap::copyFrom: OpCode 0 assigned, this: '"
     912             :             << mpTable[0] << "'  that: '" << r.mpTable[0] << "'");
     913             : 
     914             :     // For bOverrideKnownBad when copying from the English core map (ODF 1.1
     915             :     // and API) to the native map (UI "use English function names") replace the
     916             :     // known bad legacy function names with correct ones.
     917           0 :     if (bOverrideKnownBad && r.mbCore &&
     918           0 :             FormulaGrammar::extractFormulaLanguage( meGrammar) == sheet::FormulaLanguage::NATIVE &&
     919           0 :             FormulaGrammar::extractFormulaLanguage( r.meGrammar) == sheet::FormulaLanguage::ENGLISH)
     920             :     {
     921           0 :         for (sal_uInt16 i = 1; i < n; ++i)
     922             :         {
     923           0 :             OUString aSymbol;
     924           0 :             OpCode eOp = OpCode(i);
     925           0 :             switch (eOp)
     926             :             {
     927             :                 case ocRRI:
     928           0 :                     aSymbol = "RRI";
     929           0 :                     break;
     930             :                 case ocTableOp:
     931           0 :                     aSymbol = "MULTIPLE.OPERATIONS";
     932           0 :                     break;
     933             :                 default:
     934           0 :                     aSymbol = r.mpTable[i];
     935             :             }
     936           0 :             putCopyOpCode( aSymbol, eOp);
     937           0 :         }
     938             :     }
     939             :     else
     940             :     {
     941           0 :         for (sal_uInt16 i = 1; i < n; ++i)
     942             :         {
     943           0 :             OpCode eOp = OpCode(i);
     944           0 :             const OUString& rSymbol = r.mpTable[i];
     945           0 :             putCopyOpCode( rSymbol, eOp);
     946             :         }
     947             :     }
     948             : 
     949             :     // TODO: maybe copy the external maps too?
     950           0 : }
     951             : 
     952             : 
     953          37 : sal_uInt16 FormulaCompiler::GetErrorConstant( const OUString& rName ) const
     954             : {
     955          37 :     sal_uInt16 nError = 0;
     956          37 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
     957          37 :     if (iLook != mxSymbols->getHashMap()->end())
     958             :     {
     959          37 :         switch ((*iLook).second)
     960             :         {
     961             :             // Not all may make sense in a formula, but these we know as
     962             :             // opcodes.
     963             :             case ocErrNull:
     964           0 :                 nError = errNoCode;
     965           0 :                 break;
     966             :             case ocErrDivZero:
     967           4 :                 nError = errDivisionByZero;
     968           4 :                 break;
     969             :             case ocErrValue:
     970           0 :                 nError = errNoValue;
     971           0 :                 break;
     972             :             case ocErrRef:
     973          23 :                 nError = errNoRef;
     974          23 :                 break;
     975             :             case ocErrName:
     976           0 :                 nError = errNoName;
     977           0 :                 break;
     978             :             case ocErrNum:
     979           0 :                 nError = errIllegalFPOperation;
     980           0 :                 break;
     981             :             case ocErrNA:
     982          10 :                 nError = NOTAVAILABLE;
     983          10 :                 break;
     984             :             default:
     985             :                 ;   // nothing
     986             :         }
     987             :     }
     988          37 :     return nError;
     989             : }
     990             : 
     991         454 : void FormulaCompiler::EnableJumpCommandReorder( bool bEnable )
     992             : {
     993         454 :     mbJumpCommandReorder = bEnable;
     994         454 : }
     995             : 
     996         453 : void FormulaCompiler::EnableStopOnError( bool bEnable )
     997             : {
     998         453 :     mbStopOnError = bEnable;
     999         453 : }
    1000             : 
    1001           0 : void FormulaCompiler::AppendErrorConstant( OUStringBuffer& rBuffer, sal_uInt16 nError ) const
    1002             : {
    1003             :     OpCode eOp;
    1004           0 :     switch (nError)
    1005             :     {
    1006             :         default:
    1007             :         case errNoCode:
    1008           0 :             eOp = ocErrNull;
    1009           0 :             break;
    1010             :         case errDivisionByZero:
    1011           0 :             eOp = ocErrDivZero;
    1012           0 :             break;
    1013             :         case errNoValue:
    1014           0 :             eOp = ocErrValue;
    1015           0 :             break;
    1016             :         case errNoRef:
    1017           0 :             eOp = ocErrRef;
    1018           0 :             break;
    1019             :         case errNoName:
    1020           0 :             eOp = ocErrName;
    1021           0 :             break;
    1022             :         case errIllegalFPOperation:
    1023           0 :             eOp = ocErrNum;
    1024           0 :             break;
    1025             :         case NOTAVAILABLE:
    1026           0 :             eOp = ocErrNA;
    1027           0 :             break;
    1028             :     }
    1029           0 :     rBuffer.append( mxSymbols->getSymbol( eOp));
    1030           0 : }
    1031             : 
    1032             : 
    1033         938 : sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
    1034             : {
    1035             :     static const sal_Int32 kOpCodeUnknown = -1;
    1036         938 :     return kOpCodeUnknown;
    1037             : }
    1038             : 
    1039       69989 : bool FormulaCompiler::GetToken()
    1040             : {
    1041             :     static const short nRecursionMax = 42;
    1042       69989 :     FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
    1043       69989 :     if ( nRecursion > nRecursionMax )
    1044             :     {
    1045           0 :         SetError( errStackOverflow );
    1046           0 :         mpToken = new FormulaByteToken( ocStop );
    1047           0 :         return false;
    1048             :     }
    1049       69989 :     if ( bAutoCorrect && !pStack )
    1050             :     {   // don't merge stacked subroutine code into entered formula
    1051           0 :         aCorrectedFormula += aCorrectedSymbol;
    1052           0 :         aCorrectedSymbol.clear();
    1053             :     }
    1054       69989 :     bool bStop = false;
    1055       69989 :     if (pArr->GetCodeError() && mbStopOnError)
    1056           0 :         bStop = true;
    1057             :     else
    1058             :     {
    1059             :         short nWasColRowName;
    1060       69989 :         if ( pArr->nIndex
    1061       69989 :           && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
    1062           0 :              nWasColRowName = 1;
    1063             :         else
    1064       69989 :              nWasColRowName = 0;
    1065       69989 :         mpToken = pArr->Next();
    1066      140429 :         while( mpToken && mpToken->GetOpCode() == ocSpaces )
    1067             :         {
    1068         451 :             if ( nWasColRowName )
    1069           0 :                 nWasColRowName++;
    1070         451 :             if ( bAutoCorrect && !pStack )
    1071           0 :                 CreateStringFromToken( aCorrectedFormula, mpToken.get(), false );
    1072         451 :             mpToken = pArr->Next();
    1073             :         }
    1074       69989 :         if ( bAutoCorrect && !pStack && mpToken )
    1075           0 :             CreateStringFromToken( aCorrectedSymbol, mpToken.get(), false );
    1076       69989 :         if( !mpToken )
    1077             :         {
    1078        9013 :             if( pStack )
    1079             :             {
    1080         499 :                 PopTokenArray();
    1081         499 :                 return GetToken();
    1082             :             }
    1083             :             else
    1084        8514 :                 bStop = true;
    1085             :         }
    1086             :         else
    1087             :         {
    1088       60976 :             if ( nWasColRowName >= 2 && mpToken->GetOpCode() == ocColRowName )
    1089             :             {   // convert an ocSpaces to ocIntersect in RPN
    1090           0 :                 mpToken = new FormulaByteToken( ocIntersect );
    1091           0 :                 pArr->nIndex--;     // we advanced to the second ocColRowName, step back
    1092             :             }
    1093             :         }
    1094             :     }
    1095       69490 :     if( bStop )
    1096             :     {
    1097        8514 :         mpToken = new FormulaByteToken( ocStop );
    1098        8514 :         return false;
    1099             :     }
    1100      121932 :     if ( mpToken->GetOpCode() == ocSubTotal ||
    1101       60956 :          mpToken->GetOpCode() == ocAggregate )
    1102         441 :         glSubTotal = true;
    1103       60535 :     else if ( mpToken->IsExternalRef() )
    1104             :     {
    1105         199 :         return HandleExternalReference(*mpToken);
    1106             :     }
    1107       60336 :     else if( mpToken->GetOpCode() == ocName )
    1108             :     {
    1109         431 :         return HandleRange();
    1110             :     }
    1111       59905 :     else if( mpToken->GetOpCode() == ocColRowName )
    1112             :     {
    1113           0 :         return HandleColRowName();
    1114             :     }
    1115       59905 :     else if( mpToken->GetOpCode() == ocDBArea )
    1116             :     {
    1117          12 :         return HandleDbData();
    1118             :     }
    1119       59893 :     else if( mpToken->GetOpCode() == ocTableRef )
    1120             :     {
    1121           0 :         return HandleTableRef();
    1122             :     }
    1123       60334 :     return true;
    1124             : }
    1125             : 
    1126             : 
    1127             : // RPN creation by recursion
    1128       31764 : void FormulaCompiler::Factor()
    1129             : {
    1130       31764 :     if (pArr->GetCodeError() && mbStopOnError)
    1131       31764 :         return;
    1132             : 
    1133       31764 :     CurrentFactor pFacToken( this );
    1134             : 
    1135       31764 :     OpCode eOp = mpToken->GetOpCode();
    1136       31764 :     if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
    1137        9404 :             eOp == ocDBArea || eOp == ocTableRef
    1138        9404 :             || (!mbJumpCommandReorder && ((eOp == ocName) || (eOp == ocDBArea)
    1139           1 :             || (eOp == ocTableRef) || (eOp == ocColRowName) || (eOp == ocBad)))
    1140             :         )
    1141             :     {
    1142       22360 :         PutCode( mpToken );
    1143       22360 :         eOp = NextToken();
    1144       44720 :         if( eOp == ocOpen )
    1145             :         {
    1146             :             // PUSH( is an error that may be caused by an unknown function.
    1147             :             SetError(
    1148           0 :                 ( mpToken->GetType() == svString
    1149           0 :                || mpToken->GetType() == svSingleRef )
    1150           0 :                ? errNoName : errOperatorExpected );
    1151           0 :             if ( bAutoCorrect && !pStack )
    1152             :             {   // assume multiplication
    1153           0 :                 aCorrectedFormula += mxSymbols->getSymbol( ocMul);
    1154           0 :                 bCorrected = true;
    1155           0 :                 NextToken();
    1156           0 :                 eOp = Expression();
    1157           0 :                 if( eOp != ocClose )
    1158           0 :                     SetError( errPairExpected);
    1159             :                 else
    1160           0 :                     eOp = NextToken();
    1161             :             }
    1162             :         }
    1163             :     }
    1164        9404 :     else if( eOp == ocOpen )
    1165             :     {
    1166        1039 :         NextToken();
    1167        1039 :         eOp = Expression();
    1168        2078 :         while ((eOp == ocSep) && (!pArr->GetCodeError() || !mbStopOnError))
    1169             :         {   // range list  (A1;A2)  converted to  (A1~A2)
    1170           0 :             pFacToken = mpToken;
    1171           0 :             NextToken();
    1172           0 :             eOp = Expression();
    1173             :             // Do not ignore error here, regardless of bIgnoreErrors, otherwise
    1174             :             // errors like =(1;) would also result in display of =(1~)
    1175           0 :             if (!pArr->GetCodeError())
    1176             :             {
    1177           0 :                 pFacToken->NewOpCode( ocUnion, FormulaToken::PrivateAccess());
    1178           0 :                 PutCode( pFacToken);
    1179             :             }
    1180             :         }
    1181        1039 :         if (eOp != ocClose)
    1182           0 :             SetError( errPairExpected);
    1183             :         else
    1184        1039 :             eOp = NextToken();
    1185             :     }
    1186             :     else
    1187             :     {
    1188        8365 :         if( nNumFmt == css::util::NumberFormat::UNDEFINED )
    1189        5705 :             nNumFmt = lcl_GetRetFormat( eOp );
    1190             : 
    1191        8365 :         if ( IsOpCodeVolatile( eOp) )
    1192          34 :             pArr->SetExclusiveRecalcModeAlways();
    1193             :         else
    1194             :         {
    1195        8331 :             switch( eOp )
    1196             :             {
    1197             :                     // Functions recalculated on every document load.
    1198             :                     // Don't use SetExclusiveRecalcModeOnLoad() which would
    1199             :                     // override ModeAlways, use
    1200             :                     // AddRecalcMode(ScRecalcMode::ONLOAD) instead.
    1201             :                 case ocConvert :
    1202             :                 case ocDde:
    1203             :                 case ocMacro:
    1204             :                 case ocExternal:
    1205         114 :                     pArr->AddRecalcMode( ScRecalcMode::ONLOAD );
    1206         114 :                 break;
    1207             :                     // If the referred cell is moved the value changes.
    1208             :                 case ocColumn :
    1209             :                 case ocRow :
    1210          70 :                     pArr->SetRecalcModeOnRefMove();
    1211          70 :                 break;
    1212             :                     // ocCell needs recalc on move for some possible type values.
    1213             :                     // and recalc mode on load, fdo#60646
    1214             :                 case ocCell :
    1215          50 :                     pArr->SetRecalcModeOnRefMove();
    1216          50 :                     pArr->AddRecalcMode( ScRecalcMode::ONLOAD );
    1217          50 :                 break;
    1218             :                 case ocHyperLink :
    1219             :                     // cell with hyperlink needs to be calculated on load to
    1220             :                     // get its matrix result generated.
    1221           4 :                     pArr->AddRecalcMode( ScRecalcMode::ONLOAD );
    1222           4 :                     pArr->SetHyperLink( true);
    1223           4 :                 break;
    1224             :                 default:
    1225             :                     ;   // nothing
    1226             :             }
    1227             :         }
    1228        8365 :         if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
    1229             :         {
    1230          77 :             pFacToken = mpToken;
    1231          77 :             eOp = NextToken();
    1232         154 :             if (eOp != ocOpen)
    1233             :             {
    1234           0 :                 SetError( errPairExpected);
    1235           0 :                 PutCode( pFacToken );
    1236             :             }
    1237             :             else
    1238             :             {
    1239          77 :                 eOp = NextToken();
    1240          77 :                 if (eOp != ocClose)
    1241           0 :                     SetError( errPairExpected);
    1242          77 :                 PutCode( pFacToken);
    1243          77 :                 eOp = NextToken();
    1244             :             }
    1245             :         }
    1246             :         // special cases NOT() and NEG()
    1247        8288 :         else if( eOp == ocNot || eOp == ocNeg
    1248        8288 :               || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
    1249             :         {
    1250         468 :             pFacToken = mpToken;
    1251         468 :             eOp = NextToken();
    1252         468 :             if( nNumFmt == css::util::NumberFormat::UNDEFINED && eOp == ocNot )
    1253           0 :                 nNumFmt = css::util::NumberFormat::LOGICAL;
    1254         468 :             if (eOp == ocOpen)
    1255             :             {
    1256         468 :                 NextToken();
    1257         468 :                 eOp = Expression();
    1258             :             }
    1259             :             else
    1260           0 :                 SetError( errPairExpected);
    1261         468 :             if (eOp != ocClose)
    1262           0 :                 SetError( errPairExpected);
    1263         468 :             else if ( !pArr->GetCodeError() )
    1264         468 :                 pFacToken->SetByte( 1 );
    1265         468 :             PutCode( pFacToken );
    1266         468 :             eOp = NextToken();
    1267             :         }
    1268       13875 :         else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
    1269        1765 :                 || eOp == ocExternal
    1270        1665 :                 || eOp == ocMacro
    1271        1663 :                 || eOp == ocAnd
    1272        1642 :                 || eOp == ocOr
    1273        1627 :                 || eOp == ocBad
    1274        1611 :                 || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
    1275        9431 :                 || (!mbJumpCommandReorder && IsOpCodeJumpCommand(eOp)))
    1276             :         {
    1277        6210 :             pFacToken = mpToken;
    1278        6210 :             OpCode eMyLastOp = eOp;
    1279        6210 :             eOp = NextToken();
    1280        6210 :             bool bNoParam = false;
    1281        6210 :             bool bBadName = false;
    1282        6210 :             if (eOp == ocOpen)
    1283             :             {
    1284        6194 :                 eOp = NextToken();
    1285        6194 :                 if (eOp == ocClose)
    1286          51 :                     bNoParam = true;
    1287             :                 else
    1288        6143 :                     eOp = Expression();
    1289             :             }
    1290          16 :             else if (eMyLastOp == ocBad)
    1291             :             {
    1292             :                 // Just a bad name, not an unknown function, no parameters, no
    1293             :                 // closing expected.
    1294          16 :                 bBadName = true;
    1295          16 :                 bNoParam = true;
    1296             :             }
    1297             :             else
    1298           0 :                 SetError( errPairExpected);
    1299        6210 :             sal_uInt8 nSepCount = 0;
    1300        6210 :             if( !bNoParam )
    1301             :             {
    1302        6143 :                 nSepCount++;
    1303       19591 :                 while ((eOp == ocSep) && (!pArr->GetCodeError() || !mbStopOnError))
    1304             :                 {
    1305        7305 :                     nSepCount++;
    1306        7305 :                     NextToken();
    1307        7305 :                     eOp = Expression();
    1308             :                 }
    1309             :             }
    1310        6210 :             if (bBadName)
    1311             :                 ;   // nothing, keep current token for return
    1312        6194 :             else if (eOp != ocClose)
    1313           0 :                 SetError( errPairExpected);
    1314             :             else
    1315        6194 :                 eOp = NextToken();
    1316             :             // Jumps are just normal functions for the FunctionAutoPilot tree view
    1317        6210 :             if (!mbJumpCommandReorder && pFacToken->GetType() == svJump)
    1318           1 :                 pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
    1319             :             else
    1320        6209 :                 pFacToken->SetByte( nSepCount );
    1321        6210 :             PutCode( pFacToken );
    1322             :         }
    1323        1610 :         else if (IsOpCodeJumpCommand(eOp))
    1324             :         {
    1325             :             // the PC counters are -1
    1326          47 :             pFacToken = mpToken;
    1327          47 :             switch (eOp)
    1328             :             {
    1329             :                 case ocIf:
    1330          30 :                     pFacToken->GetJump()[ 0 ] = 3;  // if, else, behind
    1331          30 :                     break;
    1332             :                 case ocChoose:
    1333           5 :                     pFacToken->GetJump()[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
    1334           5 :                     break;
    1335             :                 case ocIfError:
    1336             :                 case ocIfNA:
    1337          12 :                     pFacToken->GetJump()[ 0 ] = 2;  // if, behind
    1338          12 :                     break;
    1339             :                 default:
    1340             :                     SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump count case?");
    1341             :             }
    1342          47 :             eOp = NextToken();
    1343          47 :             if (eOp == ocOpen)
    1344             :             {
    1345          47 :                 NextToken();
    1346          47 :                 eOp = Expression();
    1347             :             }
    1348             :             else
    1349           0 :                 SetError( errPairExpected);
    1350          47 :             PutCode( pFacToken );
    1351             :             // During AutoCorrect (since pArr->GetCodeError() is
    1352             :             // ignored) an unlimited ocIf would crash because
    1353             :             // ScRawToken::Clone() allocates the JumpBuffer according to
    1354             :             // nJump[0]*2+2, which is 3*2+2 on ocIf and 2*2+2 ocIfError and ocIfNA.
    1355             :             short nJumpMax;
    1356          47 :             OpCode eFacOpCode = pFacToken->GetOpCode();
    1357          47 :             switch (eFacOpCode)
    1358             :             {
    1359             :                 case ocIf:
    1360          30 :                     nJumpMax = 3;
    1361          30 :                     break;
    1362             :                 case ocChoose:
    1363           5 :                     nJumpMax = FORMULA_MAXJUMPCOUNT;
    1364           5 :                     break;
    1365             :                 case ocIfError:
    1366             :                 case ocIfNA:
    1367          12 :                     nJumpMax = 2;
    1368          12 :                     break;
    1369             :                 default:
    1370           0 :                     nJumpMax = 0;
    1371             :                     SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump max case?");
    1372             :             }
    1373          47 :             short nJumpCount = 0;
    1374         305 :             while ( (nJumpCount < (FORMULA_MAXJUMPCOUNT - 1)) && (eOp == ocSep)
    1375         211 :                     && (!pArr->GetCodeError() || !mbStopOnError))
    1376             :             {
    1377          82 :                 if ( ++nJumpCount <= nJumpMax )
    1378          82 :                     pFacToken->GetJump()[nJumpCount] = pc-1;
    1379          82 :                 NextToken();
    1380          82 :                 eOp = Expression();
    1381             :                 // ocSep or ocClose terminate the subexpression
    1382          82 :                 PutCode( mpToken );
    1383             :             }
    1384          47 :             if (eOp != ocClose)
    1385           0 :                 SetError( errPairExpected);
    1386             :             else
    1387             :             {
    1388          47 :                 eOp = NextToken();
    1389             :                 // always limit to nJumpMax, no arbitrary overwrites
    1390          47 :                 if ( ++nJumpCount <= nJumpMax )
    1391          47 :                     pFacToken->GetJump()[ nJumpCount ] = pc-1;
    1392          47 :                 eFacOpCode = pFacToken->GetOpCode();
    1393             :                 bool bLimitOk;
    1394          47 :                 switch (eFacOpCode)
    1395             :                 {
    1396             :                     case ocIf:
    1397          30 :                         bLimitOk = (nJumpCount <= 3);
    1398          30 :                         break;
    1399             :                     case ocChoose:
    1400           5 :                         bLimitOk = (nJumpCount < FORMULA_MAXJUMPCOUNT); /* TODO: check, really <, not <=? */
    1401           5 :                         break;
    1402             :                     case ocIfError:
    1403             :                     case ocIfNA:
    1404          12 :                         bLimitOk = (nJumpCount <= 2);
    1405          12 :                         break;
    1406             :                     default:
    1407           0 :                         bLimitOk = false;
    1408             :                         SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump limit case?");
    1409             :                 }
    1410          47 :                 if (bLimitOk)
    1411          47 :                     pFacToken->GetJump()[ 0 ] = nJumpCount;
    1412             :                 else
    1413           0 :                     SetError( errIllegalParameter);
    1414             :             }
    1415             :         }
    1416        1563 :         else if ( eOp == ocMissing )
    1417             :         {
    1418          13 :             PutCode( mpToken );
    1419          13 :             eOp = NextToken();
    1420             :         }
    1421        1550 :         else if ( eOp == ocClose )
    1422             :         {
    1423           0 :             SetError( errParameterExpected );
    1424             :         }
    1425        1550 :         else if ( eOp == ocSep )
    1426             :         {   // Subsequent ocSep
    1427           0 :             SetError( errParameterExpected );
    1428           0 :             if ( bAutoCorrect && !pStack )
    1429             :             {
    1430           0 :                 aCorrectedSymbol.clear();
    1431           0 :                 bCorrected = true;
    1432             :             }
    1433             :         }
    1434        1550 :         else if ( mpToken->IsExternalRef() )
    1435             :         {
    1436           0 :             PutCode( mpToken);
    1437           0 :             eOp = NextToken();
    1438             :         }
    1439             :         else
    1440             :         {
    1441        1550 :             SetError( errUnknownToken );
    1442        1550 :             if ( bAutoCorrect && !pStack )
    1443             :             {
    1444           0 :                 if ( eOp == ocStop )
    1445             :                 {   // trailing operator w/o operand
    1446           0 :                     sal_Int32 nLen = aCorrectedFormula.getLength();
    1447           0 :                     if ( nLen )
    1448           0 :                         aCorrectedFormula = aCorrectedFormula.copy( 0, nLen - 1 );
    1449           0 :                     aCorrectedSymbol.clear();
    1450           0 :                     bCorrected = true;
    1451             :                 }
    1452             :             }
    1453             :         }
    1454       31764 :     }
    1455             : }
    1456             : 
    1457       31764 : void FormulaCompiler::RangeLine()
    1458             : {
    1459       31764 :     Factor();
    1460       63528 :     while (mpToken->GetOpCode() == ocRange)
    1461             :     {
    1462           0 :         FormulaToken** pCode1 = pCode - 1;
    1463           0 :         FormulaTokenRef p = mpToken;
    1464           0 :         NextToken();
    1465           0 :         Factor();
    1466           0 :         FormulaToken** pCode2 = pCode - 1;
    1467           0 :         if (!MergeRangeReference( pCode1, pCode2))
    1468           0 :             PutCode(p);
    1469           0 :     }
    1470       31764 : }
    1471             : 
    1472       31764 : void FormulaCompiler::IntersectionLine()
    1473             : {
    1474       31764 :     RangeLine();
    1475       63528 :     while (mpToken->GetOpCode() == ocIntersect)
    1476             :     {
    1477           0 :         FormulaTokenRef p = mpToken;
    1478           0 :         NextToken();
    1479           0 :         RangeLine();
    1480           0 :         PutCode(p);
    1481           0 :     }
    1482       31764 : }
    1483             : 
    1484       31760 : void FormulaCompiler::UnionLine()
    1485             : {
    1486       31760 :     IntersectionLine();
    1487       63524 :     while (mpToken->GetOpCode() == ocUnion)
    1488             :     {
    1489           4 :         FormulaTokenRef p = mpToken;
    1490           4 :         NextToken();
    1491           4 :         IntersectionLine();
    1492           4 :         PutCode(p);
    1493           4 :     }
    1494       31760 : }
    1495             : 
    1496       31915 : void FormulaCompiler::UnaryLine()
    1497             : {
    1498       31915 :     if( mpToken->GetOpCode() == ocAdd )
    1499           0 :         GetToken();
    1500       38670 :     else if (SC_OPCODE_START_UN_OP <= mpToken->GetOpCode() &&
    1501        6755 :             mpToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
    1502             :     {
    1503         155 :         FormulaTokenRef p = mpToken;
    1504         155 :         NextToken();
    1505         155 :         UnaryLine();
    1506         155 :         PutCode( p );
    1507             :     }
    1508             :     else
    1509       31760 :         UnionLine();
    1510       31915 : }
    1511             : 
    1512       31760 : void FormulaCompiler::PostOpLine()
    1513             : {
    1514       31760 :     UnaryLine();
    1515       63520 :     while ( mpToken->GetOpCode() == ocPercentSign )
    1516             :     {   // this operator _follows_ its operand
    1517           0 :         PutCode( mpToken );
    1518           0 :         NextToken();
    1519             :     }
    1520       31760 : }
    1521             : 
    1522       31757 : void FormulaCompiler::PowLine()
    1523             : {
    1524       31757 :     PostOpLine();
    1525       63517 :     while (mpToken->GetOpCode() == ocPow)
    1526             :     {
    1527           3 :         FormulaTokenRef p = mpToken;
    1528           3 :         NextToken();
    1529           3 :         PostOpLine();
    1530           3 :         PutCode(p);
    1531           3 :     }
    1532       31757 : }
    1533             : 
    1534       29662 : void FormulaCompiler::MulDivLine()
    1535             : {
    1536       29662 :     PowLine();
    1537       61419 :     while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv)
    1538             :     {
    1539        2095 :         FormulaTokenRef p = mpToken;
    1540        2095 :         NextToken();
    1541        2095 :         PowLine();
    1542        2095 :         PutCode(p);
    1543        2095 :     }
    1544       29662 : }
    1545             : 
    1546       25504 : void FormulaCompiler::AddSubLine()
    1547             : {
    1548       25504 :     MulDivLine();
    1549       55166 :     while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub)
    1550             :     {
    1551        4158 :         FormulaTokenRef p = mpToken;
    1552        4158 :         NextToken();
    1553        4158 :         MulDivLine();
    1554        4158 :         PutCode(p);
    1555        4158 :     }
    1556       25504 : }
    1557             : 
    1558       25492 : void FormulaCompiler::ConcatLine()
    1559             : {
    1560       25492 :     AddSubLine();
    1561       50996 :     while (mpToken->GetOpCode() == ocAmpersand)
    1562             :     {
    1563          12 :         FormulaTokenRef p = mpToken;
    1564          12 :         NextToken();
    1565          12 :         AddSubLine();
    1566          12 :         PutCode(p);
    1567          12 :     }
    1568       25492 : }
    1569             : 
    1570       25151 : void FormulaCompiler::CompareLine()
    1571             : {
    1572       25151 :     ConcatLine();
    1573       50643 :     while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual)
    1574             :     {
    1575         341 :         FormulaTokenRef p = mpToken;
    1576         341 :         NextToken();
    1577         341 :         ConcatLine();
    1578         341 :         PutCode(p);
    1579         341 :     }
    1580       25151 : }
    1581             : 
    1582       25151 : void FormulaCompiler::NotLine()
    1583             : {
    1584       25151 :     CompareLine();
    1585       50302 :     while (mpToken->GetOpCode() == ocNot)
    1586             :     {
    1587           0 :         FormulaTokenRef p = mpToken;
    1588           0 :         NextToken();
    1589           0 :         CompareLine();
    1590           0 :         PutCode(p);
    1591           0 :     }
    1592       25151 : }
    1593             : 
    1594       25151 : OpCode FormulaCompiler::Expression()
    1595             : {
    1596             :     static const short nRecursionMax = 42;
    1597       25151 :     FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
    1598       25151 :     if ( nRecursion > nRecursionMax )
    1599             :     {
    1600           0 :         SetError( errStackOverflow );
    1601           0 :         return ocStop;      //! generate token instead?
    1602             :     }
    1603       25151 :     NotLine();
    1604       50302 :     while (mpToken->GetOpCode() == ocAnd || mpToken->GetOpCode() == ocOr)
    1605             :     {
    1606           0 :         FormulaTokenRef p = mpToken;
    1607           0 :         mpToken->SetByte( 2 );       // 2 parameters!
    1608           0 :         NextToken();
    1609           0 :         NotLine();
    1610           0 :         PutCode(p);
    1611           0 :     }
    1612       25151 :     return mpToken->GetOpCode();
    1613             : }
    1614             : 
    1615             : 
    1616           0 : void FormulaCompiler::SetError( sal_uInt16 /*nError*/ )
    1617             : {
    1618           0 : }
    1619             : 
    1620           0 : FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/,
    1621             :         bool /*bReuseDoubleRef*/ )
    1622             : {
    1623           0 :     return FormulaTokenRef();
    1624             : }
    1625             : 
    1626           0 : bool FormulaCompiler::MergeRangeReference( FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
    1627             : {
    1628             :     FormulaToken *p1, *p2;
    1629           0 :     if (pc < 2 || !pCode1 || !pCode2 ||
    1630           0 :             (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
    1631           0 :             ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
    1632           0 :         return false;
    1633             : 
    1634           0 :     FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
    1635           0 :     if (!p)
    1636           0 :         return false;
    1637             : 
    1638           0 :     p->IncRef();
    1639           0 :     p1->DecRef();
    1640           0 :     p2->DecRef();
    1641           0 :     *pCode1 = p.get();
    1642           0 :     --pCode, --pc;
    1643             : 
    1644           0 :     return true;
    1645             : }
    1646             : 
    1647       10067 : bool FormulaCompiler::CompileTokenArray()
    1648             : {
    1649       10067 :     glSubTotal = false;
    1650       10067 :     bCorrected = false;
    1651       10067 :     if (!pArr->GetCodeError() || !mbStopOnError)
    1652             :     {
    1653       10067 :         if ( bAutoCorrect )
    1654             :         {
    1655           0 :             aCorrectedFormula.clear();
    1656           0 :             aCorrectedSymbol.clear();
    1657             :         }
    1658       10067 :         pArr->DelRPN();
    1659       10067 :         pStack = NULL;
    1660             :         FormulaToken* pData[ FORMULA_MAXTOKENS ];
    1661       10067 :         pCode = pData;
    1662       10067 :         bool bWasForced = pArr->IsRecalcModeForced();
    1663       10067 :         if ( bWasForced )
    1664             :         {
    1665           0 :             if ( bAutoCorrect )
    1666           0 :                 aCorrectedFormula = "=";
    1667             :         }
    1668       10067 :         pArr->ClearRecalcMode();
    1669       10067 :         pArr->Reset();
    1670       10067 :         eLastOp = ocOpen;
    1671       10067 :         pc = 0;
    1672       10067 :         NextToken();
    1673       10067 :         OpCode eOp = Expression();
    1674             :         // Some trailing garbage that doesn't form an expression?
    1675       10067 :         if (eOp != ocStop)
    1676        1551 :             SetError( errOperatorExpected);
    1677             : 
    1678       10067 :         sal_uInt16 nErrorBeforePop = pArr->GetCodeError();
    1679             : 
    1680       20134 :         while( pStack )
    1681           0 :             PopTokenArray();
    1682       10067 :         if( pc )
    1683             :         {
    1684        8517 :             pArr->pRPN = new FormulaToken*[ pc ];
    1685        8517 :             pArr->nRPN = pc;
    1686        8517 :             memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
    1687             :         }
    1688             : 
    1689             :         // once an error, always an error
    1690       10067 :         if( !pArr->GetCodeError() && nErrorBeforePop )
    1691           0 :             pArr->SetCodeError( nErrorBeforePop);
    1692             : 
    1693       10067 :         if (pArr->GetCodeError() && mbStopOnError)
    1694             :         {
    1695        1551 :             pArr->DelRPN();
    1696        1551 :             pArr->SetHyperLink( false);
    1697             :         }
    1698             : 
    1699       10067 :         if ( bWasForced )
    1700           0 :             pArr->SetRecalcModeForced();
    1701             :     }
    1702       10067 :     if( nNumFmt == css::util::NumberFormat::UNDEFINED )
    1703        4362 :         nNumFmt = css::util::NumberFormat::NUMBER;
    1704       10067 :     return glSubTotal;
    1705             : }
    1706             : 
    1707         499 : void FormulaCompiler::PopTokenArray()
    1708             : {
    1709         499 :     if( pStack )
    1710             :     {
    1711         499 :         FormulaArrayStack* p = pStack;
    1712         499 :         pStack = p->pNext;
    1713             :         // obtain special RecalcMode from SharedFormula
    1714         499 :         if ( pArr->IsRecalcModeAlways() )
    1715           0 :             p->pArr->SetExclusiveRecalcModeAlways();
    1716         499 :         else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
    1717           0 :             p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
    1718         499 :         p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
    1719         499 :         if ( pArr->IsHyperLink() )  // fdo 87534
    1720           0 :             p->pArr->SetHyperLink( true );
    1721         499 :         if( p->bTemp )
    1722         499 :             delete pArr;
    1723         499 :         pArr = p->pArr;
    1724         499 :         delete p;
    1725             :     }
    1726         499 : }
    1727             : 
    1728         146 : void FormulaCompiler::CreateStringFromTokenArray( OUString& rFormula )
    1729             : {
    1730         146 :     OUStringBuffer aBuffer( pArr->GetLen() * 5 );
    1731         146 :     CreateStringFromTokenArray( aBuffer );
    1732         146 :     rFormula = aBuffer.makeStringAndClear();
    1733         146 : }
    1734             : 
    1735        2724 : void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer )
    1736             : {
    1737        2724 :     rBuffer.setLength(0);
    1738        2724 :     if( !pArr->GetLen() )
    1739        2724 :         return;
    1740             : 
    1741        2724 :     FormulaTokenArray* pSaveArr = pArr;
    1742        2724 :     bool bODFF = FormulaGrammar::isODFF( meGrammar);
    1743        2724 :     if (bODFF || FormulaGrammar::isPODF( meGrammar) )
    1744             :     {
    1745             :         // Scan token array for missing args and re-write if present.
    1746        1354 :         MissingConventionODF aConv( bODFF);
    1747        1354 :         if (pArr->NeedsPodfRewrite( aConv))
    1748          16 :             pArr = pArr->RewriteMissing( aConv );
    1749             :     }
    1750        1370 :     else if ( FormulaGrammar::isOOXML( meGrammar ) )
    1751             :     {
    1752             :         // Scan token array for missing args and rewrite if present.
    1753         560 :         MissingConventionOOXML aConv;
    1754         560 :         if (pArr->NeedsOoxmlRewrite())
    1755         253 :             pArr = pArr->RewriteMissing( aConv );
    1756             :     }
    1757             : 
    1758             :     // At least one character per token, plus some are references, some are
    1759             :     // function names, some are numbers, ...
    1760        2724 :     rBuffer.ensureCapacity( pArr->GetLen() * 5 );
    1761             : 
    1762        2724 :     if ( pArr->IsRecalcModeForced() )
    1763           0 :         rBuffer.append( '=');
    1764        2724 :     const FormulaToken* t = pArr->First();
    1765       21471 :     while( t )
    1766       16023 :         t = CreateStringFromToken( rBuffer, t, true );
    1767             : 
    1768        2724 :     if (pSaveArr != pArr)
    1769             :     {
    1770         269 :         delete pArr;
    1771         269 :         pArr = pSaveArr;
    1772             :     }
    1773             : }
    1774             : 
    1775       25863 : const FormulaToken* FormulaCompiler::CreateStringFromToken( OUString& rFormula, const FormulaToken* pTokenP,
    1776             :         bool bAllowArrAdvance )
    1777             : {
    1778       25863 :     OUStringBuffer aBuffer;
    1779       25863 :     const FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
    1780       25863 :     rFormula += aBuffer.makeStringAndClear();
    1781       25863 :     return p;
    1782             : }
    1783             : 
    1784       41886 : const FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuffer, const FormulaToken* pTokenP,
    1785             :         bool bAllowArrAdvance )
    1786             : {
    1787       41886 :     bool bNext = true;
    1788       41886 :     bool bSpaces = false;
    1789       41886 :     const FormulaToken* t = pTokenP;
    1790       41886 :     OpCode eOp = t->GetOpCode();
    1791       41886 :     if( eOp >= ocAnd && eOp <= ocOr )
    1792             :     {
    1793             :         // AND, OR infix?
    1794          31 :         if ( bAllowArrAdvance )
    1795          31 :             t = pArr->Next();
    1796             :         else
    1797           0 :             t = pArr->PeekNext();
    1798          31 :         bNext = false;
    1799          31 :         bSpaces = ( !t || t->GetOpCode() != ocOpen );
    1800             :     }
    1801       41886 :     if( bSpaces )
    1802           0 :         rBuffer.append( ' ');
    1803             : 
    1804       41886 :     if( eOp == ocSpaces )
    1805             :     {
    1806         337 :         bool bIntersectionOp = mxSymbols->isODFF();
    1807         337 :         if (bIntersectionOp)
    1808             :         {
    1809         160 :             const FormulaToken* p = pArr->PeekPrevNoSpaces();
    1810         160 :             bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
    1811         160 :             if (bIntersectionOp)
    1812             :             {
    1813           0 :                 p = pArr->PeekNextNoSpaces();
    1814           0 :                 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
    1815             :             }
    1816             :         }
    1817         337 :         if (bIntersectionOp)
    1818           0 :             rBuffer.appendAscii( "!!");
    1819             :         else
    1820             :         {
    1821             :             // most times it's just one blank
    1822         337 :             sal_uInt8 n = t->GetByte();
    1823         674 :             for ( sal_uInt8 j=0; j<n; ++j )
    1824             :             {
    1825         337 :                 rBuffer.append( ' ');
    1826             :             }
    1827             :         }
    1828             :     }
    1829       41549 :     else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
    1830           0 :         rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
    1831       41549 :     else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount())        // Keyword:
    1832       41549 :         rBuffer.append( mxSymbols->getSymbol( eOp));
    1833             :     else
    1834             :     {
    1835             :         SAL_WARN( "formula.core","unknown OpCode");
    1836           0 :         rBuffer.append( GetNativeSymbol( ocErrName ));
    1837             :     }
    1838       41886 :     if( bNext )
    1839             :     {
    1840       41855 :         if (t->IsExternalRef())
    1841             :         {
    1842          56 :             CreateStringFromExternal( rBuffer, pTokenP);
    1843             :         }
    1844             :         else
    1845             :         {
    1846       41799 :             switch( t->GetType() )
    1847             :             {
    1848             :             case svDouble:
    1849        2414 :                 AppendDouble( rBuffer, t->GetDouble() );
    1850        2414 :             break;
    1851             : 
    1852             :             case svString:
    1853         418 :                 if( eOp == ocBad || eOp == ocStringXML )
    1854          71 :                     rBuffer.append( t->GetString().getString());
    1855             :                 else
    1856         347 :                     AppendString( rBuffer, t->GetString().getString() );
    1857         418 :                 break;
    1858             :             case svSingleRef:
    1859       15011 :                 CreateStringFromSingleRef( rBuffer, t);
    1860       15011 :                 break;
    1861             :             case svDoubleRef:
    1862       13643 :                 CreateStringFromDoubleRef( rBuffer, t);
    1863       13643 :                 break;
    1864             :             case svMatrix:
    1865           4 :                 CreateStringFromMatrix( rBuffer, t );
    1866           4 :                 break;
    1867             : 
    1868             :             case svIndex:
    1869          55 :                 CreateStringFromIndex( rBuffer, t );
    1870          55 :                 if (t->GetOpCode() == ocTableRef && bAllowArrAdvance && NeedsTableRefTransformation())
    1871             :                 {
    1872             :                     // Suppress all TableRef related tokens, the resulting
    1873             :                     // range was written by CreateStringFromIndex().
    1874           0 :                     const FormulaToken* const p = pArr->PeekNext();
    1875           0 :                     if (p && p->GetOpCode() == ocTableRefOpen)
    1876             :                     {
    1877           0 :                         int nLevel = 0;
    1878           0 :                         do
    1879             :                         {
    1880           0 :                             t = pArr->Next();
    1881           0 :                             if (!t)
    1882           0 :                                 break;
    1883             : 
    1884             :                             // Switch cases correspond with those in
    1885             :                             // ScCompiler::HandleTableRef()
    1886           0 :                             switch (t->GetOpCode())
    1887             :                             {
    1888             :                                 case ocTableRefOpen:
    1889           0 :                                     ++nLevel;
    1890           0 :                                     break;
    1891             :                                 case ocTableRefClose:
    1892           0 :                                     --nLevel;
    1893           0 :                                     break;
    1894             :                                 case ocTableRefItemAll:
    1895             :                                 case ocTableRefItemHeaders:
    1896             :                                 case ocTableRefItemData:
    1897             :                                 case ocTableRefItemTotals:
    1898             :                                 case ocTableRefItemThisRow:
    1899             :                                 case ocSep:
    1900             :                                 case ocPush:
    1901             :                                 case ocRange:
    1902             :                                 case ocSpaces:
    1903           0 :                                     break;
    1904             :                                 default:
    1905           0 :                                     nLevel = 0;
    1906           0 :                                     bNext = false;
    1907             :                             }
    1908             :                         } while (nLevel);
    1909             :                     }
    1910             :                 }
    1911          55 :                 break;
    1912             :             case svExternal:
    1913             :             {
    1914             :                 // mapped or translated name of AddIns
    1915          89 :                 OUString aAddIn( t->GetExternal() );
    1916          89 :                 bool bMapped = mxSymbols->isPODF();     // ODF 1.1 directly uses programmatical name
    1917          89 :                 if (!bMapped && mxSymbols->hasExternals())
    1918             :                 {
    1919          88 :                     ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
    1920          88 :                     if (iLook != mxSymbols->getReverseExternalHashMap()->end())
    1921             :                     {
    1922          88 :                         aAddIn = (*iLook).second;
    1923          88 :                         bMapped = true;
    1924             :                     }
    1925             :                 }
    1926          89 :                 if (!bMapped && !mxSymbols->isEnglish())
    1927           1 :                     LocalizeString( aAddIn );
    1928          89 :                 rBuffer.append( aAddIn);
    1929             :             }
    1930          89 :             break;
    1931             :             case svError:
    1932           0 :                 AppendErrorConstant( rBuffer, t->GetError());
    1933           0 :             break;
    1934             :             case svByte:
    1935             :             case svJump:
    1936             :             case svFAP:
    1937             :             case svMissing:
    1938             :             case svSep:
    1939       10165 :                 break;      // Opcodes
    1940             :             default:
    1941             :                 SAL_WARN("formula.core", "FormulaCompiler::GetStringFromToken: unknown token type " << t->GetType());
    1942             :             } // of switch
    1943             :         }
    1944             :     }
    1945       41886 :     if( bSpaces )
    1946           0 :         rBuffer.append( ' ');
    1947       41886 :     if ( bAllowArrAdvance )
    1948             :     {
    1949       16023 :         if( bNext )
    1950       15992 :             t = pArr->Next();
    1951       16023 :         return t;
    1952             :     }
    1953       25863 :     return pTokenP;
    1954             : }
    1955             : 
    1956             : 
    1957        2426 : void FormulaCompiler::AppendDouble( OUStringBuffer& rBuffer, double fVal ) const
    1958             : {
    1959        2426 :     if ( mxSymbols->isEnglish() )
    1960             :     {
    1961             :         ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
    1962             :                 rtl_math_StringFormat_Automatic,
    1963        2388 :                 rtl_math_DecimalPlaces_Max, '.', true );
    1964             :     }
    1965             :     else
    1966             :     {
    1967          38 :         SvtSysLocale aSysLocale;
    1968             :         ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
    1969             :                 rtl_math_StringFormat_Automatic,
    1970             :                 rtl_math_DecimalPlaces_Max,
    1971          38 :                 aSysLocale.GetLocaleDataPtr()->getNumDecimalSep()[0],
    1972          38 :                 true );
    1973             :     }
    1974        2426 : }
    1975             : 
    1976           0 : void FormulaCompiler::AppendBoolean( OUStringBuffer& rBuffer, bool bVal ) const
    1977             : {
    1978           0 :     rBuffer.append( mxSymbols->getSymbol( static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
    1979           0 : }
    1980             : 
    1981         347 : void FormulaCompiler::AppendString( OUStringBuffer& rBuffer, const OUString & rStr )
    1982             : {
    1983         347 :     rBuffer.append( '"');
    1984         347 :     if ( lcl_UnicodeStrChr( rStr.getStr(), '"' ) == NULL )
    1985         347 :         rBuffer.append( rStr );
    1986             :     else
    1987             :     {
    1988           0 :         OUString aStr = rStr.replaceAll( "\"", "\"\"" );
    1989           0 :         rBuffer.append(aStr);
    1990             :     }
    1991         347 :     rBuffer.append( '"');
    1992         347 : }
    1993             : 
    1994           0 : bool FormulaCompiler::NeedsTableRefTransformation() const
    1995             : {
    1996             :     /* TODO: currently only UI representations use Table structured
    1997             :      * references. Not defined in ODFF, and not implemented yet for OOXML
    1998             :      * export. Change this once OOXML export is implemented, until then write
    1999             :      * A1 style references also for OOXML to not lose functionality. */
    2000             :     // Unnecessary to explicitly check for ODFF grammar as the ocTableRefOpen
    2001             :     // symbol is not defined there.
    2002           0 :     return mxSymbols->getSymbol( ocTableRefOpen).isEmpty() || FormulaGrammar::isPODF( meGrammar)
    2003           0 :         || FormulaGrammar::isOOXML( meGrammar);
    2004             : }
    2005             : 
    2006         467 : void FormulaCompiler::UpdateSeparatorsNative(
    2007             :     const OUString& rSep, const OUString& rArrayColSep, const OUString& rArrayRowSep )
    2008             : {
    2009         467 :     NonConstOpCodeMapPtr xSymbolsNative;
    2010         467 :     lcl_fillNativeSymbols( xSymbolsNative);
    2011         467 :     xSymbolsNative->putOpCode( rSep, ocSep, NULL);
    2012         467 :     xSymbolsNative->putOpCode( rArrayColSep, ocArrayColSep, NULL);
    2013         467 :     xSymbolsNative->putOpCode( rArrayRowSep, ocArrayRowSep, NULL);
    2014         467 : }
    2015             : 
    2016          49 : void FormulaCompiler::ResetNativeSymbols()
    2017             : {
    2018          49 :     NonConstOpCodeMapPtr xSymbolsNative;
    2019          49 :     lcl_fillNativeSymbols( xSymbolsNative, true);
    2020          49 :     lcl_fillNativeSymbols( xSymbolsNative);
    2021          49 : }
    2022             : 
    2023           0 : void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr& xMap )
    2024             : {
    2025           0 :     NonConstOpCodeMapPtr xSymbolsNative;
    2026           0 :     lcl_fillNativeSymbols( xSymbolsNative);
    2027           0 :     xSymbolsNative->copyFrom( *xMap, true);
    2028           0 : }
    2029             : 
    2030             : 
    2031       69047 : OpCode FormulaCompiler::NextToken()
    2032             : {
    2033       69047 :     if( !GetToken() )
    2034        8514 :         return ocStop;
    2035       60533 :     OpCode eOp = mpToken->GetOpCode();
    2036             :     // There must be an operator before a push
    2037       82758 :     if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
    2038       33195 :             !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
    2039        3712 :                 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
    2040           0 :         SetError( errOperatorExpected);
    2041             :     // Operator and Plus => operator
    2042       63866 :     if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
    2043        3333 :                 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
    2044           0 :         eOp = NextToken();
    2045             :     else
    2046             :     {
    2047             :         // Before an operator there must not be another operator, with the
    2048             :         // exception of AND and OR.
    2049       60533 :         if ( eOp != ocAnd && eOp != ocOr &&
    2050       13368 :                 (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP )
    2051       13226 :                 && (eLastOp == ocOpen || eLastOp == ocSep ||
    2052        6613 :                     (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
    2053             :         {
    2054           0 :             SetError( errVariableExpected);
    2055           0 :             if ( bAutoCorrect && !pStack )
    2056             :             {
    2057           0 :                 if ( eOp == eLastOp || eLastOp == ocOpen )
    2058             :                 {   // throw away duplicated operator
    2059           0 :                     aCorrectedSymbol.clear();
    2060           0 :                     bCorrected = true;
    2061             :                 }
    2062             :                 else
    2063             :                 {
    2064           0 :                     sal_Int32 nPos = aCorrectedFormula.getLength();
    2065           0 :                     if ( nPos )
    2066             :                     {
    2067           0 :                         nPos--;
    2068           0 :                         sal_Unicode c = aCorrectedFormula[ nPos ];
    2069           0 :                         switch ( eOp )
    2070             :                         {   // swap operators
    2071             :                             case ocGreater:
    2072           0 :                                 if ( c == mxSymbols->getSymbolChar( ocEqual) )
    2073             :                                 {   // >= instead of =>
    2074           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    2075           0 :                                         OUString( mxSymbols->getSymbolChar(ocGreater) ) );
    2076           0 :                                     aCorrectedSymbol = OUString(c);
    2077           0 :                                     bCorrected = true;
    2078             :                                 }
    2079           0 :                             break;
    2080             :                             case ocLess:
    2081           0 :                                 if ( c == mxSymbols->getSymbolChar( ocEqual) )
    2082             :                                 {   // <= instead of =<
    2083           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    2084           0 :                                         OUString( mxSymbols->getSymbolChar(ocLess) ) );
    2085           0 :                                     aCorrectedSymbol = OUString(c);
    2086           0 :                                     bCorrected = true;
    2087             :                                 }
    2088           0 :                                 else if ( c == mxSymbols->getSymbolChar( ocGreater) )
    2089             :                                 {   // <> instead of ><
    2090           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    2091           0 :                                         OUString( mxSymbols->getSymbolChar(ocLess) ) );
    2092           0 :                                     aCorrectedSymbol = OUString(c);
    2093           0 :                                     bCorrected = true;
    2094             :                                 }
    2095           0 :                             break;
    2096             :                             case ocMul:
    2097           0 :                                 if ( c == mxSymbols->getSymbolChar( ocSub) )
    2098             :                                 {   // *- instead of -*
    2099           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    2100           0 :                                         OUString( mxSymbols->getSymbolChar(ocMul) ) );
    2101           0 :                                     aCorrectedSymbol = OUString(c);
    2102           0 :                                     bCorrected = true;
    2103             :                                 }
    2104           0 :                             break;
    2105             :                             case ocDiv:
    2106           0 :                                 if ( c == mxSymbols->getSymbolChar( ocSub) )
    2107             :                                 {   // /- instead of -/
    2108           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    2109           0 :                                         OUString( mxSymbols->getSymbolChar(ocDiv) ) );
    2110           0 :                                     aCorrectedSymbol = OUString(c);
    2111           0 :                                     bCorrected = true;
    2112             :                                 }
    2113           0 :                             break;
    2114             :                             default:
    2115             :                                 ;   // nothing
    2116             :                         }
    2117             :                     }
    2118             :                 }
    2119             :             }
    2120             :         }
    2121       60533 :         eLastOp = eOp;
    2122             :     }
    2123       60533 :     return eOp;
    2124             : }
    2125       36025 : void FormulaCompiler::PutCode( FormulaTokenRef& p )
    2126             : {
    2127       36025 :     if( pc >= FORMULA_MAXTOKENS - 1 )
    2128             :     {
    2129           0 :         if ( pc == FORMULA_MAXTOKENS - 1 )
    2130             :         {
    2131           0 :             p = new FormulaByteToken( ocStop );
    2132           0 :             p->IncRef();
    2133           0 :             *pCode++ = p.get();
    2134           0 :             ++pc;
    2135             :         }
    2136           0 :         SetError( errCodeOverflow);
    2137           0 :         return;
    2138             :     }
    2139       36025 :     if (pArr->GetCodeError() && mbJumpCommandReorder)
    2140           0 :         return;
    2141       36025 :     ForceArrayOperator( p, pCurrentFactorToken);
    2142       36025 :     p->IncRef();
    2143       36025 :     *pCode++ = p.get();
    2144       36025 :     pc++;
    2145             : }
    2146             : 
    2147             : 
    2148           0 : bool FormulaCompiler::HandleExternalReference( const FormulaToken& /*_aToken*/)
    2149             : {
    2150           0 :     return true;
    2151             : }
    2152             : 
    2153           0 : bool FormulaCompiler::HandleRange()
    2154             : {
    2155           0 :     return true;
    2156             : }
    2157             : 
    2158           0 : bool FormulaCompiler::HandleColRowName()
    2159             : {
    2160           0 :     return true;
    2161             : }
    2162             : 
    2163           0 : bool FormulaCompiler::HandleDbData()
    2164             : {
    2165           0 :     return true;
    2166             : }
    2167             : 
    2168           0 : bool FormulaCompiler::HandleTableRef()
    2169             : {
    2170           0 :     return true;
    2171             : }
    2172             : 
    2173           0 : void FormulaCompiler::CreateStringFromSingleRef( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
    2174             : {
    2175           0 : }
    2176             : 
    2177           0 : void FormulaCompiler::CreateStringFromDoubleRef( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
    2178             : {
    2179           0 : }
    2180             : 
    2181           0 : void FormulaCompiler::CreateStringFromIndex( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
    2182             : {
    2183           0 : }
    2184             : 
    2185           0 : void FormulaCompiler::CreateStringFromMatrix( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
    2186             : {
    2187           0 : }
    2188             : 
    2189           0 : void FormulaCompiler::CreateStringFromExternal( OUStringBuffer& /*rBuffer*/, const FormulaToken* /*pToken*/) const
    2190             : {
    2191           0 : }
    2192             : 
    2193           0 : void FormulaCompiler::LocalizeString( OUString& /*rName*/ ) const
    2194             : {
    2195           0 : }
    2196             : 
    2197         499 : void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
    2198             : {
    2199         499 :     if ( bAutoCorrect && !pStack )
    2200             :     {   // don't merge stacked subroutine code into entered formula
    2201           0 :         aCorrectedFormula += aCorrectedSymbol;
    2202           0 :         aCorrectedSymbol.clear();
    2203             :     }
    2204         499 :     FormulaArrayStack* p = new FormulaArrayStack;
    2205         499 :     p->pNext      = pStack;
    2206         499 :     p->pArr       = pArr;
    2207         499 :     p->bTemp      = bTemp;
    2208         499 :     pStack        = p;
    2209         499 :     pArr          = pa;
    2210         499 : }
    2211             : 
    2212             : } // namespace formula
    2213             : 
    2214             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11