LCOV - code coverage report
Current view: top level - libreoffice/formula/source/core/api - FormulaCompiler.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 611 976 62.6 %
Date: 2012-12-17 Functions: 60 87 69.0 %
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 <svl/zforlist.hxx>
      28             : #include <tools/rc.hxx>
      29             : #include <tools/rcid.h>
      30             : #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
      31             : #include <com/sun/star/sheet/FormulaMapGroup.hpp>
      32             : #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
      33             : #include <rtl/strbuf.hxx>
      34             : #include <stdio.h>
      35             : 
      36             : // =============================================================================
      37             : namespace formula
      38             : {
      39             : // =============================================================================
      40             :     using namespace ::com::sun::star;
      41             : 
      42             :     static const sal_Char* pInternal[ 1 ] = { "TTT" };
      43             : 
      44             : // =============================================================================
      45             : namespace
      46             : {
      47             : // =============================================================================
      48             : class FormulaCompilerRecursionGuard
      49             : {
      50             : private:
      51             :             short&              rRecursion;
      52             : public:
      53       96012 :                                 FormulaCompilerRecursionGuard( short& rRec )
      54       96012 :                                     : rRecursion( rRec ) { ++rRecursion; }
      55       96012 :                                 ~FormulaCompilerRecursionGuard() { --rRecursion; }
      56             : };
      57             : 
      58        3536 : short lcl_GetRetFormat( OpCode eOpCode )
      59             : {
      60        3536 :     switch (eOpCode)
      61             :     {
      62             :         case ocEqual:
      63             :         case ocNotEqual:
      64             :         case ocLess:
      65             :         case ocGreater:
      66             :         case ocLessEqual:
      67             :         case ocGreaterEqual:
      68             :         case ocAnd:
      69             :         case ocOr:
      70             :         case ocXor:
      71             :         case ocNot:
      72             :         case ocTrue:
      73             :         case ocFalse:
      74             :         case ocIsEmpty:
      75             :         case ocIsString:
      76             :         case ocIsNonString:
      77             :         case ocIsLogical:
      78             :         case ocIsRef:
      79             :         case ocIsValue:
      80             :         case ocIsFormula:
      81             :         case ocIsNA:
      82             :         case ocIsErr:
      83             :         case ocIsError:
      84             :         case ocIsEven:
      85             :         case ocIsOdd:
      86             :         case ocExact:
      87         244 :             return NUMBERFORMAT_LOGICAL;
      88             :         case ocGetActDate:
      89             :         case ocGetDate:
      90             :         case ocEasterSunday :
      91           0 :             return NUMBERFORMAT_DATE;
      92             :         case ocGetActTime:
      93           2 :             return NUMBERFORMAT_DATETIME;
      94             :         case ocGetTime:
      95           0 :             return NUMBERFORMAT_TIME;
      96             :         case ocNPV:
      97             :         case ocBW:
      98             :         case ocDIA:
      99             :         case ocGDA:
     100             :         case ocGDA2:
     101             :         case ocVBD:
     102             :         case ocLIA:
     103             :         case ocRMZ:
     104             :         case ocZW:
     105             :         case ocZinsZ:
     106             :         case ocKapz:
     107             :         case ocKumZinsZ:
     108             :         case ocKumKapZ:
     109           0 :             return NUMBERFORMAT_CURRENCY;
     110             :         case ocZins:
     111             :         case ocIRR:
     112             :         case ocMIRR:
     113             :         case ocZGZ:
     114             :         case ocEffektiv:
     115             :         case ocNominal:
     116             :         case ocPercentSign:
     117           0 :             return NUMBERFORMAT_PERCENT;
     118             :         default:
     119        3290 :             return NUMBERFORMAT_NUMBER;
     120             :     }
     121             : }
     122             : 
     123        7062 : inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, sal_uInt16 nOpCode )
     124             : {
     125        7062 :     sheet::FormulaOpCodeMapEntry aEntry;
     126        7062 :     aEntry.Token.OpCode = nOpCode;
     127        7062 :     aEntry.Name = pTable[nOpCode];
     128        7062 :     rVec.push_back( aEntry);
     129        7062 : }
     130             : 
     131          44 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, sal_uInt16 nOpCodeBeg, sal_uInt16 nOpCodeEnd )
     132             : {
     133        2024 :     for (sal_uInt16 nOpCode = nOpCodeBeg; nOpCode < nOpCodeEnd; ++nOpCode)
     134        1980 :         lclPushOpCodeMapEntry( rVec, pTable, nOpCode );
     135          44 : }
     136             : 
     137          66 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, const sal_uInt16* pnOpCodes, size_t nCount )
     138             : {
     139         352 :     for (const sal_uInt16* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes)
     140         286 :         lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes );
     141          66 : }
     142             : 
     143         202 : class OpCodeList : public Resource        // temp object for resource
     144             : {
     145             : public:
     146             : 
     147             :     OpCodeList( sal_uInt16, FormulaCompiler::NonConstOpCodeMapPtr );
     148             : 
     149             : private:
     150             :     bool getOpCodeString( String& rStr, sal_uInt16 nOp );
     151             :     void putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp );
     152             : 
     153             : private:
     154             :     enum SeparatorType
     155             :     {
     156             :         SEMICOLON_BASE,
     157             :         COMMA_BASE
     158             :     };
     159             :     SeparatorType meSepType;
     160             : };
     161             : 
     162         202 : OpCodeList::OpCodeList( sal_uInt16 nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap ) :
     163         202 :     Resource( ResId(nRID,*ResourceManager::getResManager()) )
     164         202 :     ,meSepType(SEMICOLON_BASE)
     165             : {
     166       81608 :      for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
     167             :     {
     168       81406 :         String aOpStr;
     169       81406 :         if ( getOpCodeString(aOpStr, i) )
     170         606 :             xMap->putOpCode(aOpStr, OpCode(i));
     171             :         else
     172       80800 :             putDefaultOpCode(xMap, i);
     173       81406 :     }
     174             : 
     175         202 :     FreeResource();
     176         202 : }
     177             : 
     178       81406 : bool OpCodeList::getOpCodeString( String& rStr, sal_uInt16 nOp )
     179             : {
     180       81406 :     switch (nOp)
     181             :     {
     182             :         case SC_OPCODE_SEP:
     183             :         {
     184         202 :             if (meSepType == COMMA_BASE)
     185             :             {
     186           0 :                 rStr = rtl::OUString(",");
     187           0 :                 return true;
     188             :             }
     189         202 :             else if (meSepType == SEMICOLON_BASE)
     190             :             {
     191         202 :                 rStr = rtl::OUString(";");
     192         202 :                 return true;
     193             :             }
     194             :         }
     195           0 :         break;
     196             :         case SC_OPCODE_ARRAY_COL_SEP:
     197             :         {
     198         202 :             if (meSepType == COMMA_BASE)
     199             :             {
     200           0 :                 rStr = rtl::OUString(",");
     201           0 :                 return true;
     202             :             }
     203         202 :             else if (meSepType == SEMICOLON_BASE)
     204             :             {
     205         202 :                 rStr = rtl::OUString(";");
     206         202 :                 return true;
     207             :             }
     208             :         }
     209           0 :         break;
     210             :         case SC_OPCODE_ARRAY_ROW_SEP:
     211             :         {
     212         202 :             if (meSepType == COMMA_BASE)
     213             :             {
     214           0 :                 rStr = rtl::OUString(";");
     215           0 :                 return true;
     216             :             }
     217         202 :             else if (meSepType == SEMICOLON_BASE)
     218             :             {
     219         202 :                 rStr = rtl::OUString("|");
     220         202 :                 return true;
     221             :             }
     222             :         }
     223           0 :         break;
     224             :     }
     225             : 
     226       80800 :     return false;
     227             : }
     228             : 
     229       80800 : void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp )
     230             : {
     231       80800 :     ResId aRes(nOp,*ResourceManager::getResManager());
     232       80800 :     aRes.SetRT(RSC_STRING);
     233       80800 :     if (IsAvailableRes(aRes))
     234       65234 :         xMap->putOpCode(aRes, OpCode(nOp));
     235       80800 : }
     236             : // -----------------------------------------------------------------------------
     237             : // static
     238           6 : const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,sal_Unicode c )
     239             : {
     240           6 :     if ( !pStr )
     241           0 :         return NULL;
     242          30 :     while ( *pStr )
     243             :     {
     244          18 :         if ( *pStr == c )
     245           0 :             return pStr;
     246          18 :         pStr++;
     247             :     }
     248           6 :     return NULL;
     249             : }
     250             : // =============================================================================
     251             : } // empty
     252             : // =============================================================================
     253             : 
     254        5098 : void FormulaCompiler::OpCodeMap::putExternal( const String & rSymbol, const String & rAddIn )
     255             : {
     256        5098 :     bool bOk = mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second;
     257        5098 :     if (bOk)
     258        5098 :         bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
     259             :     DBG_ASSERT( bOk, "OpCodeMap::putExternal: symbol not inserted");
     260        5098 : }
     261             : 
     262         872 : void FormulaCompiler::OpCodeMap::putExternalSoftly( const String & rSymbol, const String & rAddIn )
     263             : {
     264         872 :     bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
     265         872 :     if (bOk)
     266           0 :         mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn));
     267         872 : }
     268           0 : uno::Sequence< sheet::FormulaToken > FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(const FormulaCompiler& _rCompiler,const uno::Sequence< ::rtl::OUString >& rNames ) const
     269             : {
     270           0 :     const sal_Int32 nLen = rNames.getLength();
     271           0 :     uno::Sequence< sheet::FormulaToken > aTokens( nLen);
     272           0 :     sheet::FormulaToken* pToken = aTokens.getArray();
     273           0 :     ::rtl::OUString const * pName = rNames.getConstArray();
     274           0 :     ::rtl::OUString const * const pStop = pName + nLen;
     275           0 :     for ( ; pName < pStop; ++pName, ++pToken)
     276             :     {
     277           0 :         OpCodeHashMap::const_iterator iLook( mpHashMap->find( *pName));
     278           0 :         if (iLook != mpHashMap->end())
     279           0 :             pToken->OpCode = (*iLook).second;
     280             :         else
     281             :         {
     282           0 :             ::rtl::OUString aIntName;
     283           0 :             if (hasExternals())
     284             :             {
     285           0 :                 ExternalHashMap::const_iterator iExt( mpExternalHashMap->find( *pName));
     286           0 :                 if (iExt != mpExternalHashMap->end())
     287           0 :                     aIntName = (*iExt).second;
     288             :                 // Check for existence not needed here, only name-mapping is of
     289             :                 // interest.
     290             :             }
     291           0 :             if (aIntName.isEmpty())
     292           0 :                 aIntName = _rCompiler.FindAddInFunction(*pName, !isEnglish());    // bLocalFirst=false for english
     293           0 :             if (aIntName.isEmpty())
     294           0 :                 pToken->OpCode = getOpCodeUnknown();
     295             :             else
     296             :             {
     297           0 :                 pToken->OpCode = ocExternal;
     298           0 :                 pToken->Data <<= aIntName;
     299           0 :             }
     300             :         }
     301             :     }
     302           0 :     return aTokens;
     303             : }
     304         132 : uno::Sequence< sheet::FormulaOpCodeMapEntry > FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(const FormulaCompiler& _rCompiler,const sal_Int32 nGroups ) const
     305             : {
     306             :     using namespace sheet;
     307             : 
     308             :     // Unfortunately uno::Sequence can't grow without cumbersome reallocs. As
     309             :     // we don't know in advance how many elements it will have we use a
     310             :     // temporary vector to add elements and then copy to Sequence :-(
     311         132 :     ::std::vector< FormulaOpCodeMapEntry > aVec;
     312             : 
     313         132 :     if (nGroups == FormulaMapGroup::SPECIAL)
     314             :     {
     315             :         // Use specific order, keep in sync with
     316             :         // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl
     317             :         static const struct
     318             :         {
     319             :             sal_Int32 nOff;
     320             :             OpCode    eOp;
     321             :         } aMap[] = {
     322             :             { FormulaMapGroupSpecialOffset::PUSH              , ocPush }           ,
     323             :             { FormulaMapGroupSpecialOffset::CALL              , ocCall }           ,
     324             :             { FormulaMapGroupSpecialOffset::STOP              , ocStop }           ,
     325             :             { FormulaMapGroupSpecialOffset::EXTERNAL          , ocExternal }       ,
     326             :             { FormulaMapGroupSpecialOffset::NAME              , ocName }           ,
     327             :             { FormulaMapGroupSpecialOffset::NO_NAME           , ocNoName }         ,
     328             :             { FormulaMapGroupSpecialOffset::MISSING           , ocMissing }        ,
     329             :             { FormulaMapGroupSpecialOffset::BAD               , ocBad }            ,
     330             :             { FormulaMapGroupSpecialOffset::SPACES            , ocSpaces }         ,
     331             :             { FormulaMapGroupSpecialOffset::MAT_REF           , ocMatRef }         ,
     332             :             { FormulaMapGroupSpecialOffset::DB_AREA           , ocDBArea }         ,
     333             :             { FormulaMapGroupSpecialOffset::MACRO             , ocMacro }          ,
     334             :             { FormulaMapGroupSpecialOffset::COL_ROW_NAME      , ocColRowName }
     335             :         };
     336          22 :         const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
     337             :         // Preallocate vector elements.
     338          22 :         if (aVec.size() < nCount)
     339             :         {
     340          22 :             FormulaOpCodeMapEntry aEntry;
     341          22 :             aEntry.Token.OpCode = getOpCodeUnknown();
     342          22 :             aVec.resize( nCount, aEntry);
     343             :         } // if (aVec.size() < nCount)
     344             : 
     345          22 :         FormulaOpCodeMapEntry aEntry;
     346         308 :         for (size_t i=0; i < nCount; ++i)
     347             :         {
     348         286 :             size_t nIndex = static_cast< size_t >( aMap[i].nOff );
     349         286 :             if (aVec.size() <= nIndex)
     350             :             {
     351             :                 // The offsets really should be aligned with the size, so if
     352             :                 // the vector was preallocated above this code to resize it is
     353             :                 // just a measure in case the table isn't in sync with the API,
     354             :                 // usually it isn't executed.
     355           0 :                 aEntry.Token.OpCode = getOpCodeUnknown();
     356           0 :                 aVec.resize( nIndex + 1, aEntry );
     357             :             }
     358         286 :             aEntry.Token.OpCode = aMap[i].eOp;
     359         286 :             aVec[nIndex] = aEntry;
     360          22 :         }
     361             :     }
     362             :     else
     363             :     {
     364             :         /* FIXME: Once we support error constants in formulas we'll need a map
     365             :          * group for that, e.g. FormulaMapGroup::ERROR_CONSTANTS, and fill
     366             :          * SC_OPCODE_START_ERRORS to SC_OPCODE_STOP_ERRORS. */
     367             : 
     368             :         // Anything else but SPECIAL.
     369         110 :         if ((nGroups & FormulaMapGroup::SEPARATORS) != 0)
     370             :         {
     371             :             static const sal_uInt16 aOpCodes[] = {
     372             :                 SC_OPCODE_OPEN,
     373             :                 SC_OPCODE_CLOSE,
     374             :                 SC_OPCODE_SEP,
     375             :             };
     376          22 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     377             :         }
     378         110 :         if ((nGroups & FormulaMapGroup::ARRAY_SEPARATORS) != 0)
     379             :         {
     380             :             static const sal_uInt16 aOpCodes[] = {
     381             :                 SC_OPCODE_ARRAY_OPEN,
     382             :                 SC_OPCODE_ARRAY_CLOSE,
     383             :                 SC_OPCODE_ARRAY_ROW_SEP,
     384             :                 SC_OPCODE_ARRAY_COL_SEP
     385             :             };
     386          22 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     387             :         }
     388         110 :         if ((nGroups & FormulaMapGroup::UNARY_OPERATORS) != 0)
     389             :         {
     390             :             // Due to the nature of the percent operator following its operand
     391             :             // it isn't sorted into unary operators for compiler interna.
     392          22 :             lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
     393             :             // "+" can be used as unary operator too, push only if binary group is not set
     394          22 :             if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
     395          22 :                 lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
     396             :             // regular unary operators
     397          88 :             for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
     398             :             {
     399          66 :                 switch (nOp)
     400             :                 {
     401             :                     // NOT and NEG in fact are functions but for legacy reasons
     402             :                     // are sorted into unary operators for compiler interna.
     403             :                     case SC_OPCODE_NOT :
     404             :                     case SC_OPCODE_NEG :
     405          44 :                         break;   // nothing,
     406             :                     default:
     407          22 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     408             :                 }
     409             :             }
     410             :         }
     411         110 :         if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
     412             :         {
     413         396 :             for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
     414             :             {
     415         374 :                 switch (nOp)
     416             :                 {
     417             :                     // AND and OR in fact are functions but for legacy reasons
     418             :                     // are sorted into binary operators for compiler interna.
     419             :                     case SC_OPCODE_AND :
     420             :                     case SC_OPCODE_OR :
     421          44 :                         break;   // nothing,
     422             :                     default:
     423         330 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     424             :                 }
     425             :             }
     426             :         }
     427         110 :         if ((nGroups & FormulaMapGroup::FUNCTIONS) != 0)
     428             :         {
     429             :             // Function names are not consecutive, skip the gaps between
     430             :             // functions with no parameter, functions with 1 parameter
     431          22 :             lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_NO_PAR, ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
     432          22 :             lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_1_PAR, ::std::min< sal_uInt16 >( SC_OPCODE_STOP_1_PAR, mnSymbols ) );
     433             :             // Additional functions not within range of functions.
     434             :             static const sal_uInt16 aOpCodes[] = {
     435             :                 SC_OPCODE_IF,
     436             :                 SC_OPCODE_CHOSE,
     437             :                 SC_OPCODE_AND,
     438             :                 SC_OPCODE_OR,
     439             :                 SC_OPCODE_NOT,
     440             :                 SC_OPCODE_NEG
     441             :             };
     442          22 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     443             :             // functions with 2 or more parameters.
     444        4444 :             for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
     445             :             {
     446        4422 :                 switch (nOp)
     447             :                 {
     448             :                     // NO_NAME is in SPECIAL.
     449             :                     case SC_OPCODE_NO_NAME :
     450          22 :                         break;   // nothing,
     451             :                     default:
     452        4400 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     453             :                 }
     454             :             }
     455             :             // If AddIn functions are present in this mapping, use them, and only those.
     456          22 :             if (hasExternals())
     457             :             {
     458        2420 :                 for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
     459             :                 {
     460        2398 :                     FormulaOpCodeMapEntry aEntry;
     461        2398 :                     aEntry.Name = (*it).first;
     462        2398 :                     aEntry.Token.Data <<= ::rtl::OUString( (*it).second);
     463        2398 :                     aEntry.Token.OpCode = ocExternal;
     464        2398 :                     aVec.push_back( aEntry);
     465        2398 :                 }
     466             :             }
     467             :             else
     468             :             {
     469           0 :                 _rCompiler.fillAddInToken(aVec,isEnglish());
     470             :             }
     471             :         }
     472             :     }
     473         132 :     const FormulaOpCodeMapEntry* pRet = aVec.empty() ? 0 : &aVec[0];
     474         132 :     return uno::Sequence< FormulaOpCodeMapEntry >(pRet, aVec.size());
     475             : }
     476             : //-----------------------------------------------------------------------------
     477             : 
     478       72790 : void FormulaCompiler::OpCodeMap::putOpCode( const String & rStr, const OpCode eOp )
     479             : {
     480             :     DBG_ASSERT( 0 < eOp && sal_uInt16(eOp) < mnSymbols, "OpCodeMap::putOpCode: OpCode out of range");
     481       72790 :     if (0 < eOp && sal_uInt16(eOp) < mnSymbols)
     482             :     {
     483             :         DBG_ASSERT( (mpTable[eOp].Len() == 0) || (mpTable[eOp] == rStr) ||
     484             :             (eOp == ocCurrency) || (eOp == ocSep) || (eOp == ocArrayColSep) ||
     485             :             (eOp == ocArrayRowSep),
     486             :             rtl::OStringBuffer(
     487             :                 RTL_CONSTASCII_STRINGPARAM("OpCodeMap::putOpCode: reusing OpCode ")).
     488             :             append(sal_Int32(eOp)).append(RTL_CONSTASCII_STRINGPARAM(" (")).
     489             :             append(rtl::OUStringToOString(rStr, RTL_TEXTENCODING_ASCII_US)).
     490             :             append(')').getStr());
     491       72790 :         mpTable[eOp] = rStr;
     492       72790 :         mpHashMap->insert( OpCodeHashMap::value_type( rStr, eOp));
     493             :     }
     494       72790 : }
     495             : // -----------------------------------------------------------------------------
     496             : // class FormulaCompiler
     497             : // -----------------------------------------------------------------------------
     498             : DBG_NAME(FormulaCompiler)
     499        7568 : FormulaCompiler::FormulaCompiler(FormulaTokenArray& _rArr)
     500             :         :
     501             :         pArr( &_rArr ),
     502             :         pExternalRef(NULL),
     503             :         pStack( NULL ),
     504             :         nRecursion(0),
     505             :         nNumFmt( NUMBERFORMAT_UNDEFINED ),
     506             :         meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
     507             :         bAutoCorrect( false ),
     508             :         bCorrected( false ),
     509             :         bCompileForFAP( false ),
     510        7568 :         bIgnoreErrors( false )
     511             : 
     512             : {
     513             :     DBG_CTOR(FormulaCompiler,NULL);
     514        7568 : }
     515        1132 : FormulaCompiler::FormulaCompiler()
     516             :         :
     517             :         pArr( NULL ),
     518             :         pExternalRef(NULL),
     519             :         pStack( NULL ),
     520             :         nRecursion(0),
     521             :         nNumFmt( NUMBERFORMAT_UNDEFINED ),
     522             :         meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
     523             :         bAutoCorrect( false ),
     524             :         bCorrected( false ),
     525             :         bCompileForFAP( false ),
     526        1132 :         bIgnoreErrors( false )
     527             : 
     528             : {
     529             :     DBG_CTOR(FormulaCompiler,NULL);
     530        1132 : }
     531        8700 : FormulaCompiler::~FormulaCompiler()
     532             : {
     533             :     DBG_DTOR(FormulaCompiler,NULL);
     534        8700 : }
     535             : 
     536        8832 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
     537             : {
     538        8832 :     FormulaCompiler::OpCodeMapPtr xMap;
     539             :     using namespace sheet;
     540        8832 :     switch (nLanguage)
     541             :     {
     542             :         case FormulaLanguage::ODFF :
     543        1868 :             if (!mxSymbolsODFF)
     544        1758 :                 InitSymbolsODFF();
     545        1868 :             xMap = mxSymbolsODFF;
     546        1868 :             break;
     547             :         case FormulaLanguage::ODF_11 :
     548          78 :             if (!mxSymbolsPODF)
     549          78 :                 InitSymbolsPODF();
     550          78 :             xMap = mxSymbolsPODF;
     551          78 :             break;
     552             :         case FormulaLanguage::ENGLISH :
     553           8 :             if (!mxSymbolsEnglish)
     554           8 :                 InitSymbolsEnglish();
     555           8 :             xMap = mxSymbolsEnglish;
     556           8 :             break;
     557             :         case FormulaLanguage::NATIVE :
     558        6728 :             if (!mxSymbolsNative)
     559        6728 :                 InitSymbolsNative();
     560        6728 :             xMap = mxSymbolsNative;
     561        6728 :             break;
     562             :         case FormulaLanguage::XL_ENGLISH:
     563         150 :             if (!mxSymbolsEnglishXL)
     564         150 :                 InitSymbolsEnglishXL();
     565         150 :             xMap = mxSymbolsEnglishXL;
     566         150 :             break;
     567             :         default:
     568             :             ;   // nothing, NULL map returned
     569             :     }
     570        8832 :     return xMap;
     571             : }
     572             : // -----------------------------------------------------------------------------
     573             : 
     574           0 : String FormulaCompiler::FindAddInFunction( const String& /*rUpperName*/, bool /*bLocalFirst*/ ) const
     575             : {
     576           0 :     return String();
     577             : }
     578             : // -----------------------------------------------------------------------------
     579          22 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
     580             :         const uno::Sequence<
     581             :         const sheet::FormulaOpCodeMapEntry > & rMapping,
     582             :         bool bEnglish )
     583             : {
     584             :     using sheet::FormulaOpCodeMapEntry;
     585             :     // Filter / API maps are never Core
     586          22 :     NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1,false, FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(FormulaGrammar::GRAM_EXTERNAL, bEnglish),FormulaGrammar::CONV_UNSPECIFIED)));
     587          22 :     FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
     588          22 :     FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
     589        8052 :     for ( ; pArr2 < pStop; ++pArr2)
     590             :     {
     591        8030 :         OpCode eOp = OpCode(pArr2->Token.OpCode);
     592        8030 :         if (eOp != ocExternal)
     593        5984 :             xMap->putOpCode( pArr2->Name, eOp);
     594             :         else
     595             :         {
     596        2046 :             ::rtl::OUString aExternalName;
     597        2046 :             if (pArr2->Token.Data >>= aExternalName)
     598        2046 :                 xMap->putExternal( pArr2->Name, aExternalName);
     599             :             else
     600             :             {
     601             :                 SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
     602        2046 :             }
     603             :         }
     604             :     }
     605          22 :     return xMap;
     606             : }
     607             : 
     608             : // -----------------------------------------------------------------------------
     609        8749 : void lcl_fillNativeSymbols(FormulaCompiler::NonConstOpCodeMapPtr& _xMap,bool _destroy = false)
     610             : {
     611        8749 :     static FormulaCompiler::NonConstOpCodeMapPtr s_SymbolMap;
     612        8749 :     if ( _destroy )
     613             :     {
     614         172 :         s_SymbolMap.reset();
     615             :     } // if ( _destroy )
     616        8577 :     else if ( !s_SymbolMap.get() )
     617             :     {
     618             :         // Core
     619         174 :         s_SymbolMap.reset( new FormulaCompiler::OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
     620         174 :         OModuleClient aModuleClient;
     621         174 :         OpCodeList aOpCodeListNative( RID_STRLIST_FUNCTION_NAMES, s_SymbolMap );
     622             :         // No AddInMap for native core mapping.
     623             :     } // if ( !s_SymbolMap.get() )
     624        8749 :     _xMap = s_SymbolMap;
     625        8749 : }
     626             : // -----------------------------------------------------------------------------
     627        1505 : const String& FormulaCompiler::GetNativeSymbol( OpCode eOp )
     628             : {
     629        1505 :     NonConstOpCodeMapPtr xSymbolsNative;
     630        1505 :     lcl_fillNativeSymbols(xSymbolsNative);
     631        1505 :     return xSymbolsNative->getSymbol( eOp );
     632             : }
     633             : // -----------------------------------------------------------------------------
     634        6728 : void FormulaCompiler::InitSymbolsNative() const
     635             : {
     636        6728 :     lcl_fillNativeSymbols(mxSymbolsNative);
     637        6728 : }
     638             : // -----------------------------------------------------------------------------
     639           8 : void FormulaCompiler::InitSymbolsEnglish() const
     640             : {
     641           8 :     static NonConstOpCodeMapPtr s_sSymbol;
     642           8 :     if ( !s_sSymbol.get() )
     643           2 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
     644           8 :     mxSymbolsEnglish = s_sSymbol;
     645           8 : }
     646             : // -----------------------------------------------------------------------------
     647          78 : void FormulaCompiler::InitSymbolsPODF() const
     648             : {
     649          78 :     static NonConstOpCodeMapPtr s_sSymbol;
     650          78 :     if ( !s_sSymbol.get() )
     651           6 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_PODF,s_sSymbol);
     652          78 :     mxSymbolsPODF = s_sSymbol;
     653          78 : }
     654             : // -----------------------------------------------------------------------------
     655        1758 : void FormulaCompiler::InitSymbolsODFF() const
     656             : {
     657        1758 :     static NonConstOpCodeMapPtr s_sSymbol;
     658        1758 :     if ( !s_sSymbol.get() )
     659          16 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF,FormulaGrammar::GRAM_ODFF,s_sSymbol);
     660        1758 :     mxSymbolsODFF = s_sSymbol;
     661        1758 : }
     662             : // -----------------------------------------------------------------------------
     663         150 : void FormulaCompiler::InitSymbolsEnglishXL() const
     664             : {
     665         150 :     static NonConstOpCodeMapPtr s_sSymbol;
     666         150 :     if ( !s_sSymbol.get() )
     667           4 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
     668         150 :     mxSymbolsEnglishXL = s_sSymbol;
     669             : 
     670             :     // TODO: For now, just replace the separators to the Excel English
     671             :     // variants. Later, if we want to properly map Excel functions with Calc
     672             :     // functions, we'll need to do a little more work here.
     673         150 :     mxSymbolsEnglishXL->putOpCode(rtl::OUString(','), ocSep);
     674         150 :     mxSymbolsEnglishXL->putOpCode(rtl::OUString(','), ocArrayColSep);
     675         150 :     mxSymbolsEnglishXL->putOpCode(rtl::OUString(';'), ocArrayRowSep);
     676         150 : }
     677             : 
     678             : // -----------------------------------------------------------------------------
     679          28 : void FormulaCompiler::loadSymbols(sal_uInt16 _nSymbols,FormulaGrammar::Grammar _eGrammar,NonConstOpCodeMapPtr& _xMap) const
     680             : {
     681          28 :     if ( !_xMap.get() )
     682             :     {
     683             :         // not Core
     684          28 :         _xMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, _eGrammar != FormulaGrammar::GRAM_ODFF, _eGrammar ));
     685          28 :         OModuleClient aModuleClient;
     686          28 :         OpCodeList aOpCodeList( _nSymbols, _xMap );
     687             : 
     688          28 :         fillFromAddInMap( _xMap, _eGrammar);
     689             :         // Fill from collection for AddIns not already present.
     690          28 :         if ( FormulaGrammar::GRAM_ENGLISH != _eGrammar )
     691          22 :             fillFromAddInCollectionUpperName( _xMap);
     692             :         else
     693           6 :             fillFromAddInCollectionEnglishName( _xMap);
     694             :     }
     695          28 : }
     696             : // -----------------------------------------------------------------------------
     697           0 : void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const
     698             : {
     699           0 : }
     700             : // -----------------------------------------------------------------------------
     701           0 : void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const
     702             : {
     703           0 : }
     704             : // -----------------------------------------------------------------------------
     705           0 : void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const
     706             : {
     707           0 : }
     708             : // -----------------------------------------------------------------------------
     709           0 : OpCode FormulaCompiler::GetEnglishOpCode( const String& rName ) const
     710             : {
     711           0 :     FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap(sheet::FormulaLanguage::ENGLISH);
     712             : 
     713           0 :     formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) );
     714           0 :     bool bFound = (iLook != xMap->getHashMap()->end());
     715           0 :     return bFound ? (*iLook).second : OpCode(ocNone);
     716             : }
     717             : 
     718       19682 : bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
     719             : {
     720       19682 :     bool bRet = false;
     721       19682 :     switch (eOp)
     722             :     {
     723             :         // no parameters:
     724             :         case ocRandom:
     725             :         case ocGetActDate:
     726             :         case ocGetActTime:
     727             :         // one parameter:
     728             :         case ocFormula:
     729             :         case ocInfo:
     730             :         // more than one parameters:
     731             :             // ocIndirect/ocIndirectXL otherwise would have to do
     732             :             // StopListening and StartListening on a reference for every
     733             :             // interpreted value.
     734             :         case ocIndirect:
     735             :         case ocIndirectXL:
     736             :             // ocOffset results in indirect references.
     737             :         case ocOffset:
     738         130 :             bRet = true;
     739         130 :             break;
     740             :         default:
     741       19552 :             bRet = false;
     742       19552 :             break;
     743             :     }
     744       19682 :     return bRet;
     745             : }
     746             : 
     747             : // Remove quotes, escaped quotes are unescaped.
     748          16 : bool FormulaCompiler::DeQuote( String& rStr )
     749             : {
     750          16 :     xub_StrLen nLen = rStr.Len();
     751          16 :     if ( nLen > 1 && rStr.GetChar(0) == '\'' && rStr.GetChar( nLen-1 ) == '\'' )
     752             :     {
     753           0 :         rStr.Erase( nLen-1, 1 );
     754           0 :         rStr.Erase( 0, 1 );
     755           0 :         xub_StrLen nPos = 0;
     756           0 :         while ( (nPos = rStr.SearchAscii( "\\\'", nPos)) != STRING_NOTFOUND )
     757             :         {
     758           0 :             rStr.Erase( nPos, 1 );
     759           0 :             ++nPos;
     760             :         }
     761           0 :         return true;
     762             :     }
     763          16 :     return false;
     764             : }
     765             : // -----------------------------------------------------------------------------
     766           0 : void FormulaCompiler::fillAddInToken(::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,bool /*_bIsEnglish*/) const
     767             : {
     768           0 : }
     769             : // -----------------------------------------------------------------------------
     770           0 : bool FormulaCompiler::IsMatrixFunction(OpCode _eOpCode)
     771             : {
     772           0 :     switch ( _eOpCode )
     773             :     {
     774             :         case ocDde :
     775             :         case ocGrowth :
     776             :         case ocTrend :
     777             :         case ocRKP :
     778             :         case ocRGP :
     779             :         case ocFrequency :
     780             :         case ocMatTrans :
     781             :         case ocMatMult :
     782             :         case ocMatInv :
     783             :         case ocMatrixUnit :
     784           0 :             return true;
     785             :         default:
     786             :         {
     787             :             // added to avoid warnings
     788             :         }
     789             :     }
     790           0 :     return false;
     791             : }
     792             : 
     793             : // -----------------------------------------------------------------------------
     794         448 : FormulaCompiler::OpCodeMap::~OpCodeMap()
     795             : {
     796         224 :     delete mpReverseExternalHashMap;
     797         224 :     delete mpExternalHashMap;
     798         224 :     delete [] mpTable;
     799         224 :     delete mpHashMap;
     800         448 : }
     801             : // -----------------------------------------------------------------------------
     802           0 : void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap& r )
     803             : {
     804           0 :     delete mpHashMap;
     805           0 :     mpHashMap = new OpCodeHashMap(mnSymbols);
     806             : 
     807           0 :     sal_uInt16 n = r.getSymbolCount();
     808           0 :     for (sal_uInt16 i = 0; i < n; ++i)
     809             :     {
     810           0 :         OpCode eOp = OpCode(i);
     811           0 :         const String& rSymbol = r.getSymbol(eOp);
     812           0 :         putOpCode(rSymbol, eOp);
     813             :     }
     814             : 
     815             :     // TODO: maybe copy the external maps too?
     816           0 : }
     817             : // -----------------------------------------------------------------------------
     818             : 
     819           0 : sal_uInt16 FormulaCompiler::GetErrorConstant( const String& rName )
     820             : {
     821           0 :     sal_uInt16 nError = 0;
     822           0 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
     823           0 :     if (iLook != mxSymbols->getHashMap()->end())
     824             :     {
     825           0 :         switch ((*iLook).second)
     826             :         {
     827             :             // Not all may make sense in a formula, but these we know as 
     828             :             // opcodes.
     829             :             case ocErrNull:
     830           0 :                 nError = errNoCode;
     831           0 :                 break;
     832             :             case ocErrDivZero:
     833           0 :                 nError = errDivisionByZero;
     834           0 :                 break;
     835             :             case ocErrValue:
     836           0 :                 nError = errNoValue;
     837           0 :                 break;
     838             :             case ocErrRef:
     839           0 :                 nError = errNoRef;
     840           0 :                 break;
     841             :             case ocErrName:
     842           0 :                 nError = errNoName;
     843           0 :                 break;
     844             :             case ocErrNum:
     845           0 :                 nError = errIllegalFPOperation;
     846           0 :                 break;
     847             :             case ocErrNA:
     848           0 :                 nError = NOTAVAILABLE;
     849           0 :                 break;
     850             :             default:
     851             :                 ;   // nothing
     852             :         }
     853             :     }
     854           0 :     return nError;
     855             : }
     856             : 
     857             : 
     858           0 : void FormulaCompiler::AppendErrorConstant( rtl::OUStringBuffer& rBuffer, sal_uInt16 nError )
     859             : {
     860             :     OpCode eOp;
     861           0 :     switch (nError)
     862             :     {
     863             :         default:
     864             :         case errNoCode:
     865           0 :             eOp = ocErrNull;
     866           0 :             break;
     867             :         case errDivisionByZero:
     868           0 :             eOp = ocErrDivZero;
     869           0 :             break;
     870             :         case errNoValue:
     871           0 :             eOp = ocErrValue;
     872           0 :             break;
     873             :         case errNoRef:
     874           0 :             eOp = ocErrRef;
     875           0 :             break;
     876             :         case errNoName:
     877           0 :             eOp = ocErrName;
     878           0 :             break;
     879             :         case errIllegalFPOperation:
     880           0 :             eOp = ocErrNum;
     881           0 :             break;
     882             :         case NOTAVAILABLE:
     883           0 :             eOp = ocErrNA;
     884           0 :             break;
     885             :     }
     886           0 :     rBuffer.append( mxSymbols->getSymbol( eOp));
     887           0 : }
     888             : 
     889             : // -----------------------------------------------------------------------------
     890          44 : sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
     891             : {
     892             :     static const sal_Int32 kOpCodeUnknown = -1;
     893          44 :     return kOpCodeUnknown;
     894             : }
     895             : // -----------------------------------------------------------------------------
     896       73484 : bool FormulaCompiler::GetToken()
     897             : {
     898             :     static const short nRecursionMax = 42;
     899       73484 :     FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
     900       73484 :     if ( nRecursion > nRecursionMax )
     901             :     {
     902           0 :         SetError( errStackOverflow );
     903           0 :         mpToken = new FormulaByteToken( ocStop );
     904           0 :         return false;
     905             :     }
     906       73484 :     if ( bAutoCorrect && !pStack )
     907             :     {   // don't merge stacked subroutine code into entered formula
     908           0 :         aCorrectedFormula += aCorrectedSymbol;
     909           0 :         aCorrectedSymbol.Erase();
     910             :     }
     911       73484 :     bool bStop = false;
     912       73484 :     if( pArr->GetCodeError() && !bIgnoreErrors )
     913           0 :         bStop = true;
     914             :     else
     915             :     {
     916             :         short nWasColRowName;
     917      139538 :         if ( pArr->nIndex
     918       66054 :           && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
     919           0 :              nWasColRowName = 1;
     920             :         else
     921       73484 :              nWasColRowName = 0;
     922       73484 :         mpToken = pArr->Next();
     923      147036 :         while( mpToken && mpToken->GetOpCode() == ocSpaces )
     924             :         {
     925          68 :             if ( nWasColRowName )
     926           0 :                 nWasColRowName++;
     927          68 :             if ( bAutoCorrect && !pStack )
     928           0 :                 CreateStringFromToken( aCorrectedFormula, mpToken.get(), false );
     929          68 :             mpToken = pArr->Next();
     930             :         }
     931       73484 :         if ( bAutoCorrect && !pStack && mpToken )
     932           0 :             CreateStringFromToken( aCorrectedSymbol, mpToken.get(), false );
     933       73484 :         if( !mpToken )
     934             :         {
     935        6694 :             if( pStack )
     936             :             {
     937         362 :                 PopTokenArray();
     938         362 :                 return GetToken();
     939             :             }
     940             :             else
     941        6332 :                 bStop = true;
     942             :         }
     943             :         else
     944             :         {
     945       66790 :             if ( nWasColRowName >= 2 && mpToken->GetOpCode() == ocColRowName )
     946             :             {   // convert an ocSpaces to ocIntersect in RPN
     947           0 :                 mpToken = new FormulaByteToken( ocIntersect );
     948           0 :                 pArr->nIndex--;     // we advanced to the second ocColRowName, step back
     949             :             }
     950             :         }
     951             :     }
     952       73122 :     if( bStop )
     953             :     {
     954        6332 :         mpToken = new FormulaByteToken( ocStop );
     955        6332 :         return false;
     956             :     }
     957       66790 :     if( mpToken->GetOpCode() == ocSubTotal )
     958           0 :         glSubTotal = true;
     959       66790 :     else if ( mpToken->IsExternalRef() )
     960             :     {
     961          68 :         return HandleExternalReference(*mpToken);
     962             :     }
     963       66722 :     else if( mpToken->GetOpCode() == ocName )
     964             :     {
     965         318 :         return HandleRange();
     966             :     }
     967       66404 :     else if( mpToken->GetOpCode() == ocColRowName )
     968             :     {
     969           0 :         return HandleSingleRef();
     970             :     }
     971       66404 :     else if( mpToken->GetOpCode() == ocDBArea )
     972             :     {
     973           4 :         return HandleDbData();
     974             :     }
     975       66400 :     else if( mpToken->GetType() == svSingleRef )
     976             :     {
     977       10024 :         pArr->nRefs++;
     978             :     }
     979       56376 :     else if( mpToken->GetType() == svDoubleRef )
     980             :     {
     981        4442 :         pArr->nRefs++;
     982             :     }
     983       66400 :     return true;
     984             : }
     985             : //---------------------------------------------------------------------------
     986             : // RPN creation by recursion
     987             : //---------------------------------------------------------------------------
     988             : 
     989       33028 : void FormulaCompiler::Factor()
     990             : {
     991       33028 :     if ( pArr->GetCodeError() && !bIgnoreErrors )
     992       33028 :         return;
     993             : 
     994       33028 :     CurrentFactor pFacToken( this );
     995             : 
     996       33028 :     OpCode eOp = mpToken->GetOpCode();
     997       33028 :     if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
     998             :             eOp == ocDBArea
     999             :             || (bCompileForFAP && ((eOp == ocName) || (eOp == ocDBArea)
    1000             :             || (eOp == ocColRowName) || (eOp == ocBad)))
    1001             :         )
    1002             :     {
    1003       23048 :         PutCode( mpToken );
    1004       23048 :         eOp = NextToken();
    1005       46096 :         if( eOp == ocOpen )
    1006             :         {
    1007             :             // PUSH( is an error that may be caused by an unknown function.
    1008             :             SetError(
    1009           0 :                 ( mpToken->GetType() == svString
    1010           0 :                || mpToken->GetType() == svSingleRef )
    1011           0 :                ? errNoName : errOperatorExpected );
    1012           0 :             if ( bAutoCorrect && !pStack )
    1013             :             {   // assume multiplication
    1014           0 :                 aCorrectedFormula += mxSymbols->getSymbol(ocMul);
    1015           0 :                 bCorrected = true;
    1016           0 :                 NextToken();
    1017           0 :                 eOp = Expression();
    1018           0 :                 if( eOp != ocClose )
    1019           0 :                     SetError(errPairExpected);
    1020             :                 else
    1021           0 :                     eOp = NextToken();
    1022             :             }
    1023             :         }
    1024             :     }
    1025        9980 :     else if( eOp == ocOpen )
    1026             :     {
    1027        1988 :         NextToken();
    1028        1988 :         eOp = Expression();
    1029        3976 :         while ((eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors))
    1030             :         {   // range list  (A1;A2)  converted to  (A1~A2)
    1031           0 :             pFacToken = mpToken;
    1032           0 :             NextToken();
    1033           0 :             eOp = Expression();
    1034             :             // Do not ignore error here, regardless of bIgnoreErrors, otherwise
    1035             :             // errors like =(1;) would also result in display of =(1~)
    1036           0 :             if (!pArr->GetCodeError())
    1037             :             {
    1038           0 :                 pFacToken->NewOpCode( ocUnion,FormulaToken::PrivateAccess());
    1039           0 :                 PutCode( pFacToken);
    1040             :             }
    1041             :         }
    1042        1988 :         if (eOp != ocClose)
    1043           0 :             SetError(errPairExpected);
    1044             :         else
    1045        1988 :             eOp = NextToken();
    1046             :     }
    1047             :     else
    1048             :     {
    1049        7992 :         if( nNumFmt == NUMBERFORMAT_UNDEFINED )
    1050        3536 :             nNumFmt = lcl_GetRetFormat( eOp );
    1051             : 
    1052        7992 :         if ( IsOpCodeVolatile(eOp) )
    1053          44 :             pArr->SetRecalcModeAlways();
    1054             :         else
    1055             :         {
    1056        7948 :             switch( eOp )
    1057             :             {
    1058             :                     // Functions recalculated on every document load.
    1059             :                     // Don't use SetRecalcModeOnLoad() which would override
    1060             :                     // ModeAlways.
    1061             :                 case ocConvert :
    1062           0 :                     pArr->AddRecalcMode( RECALCMODE_ONLOAD );
    1063           0 :                 break;
    1064             :                     // If the referred cell is moved the value changes.
    1065             :                 case ocColumn :
    1066             :                 case ocRow :
    1067             :                     // ocCell needs recalc on move for some possible type values.
    1068             :                 case ocCell :
    1069         108 :                     pArr->SetRecalcModeOnRefMove();
    1070         108 :                 break;
    1071             :                 case ocHyperLink :
    1072             :                     // cell with hyperlink needs to be calculated on load to
    1073             :                     // get its matrix result generated.
    1074           0 :                     pArr->SetRecalcModeOnLoad();
    1075           0 :                     pArr->SetHyperLink(true);
    1076           0 :                 break;
    1077             :                 default:
    1078             :                     ;   // nothing
    1079             :             }
    1080             :         }
    1081        7992 :         if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
    1082             :         {
    1083         104 :             pFacToken = mpToken;
    1084         104 :             eOp = NextToken();
    1085         208 :             if (eOp != ocOpen)
    1086             :             {
    1087           0 :                 SetError(errPairExpected);
    1088           0 :                 PutCode( pFacToken );
    1089             :             }
    1090             :             else
    1091             :             {
    1092         104 :                 eOp = NextToken();
    1093         104 :                 if (eOp != ocClose)
    1094           0 :                     SetError(errPairExpected);
    1095         104 :                 PutCode(pFacToken);
    1096         104 :                 eOp = NextToken();
    1097             :             }
    1098             :         }
    1099             :         // special cases NOT() and NEG()
    1100        7888 :         else if( eOp == ocNot || eOp == ocNeg
    1101             :               || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
    1102             :         {
    1103         404 :             pFacToken = mpToken;
    1104         404 :             eOp = NextToken();
    1105         404 :             if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot )
    1106           0 :                 nNumFmt = NUMBERFORMAT_LOGICAL;
    1107         404 :             if (eOp == ocOpen)
    1108             :             {
    1109         404 :                 NextToken();
    1110         404 :                 eOp = Expression();
    1111             :             }
    1112             :             else
    1113           0 :                 SetError(errPairExpected);
    1114         404 :             if (eOp != ocClose)
    1115           0 :                 SetError(errPairExpected);
    1116         404 :             else if ( !pArr->GetCodeError() )
    1117         404 :                 pFacToken->SetByte( 1 );
    1118         404 :             PutCode( pFacToken );
    1119         404 :             eOp = NextToken();
    1120             :         }
    1121        7484 :         else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
    1122             :                 || eOp == ocExternal
    1123             :                 || eOp == ocMacro
    1124             :                 || eOp == ocAnd
    1125             :                 || eOp == ocOr
    1126             :                 || eOp == ocBad
    1127             :                 || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
    1128             :                 || (bCompileForFAP && ((eOp == ocIf) || (eOp == ocChose)))
    1129             :             )
    1130             :         {
    1131        6698 :             pFacToken = mpToken;
    1132        6698 :             OpCode eMyLastOp = eOp;
    1133        6698 :             eOp = NextToken();
    1134        6698 :             bool bNoParam = false;
    1135        6698 :             bool bBadName = false;
    1136        6698 :             if (eOp == ocOpen)
    1137             :             {
    1138        6684 :                 eOp = NextToken();
    1139        6684 :                 if (eOp == ocClose)
    1140          10 :                     bNoParam = true;
    1141             :                 else
    1142        6674 :                     eOp = Expression();
    1143             :             }
    1144          14 :             else if (eMyLastOp == ocBad)
    1145             :             {
    1146             :                 // Just a bad name, not an unknown function, no parameters, no
    1147             :                 // closing expected.
    1148          14 :                 bBadName = true;
    1149          14 :                 bNoParam = true;
    1150             :             }
    1151             :             else
    1152           0 :                 SetError(errPairExpected);
    1153        6698 :             sal_uInt8 nSepCount = 0;
    1154        6698 :             if( !bNoParam )
    1155             :             {
    1156        6674 :                 nSepCount++;
    1157       19646 :                 while ( (eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors) )
    1158             :                 {
    1159        6298 :                     nSepCount++;
    1160        6298 :                     NextToken();
    1161        6298 :                     eOp = Expression();
    1162             :                 }
    1163             :             }
    1164        6698 :             if (bBadName)
    1165             :                 ;   // nothing, keep current token for return
    1166        6684 :             else if (eOp != ocClose)
    1167           0 :                 SetError(errPairExpected);
    1168             :             else
    1169        6684 :                 eOp = NextToken();
    1170             :             // Jumps are just normal functions for the FunctionAutoPilot tree view
    1171        6698 :             if ( bCompileForFAP && pFacToken->GetType() == svJump )
    1172           0 :                 pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
    1173             :             else
    1174        6698 :                 pFacToken->SetByte( nSepCount );
    1175        6698 :             PutCode( pFacToken );
    1176             :         }
    1177         786 :         else if (eOp == ocIf || eOp == ocChose)
    1178             :         {
    1179             :             // the PC counters are -1
    1180          40 :             pFacToken = mpToken;
    1181          40 :             if ( eOp == ocIf )
    1182          40 :                 pFacToken->GetJump()[ 0 ] = 3;  // if, else, behind
    1183             :             else
    1184           0 :                 pFacToken->GetJump()[ 0 ] = MAXJUMPCOUNT+1;
    1185          40 :             eOp = NextToken();
    1186          40 :             if (eOp == ocOpen)
    1187             :             {
    1188          40 :                 NextToken();
    1189          40 :                 eOp = Expression();
    1190             :             }
    1191             :             else
    1192           0 :                 SetError(errPairExpected);
    1193          40 :             short nJumpCount = 0;
    1194          40 :             PutCode( pFacToken );
    1195             :             // during AutoCorrect (since pArr->GetCodeError() is
    1196             :             // ignored) an unlimited ocIf would crash because
    1197             :             // ScRawToken::Clone() allocates the JumpBuffer according to
    1198             :             // nJump[0]*2+2, which is 3*2+2 on ocIf.
    1199             :             const short nJumpMax =
    1200          40 :                 (pFacToken->GetOpCode() == ocIf ? 3 : MAXJUMPCOUNT);
    1201         192 :             while ( (nJumpCount < (MAXJUMPCOUNT - 1)) && (eOp == ocSep)
    1202          56 :                     && (!pArr->GetCodeError() || bIgnoreErrors) )
    1203             :             {
    1204          56 :                 if ( ++nJumpCount <= nJumpMax )
    1205          56 :                     pFacToken->GetJump()[nJumpCount] = pc-1;
    1206          56 :                 NextToken();
    1207          56 :                 eOp = Expression();
    1208             :                 // ocSep or ocClose terminate the subexpression
    1209          56 :                 PutCode( mpToken );
    1210             :             }
    1211          40 :             if (eOp != ocClose)
    1212           0 :                 SetError(errPairExpected);
    1213             :             else
    1214             :             {
    1215          40 :                 eOp = NextToken();
    1216             :                 // always limit to nJumpMax, no arbitrary overwrites
    1217          40 :                 if ( ++nJumpCount <= nJumpMax )
    1218          40 :                     pFacToken->GetJump()[ nJumpCount ] = pc-1;
    1219          40 :                 if ((pFacToken->GetOpCode() == ocIf && (nJumpCount > 3)) ||
    1220             :                                  (nJumpCount >= MAXJUMPCOUNT))
    1221           0 :                     SetError(errIllegalParameter);
    1222             :                 else
    1223          40 :                     pFacToken->GetJump()[ 0 ] = nJumpCount;
    1224          40 :             }
    1225             :         }
    1226         746 :         else if ( eOp == ocMissing )
    1227             :         {
    1228          12 :             PutCode( mpToken );
    1229          12 :             eOp = NextToken();
    1230             :         }
    1231         734 :         else if ( eOp == ocClose )
    1232             :         {
    1233           0 :             SetError( errParameterExpected );
    1234             :         }
    1235         734 :         else if ( eOp == ocSep )
    1236             :         {   // Subsequent ocSep
    1237           0 :             SetError( errParameterExpected );
    1238           0 :             if ( bAutoCorrect && !pStack )
    1239             :             {
    1240           0 :                 aCorrectedSymbol.Erase();
    1241           0 :                 bCorrected = true;
    1242             :             }
    1243             :         }
    1244         734 :         else if ( mpToken->IsExternalRef() )
    1245             :         {
    1246           0 :             PutCode(mpToken);
    1247           0 :             eOp = NextToken();
    1248             :         }
    1249             :         else
    1250             :         {
    1251         734 :             SetError( errUnknownToken );
    1252         734 :             if ( bAutoCorrect && !pStack )
    1253             :             {
    1254           0 :                 if ( eOp == ocStop )
    1255             :                 {   // trailing operator w/o operand
    1256           0 :                     xub_StrLen nLen = aCorrectedFormula.Len();
    1257           0 :                     if ( nLen )
    1258           0 :                         aCorrectedFormula.Erase( nLen - 1 );
    1259           0 :                     aCorrectedSymbol.Erase();
    1260           0 :                     bCorrected = true;
    1261             :                 }
    1262             :             }
    1263             :         }
    1264       33028 :     }
    1265             : }
    1266             : 
    1267             : //---------------------------------------------------------------------------
    1268             : 
    1269       33028 : void FormulaCompiler::RangeLine()
    1270             : {
    1271       33028 :     Factor();
    1272       66056 :     while (mpToken->GetOpCode() == ocRange)
    1273             :     {
    1274           0 :         FormulaToken** pCode1 = pCode - 1;
    1275           0 :         FormulaTokenRef p = mpToken;
    1276           0 :         NextToken();
    1277           0 :         Factor();
    1278           0 :         FormulaToken** pCode2 = pCode - 1;
    1279           0 :         if (!MergeRangeReference( pCode1, pCode2))
    1280           0 :             PutCode(p);
    1281           0 :     }
    1282       33028 : }
    1283             : 
    1284             : //---------------------------------------------------------------------------
    1285             : 
    1286       33028 : void FormulaCompiler::IntersectionLine()
    1287             : {
    1288       33028 :     RangeLine();
    1289       66056 :     while (mpToken->GetOpCode() == ocIntersect)
    1290             :     {
    1291           0 :         FormulaTokenRef p = mpToken;
    1292           0 :         NextToken();
    1293           0 :         RangeLine();
    1294           0 :         PutCode(p);
    1295           0 :     }
    1296       33028 : }
    1297             : 
    1298             : //---------------------------------------------------------------------------
    1299             : 
    1300       33028 : void FormulaCompiler::UnionLine()
    1301             : {
    1302       33028 :     IntersectionLine();
    1303       66056 :     while (mpToken->GetOpCode() == ocUnion)
    1304             :     {
    1305           0 :         FormulaTokenRef p = mpToken;
    1306           0 :         NextToken();
    1307           0 :         IntersectionLine();
    1308           0 :         PutCode(p);
    1309           0 :     }
    1310       33028 : }
    1311             : 
    1312             : //---------------------------------------------------------------------------
    1313             : 
    1314       33160 : void FormulaCompiler::UnaryLine()
    1315             : {
    1316       33160 :     if( mpToken->GetOpCode() == ocAdd )
    1317           0 :         GetToken();
    1318       40428 :     else if (SC_OPCODE_START_UN_OP <= mpToken->GetOpCode() &&
    1319        7268 :             mpToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
    1320             :     {
    1321         132 :         FormulaTokenRef p = mpToken;
    1322         132 :         NextToken();
    1323         132 :         UnaryLine();
    1324         132 :         PutCode( p );
    1325             :     }
    1326             :     else
    1327       33028 :         UnionLine();
    1328       33160 : }
    1329             : 
    1330             : //---------------------------------------------------------------------------
    1331             : 
    1332       33028 : void FormulaCompiler::PostOpLine()
    1333             : {
    1334       33028 :     UnaryLine();
    1335       66056 :     while ( mpToken->GetOpCode() == ocPercentSign )
    1336             :     {   // this operator _follows_ its operand
    1337           0 :         PutCode( mpToken );
    1338           0 :         NextToken();
    1339             :     }
    1340       33028 : }
    1341             : 
    1342             : //---------------------------------------------------------------------------
    1343             : 
    1344       33028 : void FormulaCompiler::PowLine()
    1345             : {
    1346       33028 :     PostOpLine();
    1347       66056 :     while (mpToken->GetOpCode() == ocPow)
    1348             :     {
    1349           0 :         FormulaTokenRef p = mpToken;
    1350           0 :         NextToken();
    1351           0 :         PostOpLine();
    1352           0 :         PutCode(p);
    1353           0 :     }
    1354       33028 : }
    1355             : 
    1356             : //---------------------------------------------------------------------------
    1357             : 
    1358       29630 : void FormulaCompiler::MulDivLine()
    1359             : {
    1360       29630 :     PowLine();
    1361       62658 :     while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv)
    1362             :     {
    1363        3398 :         FormulaTokenRef p = mpToken;
    1364        3398 :         NextToken();
    1365        3398 :         PowLine();
    1366        3398 :         PutCode(p);
    1367        3398 :     }
    1368       29630 : }
    1369             : 
    1370             : //---------------------------------------------------------------------------
    1371             : 
    1372       22568 : void FormulaCompiler::AddSubLine()
    1373             : {
    1374       22568 :     MulDivLine();
    1375       52198 :     while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub)
    1376             :     {
    1377        7062 :         FormulaTokenRef p = mpToken;
    1378        7062 :         NextToken();
    1379        7062 :         MulDivLine();
    1380        7062 :         PutCode(p);
    1381        7062 :     }
    1382       22568 : }
    1383             : 
    1384             : //---------------------------------------------------------------------------
    1385             : 
    1386       22568 : void FormulaCompiler::ConcatLine()
    1387             : {
    1388       22568 :     AddSubLine();
    1389       45136 :     while (mpToken->GetOpCode() == ocAmpersand)
    1390             :     {
    1391           0 :         FormulaTokenRef p = mpToken;
    1392           0 :         NextToken();
    1393           0 :         AddSubLine();
    1394           0 :         PutCode(p);
    1395           0 :     }
    1396       22568 : }
    1397             : 
    1398             : //---------------------------------------------------------------------------
    1399             : 
    1400       22528 : void FormulaCompiler::CompareLine()
    1401             : {
    1402       22528 :     ConcatLine();
    1403       45096 :     while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual)
    1404             :     {
    1405          40 :         FormulaTokenRef p = mpToken;
    1406          40 :         NextToken();
    1407          40 :         ConcatLine();
    1408          40 :         PutCode(p);
    1409          40 :     }
    1410       22528 : }
    1411             : 
    1412             : //---------------------------------------------------------------------------
    1413             : 
    1414       22528 : void FormulaCompiler::NotLine()
    1415             : {
    1416       22528 :     CompareLine();
    1417       45056 :     while (mpToken->GetOpCode() == ocNot)
    1418             :     {
    1419           0 :         FormulaTokenRef p = mpToken;
    1420           0 :         NextToken();
    1421           0 :         CompareLine();
    1422           0 :         PutCode(p);
    1423           0 :     }
    1424       22528 : }
    1425             : 
    1426             : //---------------------------------------------------------------------------
    1427             : 
    1428       22528 : OpCode FormulaCompiler::Expression()
    1429             : {
    1430             :     static const short nRecursionMax = 42;
    1431       22528 :     FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
    1432       22528 :     if ( nRecursion > nRecursionMax )
    1433             :     {
    1434           0 :         SetError( errStackOverflow );
    1435           0 :         return ocStop;      //! generate token instead?
    1436             :     }
    1437       22528 :     NotLine();
    1438       45056 :     while (mpToken->GetOpCode() == ocAnd || mpToken->GetOpCode() == ocOr)
    1439             :     {
    1440           0 :         FormulaTokenRef p = mpToken;
    1441           0 :         mpToken->SetByte( 2 );       // 2 parameters!
    1442           0 :         NextToken();
    1443           0 :         NotLine();
    1444           0 :         PutCode(p);
    1445           0 :     }
    1446       22528 :     return mpToken->GetOpCode();
    1447             : }
    1448             : // -----------------------------------------------------------------------------
    1449           0 : void FormulaCompiler::SetError(sal_uInt16 /*nError*/)
    1450             : {
    1451           0 : }
    1452             : // -----------------------------------------------------------------------------
    1453           0 : FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/, bool /*bReuseDoubleRef*/ )
    1454             : {
    1455           0 :     return FormulaTokenRef();
    1456             : }
    1457             : // -----------------------------------------------------------------------------
    1458           0 : bool FormulaCompiler::MergeRangeReference(FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
    1459             : {
    1460             :     FormulaToken *p1, *p2;
    1461           0 :     if (pc < 2 || !pCode1 || !pCode2 ||
    1462             :             (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
    1463             :             ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
    1464           0 :         return false;
    1465             : 
    1466           0 :     FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
    1467           0 :     if (!p)
    1468           0 :         return false;
    1469             : 
    1470           0 :     p->IncRef();
    1471           0 :     p1->DecRef();
    1472           0 :     p2->DecRef();
    1473           0 :     *pCode1 = p.get();
    1474           0 :     --pCode, --pc;
    1475           0 :     pArr->nRefs--;
    1476             : 
    1477           0 :     return true;
    1478             : }
    1479             : // -----------------------------------------------------------------------------
    1480        7068 : bool FormulaCompiler::CompileTokenArray()
    1481             : {
    1482        7068 :     glSubTotal = false;
    1483        7068 :     bCorrected = false;
    1484        7068 :     if( !pArr->GetCodeError() || bIgnoreErrors )
    1485             :     {
    1486        7068 :         if ( bAutoCorrect )
    1487             :         {
    1488           0 :             aCorrectedFormula.Erase();
    1489           0 :             aCorrectedSymbol.Erase();
    1490             :         }
    1491        7068 :         pArr->nRefs = 0;    // count from start
    1492        7068 :         pArr->DelRPN();
    1493        7068 :         pStack = NULL;
    1494             :         FormulaToken* pData[ MAXCODE ];
    1495        7068 :         pCode = pData;
    1496        7068 :         bool bWasForced = pArr->IsRecalcModeForced();
    1497        7068 :         if ( bWasForced )
    1498             :         {
    1499           0 :             if ( bAutoCorrect )
    1500           0 :                 aCorrectedFormula = '=';
    1501             :         }
    1502        7068 :         pArr->ClearRecalcMode();
    1503        7068 :         pArr->Reset();
    1504        7068 :         eLastOp = ocOpen;
    1505        7068 :         pc = 0;
    1506        7068 :         NextToken();
    1507        7068 :         OpCode eOp = Expression();
    1508             :         // Some trailing garbage that doesn't form an expression?
    1509        7068 :         if (eOp != ocStop)
    1510         734 :             SetError( errOperatorExpected);
    1511             : 
    1512        7068 :         sal_uInt16 nErrorBeforePop = pArr->GetCodeError();
    1513             : 
    1514       14136 :         while( pStack )
    1515           0 :             PopTokenArray();
    1516        7068 :         if( pc )
    1517             :         {
    1518        6334 :             pArr->pRPN = new FormulaToken*[ pc ];
    1519        6334 :             pArr->nRPN = pc;
    1520        6334 :             memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
    1521             :         }
    1522             : 
    1523             :         // once an error, always an error
    1524        7068 :         if( !pArr->GetCodeError() && nErrorBeforePop )
    1525           0 :             pArr->SetCodeError( nErrorBeforePop);
    1526             : 
    1527        7068 :         if( pArr->GetCodeError() && !bIgnoreErrors )
    1528             :         {
    1529         734 :             pArr->DelRPN();
    1530         734 :             pArr->SetHyperLink(false);
    1531             :         }
    1532             : 
    1533        7068 :         if ( bWasForced )
    1534           0 :             pArr->SetRecalcModeForced();
    1535             :     }
    1536        7068 :     if( nNumFmt == NUMBERFORMAT_UNDEFINED )
    1537        3532 :         nNumFmt = NUMBERFORMAT_NUMBER;
    1538        7068 :     return glSubTotal;
    1539             : }
    1540             : // -----------------------------------------------------------------------------
    1541         362 : void FormulaCompiler::PopTokenArray()
    1542             : {
    1543         362 :     if( pStack )
    1544             :     {
    1545         362 :         FormulaArrayStack* p = pStack;
    1546         362 :         pStack = p->pNext;
    1547         362 :         p->pArr->nRefs = sal::static_int_cast<short>( p->pArr->nRefs + pArr->nRefs );
    1548             :         // obtain special RecalcMode from SharedFormula
    1549         362 :         if ( pArr->IsRecalcModeAlways() )
    1550           0 :             p->pArr->SetRecalcModeAlways();
    1551         362 :         else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
    1552           0 :             p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
    1553         362 :         p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
    1554         362 :         if( p->bTemp )
    1555         362 :             delete pArr;
    1556         362 :         pArr = p->pArr;
    1557         362 :         delete p;
    1558             :     }
    1559         362 : }
    1560             : // -----------------------------------------------------------------------------
    1561          48 : void FormulaCompiler::CreateStringFromTokenArray( String& rFormula )
    1562             : {
    1563          48 :     rtl::OUStringBuffer aBuffer( pArr->GetLen() * 5 );
    1564          48 :     CreateStringFromTokenArray( aBuffer );
    1565          48 :     rFormula = aBuffer.makeStringAndClear();
    1566          48 : }
    1567             : 
    1568         348 : void FormulaCompiler::CreateStringFromTokenArray( rtl::OUStringBuffer& rBuffer )
    1569             : {
    1570         348 :     rBuffer.setLength(0);
    1571         348 :     if( !pArr->GetLen() )
    1572         348 :         return;
    1573             : 
    1574         348 :     FormulaTokenArray* pSaveArr = pArr;
    1575         348 :     bool bODFF = FormulaGrammar::isODFF( meGrammar);
    1576         348 :     if (bODFF || FormulaGrammar::isPODF( meGrammar) )
    1577             :     {
    1578             :         // Scan token array for missing args and re-write if present.
    1579          82 :         MissingConvention aConv( bODFF);
    1580          82 :         if (pArr->NeedsPofRewrite( aConv))
    1581           0 :             pArr = pArr->RewriteMissingToPof( aConv);
    1582             :     }
    1583             : 
    1584             :     // At least one character per token, plus some are references, some are
    1585             :     // function names, some are numbers, ...
    1586         348 :     rBuffer.ensureCapacity( pArr->GetLen() * 5 );
    1587             : 
    1588         348 :     if ( pArr->IsRecalcModeForced() )
    1589           0 :         rBuffer.append(sal_Unicode('='));
    1590         348 :     FormulaToken* t = pArr->First();
    1591        1212 :     while( t )
    1592         516 :         t = CreateStringFromToken( rBuffer, t, true );
    1593             : 
    1594         348 :     if (pSaveArr != pArr)
    1595             :     {
    1596           0 :         delete pArr;
    1597           0 :         pArr = pSaveArr;
    1598             :     }
    1599             : }
    1600             : // -----------------------------------------------------------------------------
    1601         164 : FormulaToken* FormulaCompiler::CreateStringFromToken( String& rFormula, FormulaToken* pTokenP,bool bAllowArrAdvance )
    1602             : {
    1603         164 :     rtl::OUStringBuffer aBuffer;
    1604         164 :     FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
    1605         164 :     rFormula += aBuffer.makeStringAndClear();
    1606         164 :     return p;
    1607             : }
    1608             : 
    1609         680 : FormulaToken* FormulaCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP,bool bAllowArrAdvance )
    1610             : {
    1611         680 :     bool bNext = true;
    1612         680 :     bool bSpaces = false;
    1613         680 :     FormulaToken* t = pTokenP;
    1614         680 :     OpCode eOp = t->GetOpCode();
    1615         680 :     if( eOp >= ocAnd && eOp <= ocOr )
    1616             :     {
    1617             :         // AND, OR infix?
    1618           0 :         if ( bAllowArrAdvance )
    1619           0 :             t = pArr->Next();
    1620             :         else
    1621           0 :             t = pArr->PeekNext();
    1622           0 :         bNext = false;
    1623           0 :         bSpaces = ( !t || t->GetOpCode() != ocOpen );
    1624             :     }
    1625         680 :     if( bSpaces )
    1626           0 :         rBuffer.append(sal_Unicode(' '));
    1627             : 
    1628         680 :     if( eOp == ocSpaces )
    1629             :     {
    1630           0 :         bool bIntersectionOp = mxSymbols->isODFF();
    1631           0 :         if (bIntersectionOp)
    1632             :         {
    1633           0 :             const FormulaToken* p = pArr->PeekPrevNoSpaces();
    1634           0 :             bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
    1635           0 :             if (bIntersectionOp)
    1636             :             {
    1637           0 :                 p = pArr->PeekNextNoSpaces();
    1638           0 :                 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
    1639             :             }
    1640             :         }
    1641           0 :         if (bIntersectionOp)
    1642           0 :             rBuffer.appendAscii( "!!");
    1643             :         else
    1644             :         {
    1645             :             // most times it's just one blank
    1646           0 :             sal_uInt8 n = t->GetByte();
    1647           0 :             for ( sal_uInt8 j=0; j<n; ++j )
    1648             :             {
    1649           0 :                 rBuffer.append(sal_Unicode(' '));
    1650             :             }
    1651             :         }
    1652             :     }
    1653         680 :     else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
    1654           0 :         rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
    1655         680 :     else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount())        // Keyword:
    1656         680 :         rBuffer.append(mxSymbols->getSymbol(eOp));
    1657             :     else
    1658             :     {
    1659             :         SAL_WARN( "formula.core","unknown OpCode");
    1660           0 :         rBuffer.append(GetNativeSymbol( ocErrName ));
    1661             :     }
    1662         680 :     if( bNext )
    1663             :     {
    1664         680 :         if (t->IsExternalRef())
    1665             :         {
    1666           8 :             CreateStringFromExternal(rBuffer, pTokenP);
    1667             :         }
    1668             :         else
    1669             :         {
    1670         672 :             switch( t->GetType() )
    1671             :             {
    1672             :             case svDouble:
    1673          20 :                 AppendDouble( rBuffer, t->GetDouble() );
    1674          20 :             break;
    1675             : 
    1676             :             case svString:
    1677          42 :                 if( eOp == ocBad || eOp == ocStringXML )
    1678          36 :                     rBuffer.append(t->GetString());
    1679             :                 else
    1680           6 :                     AppendString( rBuffer, t->GetString() );
    1681          42 :                 break;
    1682             :             case svSingleRef:
    1683         296 :                 CreateStringFromSingleRef(rBuffer,t);
    1684         296 :                 break;
    1685             :             case svDoubleRef:
    1686         188 :                 CreateStringFromDoubleRef(rBuffer,t);
    1687         188 :                 break;
    1688             :             case svMatrix:
    1689           0 :                 CreateStringFromMatrix( rBuffer, t );
    1690           0 :                 break;
    1691             : 
    1692             :             case svIndex:
    1693          12 :                 CreateStringFromIndex( rBuffer, t );
    1694          12 :                 break;
    1695             :             case svExternal:
    1696             :             {
    1697             :                 // mapped or translated name of AddIns
    1698           0 :                 String aAddIn( t->GetExternal() );
    1699           0 :                 bool bMapped = mxSymbols->isPODF();     // ODF 1.1 directly uses programmatical name
    1700           0 :                 if (!bMapped && mxSymbols->hasExternals())
    1701             :                 {
    1702           0 :                     ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
    1703           0 :                     if (iLook != mxSymbols->getReverseExternalHashMap()->end())
    1704             :                     {
    1705           0 :                         aAddIn = (*iLook).second;
    1706           0 :                         bMapped = true;
    1707             :                     }
    1708             :                 }
    1709           0 :                 if (!bMapped && !mxSymbols->isEnglish())
    1710           0 :                         LocalizeString( aAddIn );
    1711           0 :                     rBuffer.append(aAddIn);
    1712             :                 }
    1713           0 :             break;
    1714             :             case svError:
    1715           0 :                 AppendErrorConstant( rBuffer, t->GetError());
    1716           0 :             break;
    1717             :             case svByte:
    1718             :             case svJump:
    1719             :             case svFAP:
    1720             :             case svMissing:
    1721             :             case svSep:
    1722         114 :                 break;      // Opcodes
    1723             :             default:
    1724             :                 OSL_FAIL("FormulaCompiler:: GetStringFromToken errUnknownVariable");
    1725             :             } // of switch
    1726             :         }
    1727             :     }
    1728         680 :     if( bSpaces )
    1729           0 :         rBuffer.append(sal_Unicode(' '));
    1730         680 :     if ( bAllowArrAdvance )
    1731             :     {
    1732         516 :         if( bNext )
    1733         516 :             t = pArr->Next();
    1734         516 :         return t;
    1735             :     }
    1736         164 :     return pTokenP;
    1737             : }
    1738             : // -----------------------------------------------------------------------------
    1739             : 
    1740          20 : void FormulaCompiler::AppendDouble( rtl::OUStringBuffer& rBuffer, double fVal )
    1741             : {
    1742          20 :     if ( mxSymbols->isEnglish() )
    1743             :     {
    1744             :         ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
    1745             :                 rtl_math_StringFormat_Automatic,
    1746           8 :                 rtl_math_DecimalPlaces_Max, '.', true );
    1747             :     }
    1748             :     else
    1749             :     {
    1750          12 :         SvtSysLocale aSysLocale;
    1751             :         ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
    1752             :                 rtl_math_StringFormat_Automatic,
    1753             :                 rtl_math_DecimalPlaces_Max,
    1754          12 :                 aSysLocale.GetLocaleDataPtr()->getNumDecimalSep()[0],
    1755          12 :                 true );
    1756             :     }
    1757          20 : }
    1758             : // -----------------------------------------------------------------------------
    1759           0 : void FormulaCompiler::AppendBoolean( rtl::OUStringBuffer& rBuffer, bool bVal )
    1760             : {
    1761           0 :     rBuffer.append( mxSymbols->getSymbol(static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
    1762           0 : }
    1763             : // -----------------------------------------------------------------------------
    1764           6 : void FormulaCompiler::AppendString( rtl::OUStringBuffer& rBuffer, const String & rStr )
    1765             : {
    1766           6 :     rBuffer.append(sal_Unicode('"'));
    1767           6 :     if ( lcl_UnicodeStrChr( rStr.GetBuffer(), '"' ) == NULL )
    1768           6 :         rBuffer.append( rStr );
    1769             :     else
    1770             :     {
    1771           0 :         String aStr( rStr );
    1772           0 :         aStr.SearchAndReplaceAll( rtl::OUString('"'), rtl::OUString("\"\"") );
    1773           0 :         rBuffer.append(aStr);
    1774             :     }
    1775           6 :     rBuffer.append(sal_Unicode('"'));
    1776           6 : }
    1777             : 
    1778         172 : void FormulaCompiler::UpdateSeparatorsNative(
    1779             :     const rtl::OUString& rSep, const rtl::OUString& rArrayColSep, const rtl::OUString& rArrayRowSep )
    1780             : {
    1781         172 :     NonConstOpCodeMapPtr xSymbolsNative;
    1782         172 :     lcl_fillNativeSymbols(xSymbolsNative);
    1783         172 :     xSymbolsNative->putOpCode(rSep, ocSep);
    1784         172 :     xSymbolsNative->putOpCode(rArrayColSep, ocArrayColSep);
    1785         172 :     xSymbolsNative->putOpCode(rArrayRowSep, ocArrayRowSep);
    1786         172 : }
    1787             : 
    1788         172 : void FormulaCompiler::ResetNativeSymbols()
    1789             : {
    1790         172 :     NonConstOpCodeMapPtr xSymbolsNative;
    1791         172 :     lcl_fillNativeSymbols(xSymbolsNative, true);
    1792         172 :     lcl_fillNativeSymbols(xSymbolsNative);
    1793         172 : }
    1794             : 
    1795           0 : void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr& xMap )
    1796             : {
    1797           0 :     NonConstOpCodeMapPtr xSymbolsNative;
    1798           0 :     lcl_fillNativeSymbols(xSymbolsNative);
    1799           0 :     xSymbolsNative->copyFrom(*xMap);
    1800           0 : }
    1801             : 
    1802             : // -----------------------------------------------------------------------------
    1803       72800 : OpCode FormulaCompiler::NextToken()
    1804             : {
    1805       72800 :     if( !GetToken() )
    1806        6332 :         return ocStop;
    1807       66468 :     OpCode eOp = mpToken->GetOpCode();
    1808             :     // There must be an operator before a push
    1809       89392 :     if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
    1810             :             !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
    1811       34400 :                 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
    1812           0 :         SetError(errOperatorExpected);
    1813             :     // Operator and Plus => operator
    1814       66468 :     if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
    1815             :                 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
    1816           0 :         eOp = NextToken();
    1817             :     else
    1818             :     {
    1819             :         // Before an operator there must not be another operator, with the
    1820             :         // exception of AND and OR.
    1821       66468 :         if ( eOp != ocAnd && eOp != ocOr &&
    1822             :                 (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP )
    1823             :                 && (eLastOp == ocOpen || eLastOp == ocSep ||
    1824             :                     (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
    1825             :         {
    1826           0 :             SetError(errVariableExpected);
    1827           0 :             if ( bAutoCorrect && !pStack )
    1828             :             {
    1829           0 :                 if ( eOp == eLastOp || eLastOp == ocOpen )
    1830             :                 {   // throw away duplicated operator
    1831           0 :                     aCorrectedSymbol.Erase();
    1832           0 :                     bCorrected = true;
    1833             :                 }
    1834             :                 else
    1835             :                 {
    1836           0 :                     xub_StrLen nPos = aCorrectedFormula.Len();
    1837           0 :                     if ( nPos )
    1838             :                     {
    1839           0 :                         nPos--;
    1840           0 :                         sal_Unicode c = aCorrectedFormula.GetChar( nPos );
    1841           0 :                         switch ( eOp )
    1842             :                         {   // swap operators
    1843             :                             case ocGreater:
    1844           0 :                                 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
    1845             :                                 {   // >= instead of =>
    1846             :                                     aCorrectedFormula.SetChar( nPos,
    1847           0 :                                         mxSymbols->getSymbol(ocGreater).GetChar(0) );
    1848           0 :                                     aCorrectedSymbol = c;
    1849           0 :                                     bCorrected = true;
    1850             :                                 }
    1851           0 :                             break;
    1852             :                             case ocLess:
    1853           0 :                                 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
    1854             :                                 {   // <= instead of =<
    1855             :                                     aCorrectedFormula.SetChar( nPos,
    1856           0 :                                         mxSymbols->getSymbol(ocLess).GetChar(0) );
    1857           0 :                                     aCorrectedSymbol = c;
    1858           0 :                                     bCorrected = true;
    1859             :                                 }
    1860           0 :                                 else if ( c == mxSymbols->getSymbol(ocGreater).GetChar(0) )
    1861             :                                 {   // <> instead of ><
    1862             :                                     aCorrectedFormula.SetChar( nPos,
    1863           0 :                                         mxSymbols->getSymbol(ocLess).GetChar(0) );
    1864           0 :                                     aCorrectedSymbol = c;
    1865           0 :                                     bCorrected = true;
    1866             :                                 }
    1867           0 :                             break;
    1868             :                             case ocMul:
    1869           0 :                                 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
    1870             :                                 {   // *- instead of -*
    1871             :                                     aCorrectedFormula.SetChar( nPos,
    1872           0 :                                         mxSymbols->getSymbol(ocMul).GetChar(0) );
    1873           0 :                                     aCorrectedSymbol = c;
    1874           0 :                                     bCorrected = true;
    1875             :                                 }
    1876           0 :                             break;
    1877             :                             case ocDiv:
    1878           0 :                                 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
    1879             :                                 {   // /- instead of -/
    1880             :                                     aCorrectedFormula.SetChar( nPos,
    1881           0 :                                         mxSymbols->getSymbol(ocDiv).GetChar(0) );
    1882           0 :                                     aCorrectedSymbol = c;
    1883           0 :                                     bCorrected = true;
    1884             :                                 }
    1885           0 :                             break;
    1886             :                             default:
    1887             :                                 ;   // nothing
    1888             :                         }
    1889             :                     }
    1890             :                 }
    1891             :             }
    1892             :         }
    1893       66468 :         eLastOp = eOp;
    1894             :     }
    1895       66468 :     return eOp;
    1896             : }
    1897       40994 : void FormulaCompiler::PutCode( FormulaTokenRef& p )
    1898             : {
    1899       40994 :     if( pc >= MAXCODE-1 )
    1900             :     {
    1901           0 :         if ( pc == MAXCODE-1 )
    1902             :         {
    1903           0 :             p = new FormulaByteToken( ocStop );
    1904           0 :             p->IncRef();
    1905           0 :             *pCode++ = p.get();
    1906           0 :             ++pc;
    1907             :         }
    1908           0 :         SetError(errCodeOverflow);
    1909           0 :         return;
    1910             :     }
    1911       40994 :     if( pArr->GetCodeError() && !bCompileForFAP )
    1912           0 :         return;
    1913       40994 :     ForceArrayOperator( p, pCurrentFactorToken);
    1914       40994 :     p->IncRef();
    1915       40994 :     *pCode++ = p.get();
    1916       40994 :     pc++;
    1917             : }
    1918             : 
    1919             : // -----------------------------------------------------------------------------
    1920           0 : bool FormulaCompiler::HandleExternalReference(const FormulaToken& /*_aToken*/)
    1921             : {
    1922           0 :     return true;
    1923             : }
    1924             : // -----------------------------------------------------------------------------
    1925           0 : bool FormulaCompiler::HandleRange()
    1926             : {
    1927           0 :     return true;
    1928             : }
    1929             : // -----------------------------------------------------------------------------
    1930           0 : bool FormulaCompiler::HandleSingleRef()
    1931             : {
    1932           0 :     return true;
    1933             : }
    1934             : // -----------------------------------------------------------------------------
    1935           0 : bool FormulaCompiler::HandleDbData()
    1936             : {
    1937           0 :     return true;
    1938             : }
    1939             : // -----------------------------------------------------------------------------
    1940           0 : void FormulaCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1941             : {
    1942           0 : }
    1943             : // -----------------------------------------------------------------------------
    1944           0 : void FormulaCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1945             : {
    1946           0 : }
    1947             : // -----------------------------------------------------------------------------
    1948           0 : void FormulaCompiler::CreateStringFromIndex(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1949             : {
    1950           0 : }
    1951             : // -----------------------------------------------------------------------------
    1952           0 : void FormulaCompiler::CreateStringFromMatrix(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1953             : {
    1954           0 : }
    1955             : // -----------------------------------------------------------------------------
    1956           0 : void FormulaCompiler::CreateStringFromExternal(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1957             : {
    1958           0 : }
    1959             : // -----------------------------------------------------------------------------
    1960           0 : void FormulaCompiler::LocalizeString( String& /*rName*/ )
    1961             : {
    1962           0 : }
    1963         362 : void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
    1964             : {
    1965         362 :     if ( bAutoCorrect && !pStack )
    1966             :         {   // don't merge stacked subroutine code into entered formula
    1967           0 :         aCorrectedFormula += aCorrectedSymbol;
    1968           0 :         aCorrectedSymbol.Erase();
    1969             :     }
    1970         362 :     FormulaArrayStack* p = new FormulaArrayStack;
    1971         362 :     p->pNext      = pStack;
    1972         362 :     p->pArr       = pArr;
    1973         362 :     p->bTemp      = bTemp;
    1974         362 :     pStack        = p;
    1975         362 :     pArr          = pa;
    1976         362 : }
    1977             : 
    1978             : // =============================================================================
    1979             : } // formula
    1980             : // =============================================================================
    1981             : 
    1982             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10