LCOV - code coverage report
Current view: top level - formula/source/core/api - FormulaCompiler.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 612 975 62.8 %
Date: 2012-08-25 Functions: 59 87 67.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 645 1599 40.3 %

           Branch data     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                 :      95245 :                                 FormulaCompilerRecursionGuard( short& rRec )
      54                 :      95245 :                                     : rRecursion( rRec ) { ++rRecursion; }
      55                 :      95245 :                                 ~FormulaCompilerRecursionGuard() { --rRecursion; }
      56                 :            : };
      57                 :            : 
      58                 :       4170 : short lcl_GetRetFormat( OpCode eOpCode )
      59                 :            : {
      60   [ +  -  +  -  :       4170 :     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                 :        366 :             return NUMBERFORMAT_LOGICAL;
      88                 :            :         case ocGetActDate:
      89                 :            :         case ocGetDate:
      90                 :            :         case ocEasterSunday :
      91                 :          0 :             return NUMBERFORMAT_DATE;
      92                 :            :         case ocGetActTime:
      93                 :          3 :             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                 :       4170 :             return NUMBERFORMAT_NUMBER;
     120                 :            :     }
     121                 :            : }
     122                 :            : 
     123                 :       7704 : inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, sal_uInt16 nOpCode )
     124                 :            : {
     125                 :       7704 :     sheet::FormulaOpCodeMapEntry aEntry;
     126                 :       7704 :     aEntry.Token.OpCode = nOpCode;
     127         [ +  - ]:       7704 :     aEntry.Name = pTable[nOpCode];
     128         [ +  - ]:       7704 :     rVec.push_back( aEntry);
     129                 :       7704 : }
     130                 :            : 
     131                 :         48 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, sal_uInt16 nOpCodeBeg, sal_uInt16 nOpCodeEnd )
     132                 :            : {
     133         [ +  + ]:       2208 :     for (sal_uInt16 nOpCode = nOpCodeBeg; nOpCode < nOpCodeEnd; ++nOpCode)
     134                 :       2160 :         lclPushOpCodeMapEntry( rVec, pTable, nOpCode );
     135                 :         48 : }
     136                 :            : 
     137                 :         72 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec, const String* pTable, const sal_uInt16* pnOpCodes, size_t nCount )
     138                 :            : {
     139         [ +  + ]:        384 :     for (const sal_uInt16* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes)
     140                 :        312 :         lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes );
     141                 :         72 : }
     142                 :            : 
     143                 :        444 : 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                 :        444 : OpCodeList::OpCodeList( sal_uInt16 nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap ) :
     163                 :        444 :     Resource( ResId(nRID,*ResourceManager::getResManager()) )
     164         [ +  - ]:        444 :     ,meSepType(SEMICOLON_BASE)
     165                 :            : {
     166         [ +  + ]:     179376 :      for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
     167                 :            :     {
     168         [ +  - ]:     178932 :         String aOpStr;
     169 [ +  - ][ +  + ]:     178932 :         if ( getOpCodeString(aOpStr, i) )
     170         [ +  - ]:       1332 :             xMap->putOpCode(aOpStr, OpCode(i));
     171                 :            :         else
     172 [ +  - ][ +  - ]:     177600 :             putDefaultOpCode(xMap, i);
                 [ +  - ]
     173         [ +  - ]:     178932 :     }
     174                 :            : 
     175         [ +  - ]:        444 :     FreeResource();
     176                 :        444 : }
     177                 :            : 
     178                 :     178932 : bool OpCodeList::getOpCodeString( String& rStr, sal_uInt16 nOp )
     179                 :            : {
     180   [ +  +  +  + ]:     178932 :     switch (nOp)
     181                 :            :     {
     182                 :            :         case SC_OPCODE_SEP:
     183                 :            :         {
     184         [ -  + ]:        444 :             if (meSepType == COMMA_BASE)
     185                 :            :             {
     186         [ #  # ]:          0 :                 rStr = rtl::OUString(",");
     187                 :          0 :                 return true;
     188                 :            :             }
     189         [ +  - ]:        444 :             else if (meSepType == SEMICOLON_BASE)
     190                 :            :             {
     191         [ +  - ]:        444 :                 rStr = rtl::OUString(";");
     192                 :        444 :                 return true;
     193                 :            :             }
     194                 :            :         }
     195                 :          0 :         break;
     196                 :            :         case SC_OPCODE_ARRAY_COL_SEP:
     197                 :            :         {
     198         [ -  + ]:        444 :             if (meSepType == COMMA_BASE)
     199                 :            :             {
     200         [ #  # ]:          0 :                 rStr = rtl::OUString(",");
     201                 :          0 :                 return true;
     202                 :            :             }
     203         [ +  - ]:        444 :             else if (meSepType == SEMICOLON_BASE)
     204                 :            :             {
     205         [ +  - ]:        444 :                 rStr = rtl::OUString(";");
     206                 :        444 :                 return true;
     207                 :            :             }
     208                 :            :         }
     209                 :          0 :         break;
     210                 :            :         case SC_OPCODE_ARRAY_ROW_SEP:
     211                 :            :         {
     212         [ -  + ]:        444 :             if (meSepType == COMMA_BASE)
     213                 :            :             {
     214         [ #  # ]:          0 :                 rStr = rtl::OUString(";");
     215                 :          0 :                 return true;
     216                 :            :             }
     217         [ +  - ]:        444 :             else if (meSepType == SEMICOLON_BASE)
     218                 :            :             {
     219         [ +  - ]:        444 :                 rStr = rtl::OUString("|");
     220                 :        444 :                 return true;
     221                 :            :             }
     222                 :            :         }
     223                 :          0 :         break;
     224                 :            :     }
     225                 :            : 
     226                 :     178932 :     return false;
     227                 :            : }
     228                 :            : 
     229                 :     177600 : void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp )
     230                 :            : {
     231         [ +  - ]:     177600 :     ResId aRes(nOp,*ResourceManager::getResManager());
     232                 :     177600 :     aRes.SetRT(RSC_STRING);
     233 [ +  + ][ +  - ]:     177600 :     if (IsAvailableRes(aRes))
     234 [ +  - ][ +  - ]:     143397 :         xMap->putOpCode(aRes, OpCode(nOp));
                 [ +  - ]
     235                 :     177600 : }
     236                 :            : // -----------------------------------------------------------------------------
     237                 :            : // static
     238                 :          9 : const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,sal_Unicode c )
     239                 :            : {
     240         [ -  + ]:          9 :     if ( !pStr )
     241                 :          0 :         return NULL;
     242         [ +  + ]:         36 :     while ( *pStr )
     243                 :            :     {
     244         [ -  + ]:         27 :         if ( *pStr == c )
     245                 :          0 :             return pStr;
     246                 :         27 :         pStr++;
     247                 :            :     }
     248                 :          9 :     return NULL;
     249                 :            : }
     250                 :            : // =============================================================================
     251                 :            : } // empty
     252                 :            : // =============================================================================
     253                 :            : 
     254                 :       5393 : void FormulaCompiler::OpCodeMap::putExternal( const String & rSymbol, const String & rAddIn )
     255                 :            : {
     256         [ +  - ]:       5393 :     bool bOk = mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn)).second;
     257         [ +  - ]:       5393 :     if (bOk)
     258         [ +  - ]:       5393 :         bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
     259                 :            :     DBG_ASSERT( bOk, "OpCodeMap::putExternal: symbol not inserted");
     260                 :       5393 : }
     261                 :            : 
     262                 :       1308 : void FormulaCompiler::OpCodeMap::putExternalSoftly( const String & rSymbol, const String & rAddIn )
     263                 :            : {
     264         [ +  - ]:       1308 :     bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
     265         [ -  + ]:       1308 :     if (bOk)
     266         [ #  # ]:          0 :         mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn));
     267                 :       1308 : }
     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                 :        144 : 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         [ +  - ]:        144 :     ::std::vector< FormulaOpCodeMapEntry > aVec;
     312                 :            : 
     313         [ +  + ]:        144 :     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                 :         24 :         const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
     337                 :            :         // Preallocate vector elements.
     338         [ +  - ]:         24 :         if (aVec.size() < nCount)
     339                 :            :         {
     340                 :         24 :             FormulaOpCodeMapEntry aEntry;
     341         [ +  - ]:         24 :             aEntry.Token.OpCode = getOpCodeUnknown();
     342         [ +  - ]:         24 :             aVec.resize( nCount, aEntry);
     343                 :            :         } // if (aVec.size() < nCount)
     344                 :            : 
     345                 :         24 :         FormulaOpCodeMapEntry aEntry;
     346         [ +  + ]:        336 :         for (size_t i=0; i < nCount; ++i)
     347                 :            :         {
     348                 :        312 :             size_t nIndex = static_cast< size_t >( aMap[i].nOff );
     349         [ -  + ]:        312 :             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                 :        312 :             aEntry.Token.OpCode = aMap[i].eOp;
     359                 :        312 :             aVec[nIndex] = aEntry;
     360                 :         24 :         }
     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         [ +  + ]:        120 :         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         [ +  - ]:         24 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     377                 :            :         }
     378         [ +  + ]:        120 :         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         [ +  - ]:         24 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     387                 :            :         }
     388         [ +  + ]:        120 :         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         [ +  - ]:         24 :             lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
     393                 :            :             // "+" can be used as unary operator too, push only if binary group is not set
     394         [ +  - ]:         24 :             if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
     395         [ +  - ]:         24 :                 lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
     396                 :            :             // regular unary operators
     397 [ +  + ][ +  - ]:         96 :             for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
                 [ +  + ]
     398                 :            :             {
     399         [ +  + ]:         72 :                 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                 :         48 :                         break;   // nothing,
     406                 :            :                     default:
     407         [ +  - ]:         24 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     408                 :            :                 }
     409                 :            :             }
     410                 :            :         }
     411         [ +  + ]:        120 :         if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
     412                 :            :         {
     413 [ +  + ][ +  - ]:        432 :             for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
                 [ +  + ]
     414                 :            :             {
     415         [ +  + ]:        408 :                 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                 :         48 :                         break;   // nothing,
     422                 :            :                     default:
     423         [ +  - ]:        360 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     424                 :            :                 }
     425                 :            :             }
     426                 :            :         }
     427         [ +  + ]:        120 :         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 [ +  - ][ +  - ]:         24 :             lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_NO_PAR, ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
     432 [ +  - ][ +  - ]:         24 :             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         [ +  - ]:         24 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     443                 :            :             // functions with 2 or more parameters.
     444 [ +  + ][ +  - ]:       4848 :             for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
                 [ +  + ]
     445                 :            :             {
     446         [ +  + ]:       4824 :                 switch (nOp)
     447                 :            :                 {
     448                 :            :                     // NO_NAME is in SPECIAL.
     449                 :            :                     case SC_OPCODE_NO_NAME :
     450                 :         24 :                         break;   // nothing,
     451                 :            :                     default:
     452         [ +  - ]:       4800 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     453                 :            :                 }
     454                 :            :             }
     455                 :            :             // If AddIn functions are present in this mapping, use them, and only those.
     456 [ +  - ][ +  - ]:         24 :             if (hasExternals())
     457                 :            :             {
     458 [ +  - ][ +  - ]:       2640 :                 for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
                 [ +  + ]
     459                 :            :                 {
     460                 :       2616 :                     FormulaOpCodeMapEntry aEntry;
     461 [ +  - ][ +  - ]:       2616 :                     aEntry.Name = (*it).first;
     462 [ +  - ][ +  - ]:       2616 :                     aEntry.Token.Data <<= ::rtl::OUString( (*it).second);
                 [ +  - ]
     463                 :       2616 :                     aEntry.Token.OpCode = ocExternal;
     464         [ +  - ]:       2616 :                     aVec.push_back( aEntry);
     465                 :       2616 :                 }
     466                 :            :             }
     467                 :            :             else
     468                 :            :             {
     469         [ #  # ]:          0 :                 _rCompiler.fillAddInToken(aVec,isEnglish());
     470                 :            :             }
     471                 :            :         }
     472                 :            :     }
     473         [ -  + ]:        144 :     const FormulaOpCodeMapEntry* pRet = aVec.empty() ? 0 : &aVec[0];
     474         [ +  - ]:        144 :     return uno::Sequence< FormulaOpCodeMapEntry >(pRet, aVec.size());
     475                 :            : }
     476                 :            : //-----------------------------------------------------------------------------
     477                 :            : 
     478                 :     152493 : 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 [ +  - ][ +  - ]:     152493 :     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                 :     152493 :         mpTable[eOp] = rStr;
     492         [ +  - ]:     152493 :         mpHashMap->insert( OpCodeHashMap::value_type( rStr, eOp));
     493                 :            :     }
     494                 :     152493 : }
     495                 :            : // -----------------------------------------------------------------------------
     496                 :            : // class FormulaCompiler
     497                 :            : // -----------------------------------------------------------------------------
     498                 :            : DBG_NAME(FormulaCompiler)
     499                 :       5336 : 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 [ +  - ][ +  - ]:       5336 :         bIgnoreErrors( false )
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     511                 :            : 
     512                 :            : {
     513                 :            :     DBG_CTOR(FormulaCompiler,NULL);
     514                 :       5336 : }
     515                 :      28025 : 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 [ +  - ][ +  - ]:      28025 :         bIgnoreErrors( false )
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     527                 :            : 
     528                 :            : {
     529                 :            :     DBG_CTOR(FormulaCompiler,NULL);
     530                 :      28025 : }
     531 [ +  - ][ +  - ]:      33361 : FormulaCompiler::~FormulaCompiler()
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     532                 :            : {
     533                 :            :     DBG_DTOR(FormulaCompiler,NULL);
     534         [ -  + ]:      33361 : }
     535                 :            : 
     536                 :      33505 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
     537                 :            : {
     538                 :      33505 :     FormulaCompiler::OpCodeMapPtr xMap;
     539                 :            :     using namespace sheet;
     540   [ +  +  +  +  :      33505 :     switch (nLanguage)
                   -  - ]
     541                 :            :     {
     542                 :            :         case FormulaLanguage::ODFF :
     543         [ +  + ]:       2775 :             if (!mxSymbolsODFF)
     544         [ +  - ]:       2655 :                 InitSymbolsODFF();
     545         [ +  - ]:       2775 :             xMap = mxSymbolsODFF;
     546                 :       2775 :             break;
     547                 :            :         case FormulaLanguage::ODF_11 :
     548         [ +  - ]:        266 :             if (!mxSymbolsPODF)
     549         [ +  - ]:        266 :                 InitSymbolsPODF();
     550         [ +  - ]:        266 :             xMap = mxSymbolsPODF;
     551                 :        266 :             break;
     552                 :            :         case FormulaLanguage::ENGLISH :
     553         [ +  - ]:         69 :             if (!mxSymbolsEnglish)
     554         [ +  - ]:         69 :                 InitSymbolsEnglish();
     555         [ +  - ]:         69 :             xMap = mxSymbolsEnglish;
     556                 :         69 :             break;
     557                 :            :         case FormulaLanguage::NATIVE :
     558         [ +  - ]:      30395 :             if (!mxSymbolsNative)
     559         [ +  - ]:      30395 :                 InitSymbolsNative();
     560         [ +  - ]:      30395 :             xMap = mxSymbolsNative;
     561                 :      30395 :             break;
     562                 :            :         case FormulaLanguage::XL_ENGLISH:
     563         [ #  # ]:          0 :             if (!mxSymbolsEnglishXL)
     564         [ #  # ]:          0 :                 InitSymbolsEnglishXL();
     565         [ #  # ]:          0 :             xMap = mxSymbolsEnglishXL;
     566                 :          0 :             break;
     567                 :            :         default:
     568                 :            :             ;   // nothing, NULL map returned
     569                 :            :     }
     570                 :      33505 :     return xMap;
     571                 :            : }
     572                 :            : // -----------------------------------------------------------------------------
     573                 :            : 
     574                 :          0 : String FormulaCompiler::FindAddInFunction( const String& /*rUpperName*/, bool /*bLocalFirst*/ ) const
     575                 :            : {
     576                 :          0 :     return String();
     577                 :            : }
     578                 :            : // -----------------------------------------------------------------------------
     579                 :         24 : 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 [ +  - ][ +  - ]:         24 :     NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1,false, FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(FormulaGrammar::GRAM_EXTERNAL, bEnglish),FormulaGrammar::CONV_UNSPECIFIED)));
                 [ +  - ]
     587                 :         24 :     FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
     588                 :         24 :     FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
     589         [ +  + ]:       8784 :     for ( ; pArr2 < pStop; ++pArr2)
     590                 :            :     {
     591                 :       8760 :         OpCode eOp = OpCode(pArr2->Token.OpCode);
     592         [ +  + ]:       8760 :         if (eOp != ocExternal)
     593 [ +  - ][ +  - ]:       6528 :             xMap->putOpCode( pArr2->Name, eOp);
                 [ +  - ]
     594                 :            :         else
     595                 :            :         {
     596                 :       2232 :             ::rtl::OUString aExternalName;
     597         [ +  - ]:       2232 :             if (pArr2->Token.Data >>= aExternalName)
     598 [ +  - ][ +  - ]:       2232 :                 xMap->putExternal( pArr2->Name, aExternalName);
         [ +  - ][ +  - ]
                 [ +  - ]
     599                 :            :             else
     600                 :            :             {
     601                 :            :                 SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
     602                 :       2232 :             }
     603                 :            :         }
     604                 :            :     }
     605 [ +  - ][ +  - ]:         24 :     return xMap;
     606                 :            : }
     607                 :            : 
     608                 :            : // -----------------------------------------------------------------------------
     609                 :      63121 : void lcl_fillNativeSymbols(FormulaCompiler::NonConstOpCodeMapPtr& _xMap,bool _destroy = false)
     610                 :            : {
     611 [ +  + ][ +  - ]:      63121 :     static FormulaCompiler::NonConstOpCodeMapPtr s_SymbolMap;
         [ +  - ][ #  # ]
     612         [ +  + ]:      63121 :     if ( _destroy )
     613                 :            :     {
     614                 :        412 :         s_SymbolMap.reset();
     615                 :            :     } // if ( _destroy )
     616         [ +  + ]:      62709 :     else if ( !s_SymbolMap.get() )
     617                 :            :     {
     618                 :            :         // Core
     619 [ +  - ][ +  - ]:        415 :         s_SymbolMap.reset( new FormulaCompiler::OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
                 [ +  - ]
     620         [ +  - ]:        415 :         OModuleClient aModuleClient;
     621 [ +  - ][ +  - ]:        415 :         OpCodeList aOpCodeListNative( RID_STRLIST_FUNCTION_NAMES, s_SymbolMap );
         [ +  - ][ +  - ]
     622                 :            :         // No AddInMap for native core mapping.
     623                 :            :     } // if ( !s_SymbolMap.get() )
     624                 :      63121 :     _xMap = s_SymbolMap;
     625                 :      63121 : }
     626                 :            : // -----------------------------------------------------------------------------
     627                 :      31490 : const String& FormulaCompiler::GetNativeSymbol( OpCode eOp )
     628                 :            : {
     629         [ +  - ]:      31490 :     NonConstOpCodeMapPtr xSymbolsNative;
     630         [ +  - ]:      31490 :     lcl_fillNativeSymbols(xSymbolsNative);
     631 [ +  - ][ +  - ]:      31490 :     return xSymbolsNative->getSymbol( eOp );
     632                 :            : }
     633                 :            : // -----------------------------------------------------------------------------
     634                 :      30395 : void FormulaCompiler::InitSymbolsNative() const
     635                 :            : {
     636                 :      30395 :     lcl_fillNativeSymbols(mxSymbolsNative);
     637                 :      30395 : }
     638                 :            : // -----------------------------------------------------------------------------
     639                 :         69 : void FormulaCompiler::InitSymbolsEnglish() const
     640                 :            : {
     641 [ +  + ][ +  - ]:         69 :     static NonConstOpCodeMapPtr s_sSymbol;
         [ +  - ][ #  # ]
     642         [ +  + ]:         69 :     if ( !s_sSymbol.get() )
     643                 :          4 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
     644                 :         69 :     mxSymbolsEnglish = s_sSymbol;
     645                 :         69 : }
     646                 :            : // -----------------------------------------------------------------------------
     647                 :        266 : void FormulaCompiler::InitSymbolsPODF() const
     648                 :            : {
     649 [ +  + ][ +  - ]:        266 :     static NonConstOpCodeMapPtr s_sSymbol;
         [ +  - ][ #  # ]
     650         [ +  + ]:        266 :     if ( !s_sSymbol.get() )
     651                 :         11 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_PODF,s_sSymbol);
     652                 :        266 :     mxSymbolsPODF = s_sSymbol;
     653                 :        266 : }
     654                 :            : // -----------------------------------------------------------------------------
     655                 :       2655 : void FormulaCompiler::InitSymbolsODFF() const
     656                 :            : {
     657 [ +  + ][ +  - ]:       2655 :     static NonConstOpCodeMapPtr s_sSymbol;
         [ +  - ][ #  # ]
     658         [ +  + ]:       2655 :     if ( !s_sSymbol.get() )
     659                 :         14 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF,FormulaGrammar::GRAM_ODFF,s_sSymbol);
     660                 :       2655 :     mxSymbolsODFF = s_sSymbol;
     661                 :       2655 : }
     662                 :            : // -----------------------------------------------------------------------------
     663                 :          0 : void FormulaCompiler::InitSymbolsEnglishXL() const
     664                 :            : {
     665 [ #  # ][ #  # ]:          0 :     static NonConstOpCodeMapPtr s_sSymbol;
         [ #  # ][ #  # ]
     666         [ #  # ]:          0 :     if ( !s_sSymbol.get() )
     667                 :          0 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH,FormulaGrammar::GRAM_ENGLISH,s_sSymbol);
     668                 :          0 :     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 [ #  # ][ #  # ]:          0 :     mxSymbolsEnglishXL->putOpCode(rtl::OUString(','), ocSep);
                 [ #  # ]
     674 [ #  # ][ #  # ]:          0 :     mxSymbolsEnglishXL->putOpCode(rtl::OUString(','), ocArrayColSep);
                 [ #  # ]
     675 [ #  # ][ #  # ]:          0 :     mxSymbolsEnglishXL->putOpCode(rtl::OUString(';'), ocArrayRowSep);
                 [ #  # ]
     676                 :          0 : }
     677                 :            : 
     678                 :            : // -----------------------------------------------------------------------------
     679                 :         29 : void FormulaCompiler::loadSymbols(sal_uInt16 _nSymbols,FormulaGrammar::Grammar _eGrammar,NonConstOpCodeMapPtr& _xMap) const
     680                 :            : {
     681         [ +  - ]:         29 :     if ( !_xMap.get() )
     682                 :            :     {
     683                 :            :         // not Core
     684 [ +  - ][ +  - ]:         29 :         _xMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, _eGrammar != FormulaGrammar::GRAM_ODFF, _eGrammar ));
                 [ +  - ]
     685         [ +  - ]:         29 :         OModuleClient aModuleClient;
     686 [ +  - ][ +  - ]:         29 :         OpCodeList aOpCodeList( _nSymbols, _xMap );
                 [ +  - ]
     687                 :            : 
     688 [ +  - ][ +  - ]:         29 :         fillFromAddInMap( _xMap, _eGrammar);
                 [ +  - ]
     689                 :            :         // Fill from collection for AddIns not already present.
     690         [ +  + ]:         29 :         if ( FormulaGrammar::GRAM_ENGLISH != _eGrammar )
     691 [ +  - ][ +  - ]:         25 :             fillFromAddInCollectionUpperName( _xMap);
                 [ +  - ]
     692                 :            :         else
     693 [ +  - ][ +  - ]:         29 :             fillFromAddInCollectionEnglishName( _xMap);
         [ +  - ][ +  - ]
     694                 :            :     }
     695                 :         29 : }
     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                 :      13730 : bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
     719                 :            : {
     720                 :      13730 :     bool bRet = false;
     721         [ +  + ]:      13730 :     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                 :        195 :             bRet = true;
     739                 :        195 :             break;
     740                 :            :         default:
     741                 :      13535 :             bRet = false;
     742                 :      13535 :             break;
     743                 :            :     }
     744                 :      13730 :     return bRet;
     745                 :            : }
     746                 :            : 
     747                 :            : // Remove quotes, escaped quotes are unescaped.
     748                 :         27 : bool FormulaCompiler::DeQuote( String& rStr )
     749                 :            : {
     750                 :         27 :     xub_StrLen nLen = rStr.Len();
     751 [ -  + ][ #  # ]:         27 :     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                 :         27 :     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                 :        936 : FormulaCompiler::OpCodeMap::~OpCodeMap()
     795                 :            : {
     796         [ +  - ]:        468 :     delete mpReverseExternalHashMap;
     797         [ +  - ]:        468 :     delete mpExternalHashMap;
     798 [ +  - ][ +  + ]:     189072 :     delete [] mpTable;
     799         [ +  - ]:        468 :     delete mpHashMap;
     800         [ -  + ]:        936 : }
     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                 :         48 : sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
     891                 :            : {
     892                 :            :     static const sal_Int32 kOpCodeUnknown = -1;
     893                 :         48 :     return kOpCodeUnknown;
     894                 :            : }
     895                 :            : // -----------------------------------------------------------------------------
     896                 :      71295 : bool FormulaCompiler::GetToken()
     897                 :            : {
     898                 :            :     static const short nRecursionMax = 42;
     899                 :      71295 :     FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
     900         [ -  + ]:      71295 :     if ( nRecursion > nRecursionMax )
     901                 :            :     {
     902         [ #  # ]:          0 :         SetError( errStackOverflow );
     903 [ #  # ][ #  # ]:          0 :         mpToken = new FormulaByteToken( ocStop );
                 [ #  # ]
     904                 :          0 :         return false;
     905                 :            :     }
     906 [ -  + ][ #  # ]:      71295 :     if ( bAutoCorrect && !pStack )
     907                 :            :     {   // don't merge stacked subroutine code into entered formula
     908         [ #  # ]:          0 :         aCorrectedFormula += aCorrectedSymbol;
     909         [ #  # ]:          0 :         aCorrectedSymbol.Erase();
     910                 :            :     }
     911                 :      71295 :     bool bStop = false;
     912 [ -  + ][ #  # ]:      71295 :     if( pArr->GetCodeError() && !bIgnoreErrors )
                 [ -  + ]
     913                 :          0 :         bStop = true;
     914                 :            :     else
     915                 :            :     {
     916                 :            :         short nWasColRowName;
     917   [ +  +  -  + ]:     137392 :         if ( pArr->nIndex
                 [ -  + ]
     918                 :      66097 :           && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
     919                 :          0 :              nWasColRowName = 1;
     920                 :            :         else
     921                 :      71295 :              nWasColRowName = 0;
     922 [ +  - ][ +  - ]:      71295 :         mpToken = pArr->Next();
     923 [ +  + ][ +  + ]:      71375 :         while( mpToken && mpToken->GetOpCode() == ocSpaces )
                 [ +  + ]
     924                 :            :         {
     925         [ -  + ]:         80 :             if ( nWasColRowName )
     926                 :          0 :                 nWasColRowName++;
     927 [ -  + ][ #  # ]:         80 :             if ( bAutoCorrect && !pStack )
     928         [ #  # ]:          0 :                 CreateStringFromToken( aCorrectedFormula, mpToken.get(), false );
     929 [ +  - ][ +  - ]:         80 :             mpToken = pArr->Next();
     930                 :            :         }
     931 [ -  + ][ #  # ]:      71295 :         if ( bAutoCorrect && !pStack && mpToken )
         [ #  # ][ -  + ]
     932         [ #  # ]:          0 :             CreateStringFromToken( aCorrectedSymbol, mpToken.get(), false );
     933         [ +  + ]:      71295 :         if( !mpToken )
     934                 :            :         {
     935         [ +  + ]:       4123 :             if( pStack )
     936                 :            :             {
     937         [ +  - ]:        284 :                 PopTokenArray();
     938         [ +  - ]:        284 :                 return GetToken();
     939                 :            :             }
     940                 :            :             else
     941                 :       3839 :                 bStop = true;
     942                 :            :         }
     943                 :            :         else
     944                 :            :         {
     945 [ -  + ][ #  # ]:      67172 :             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         [ +  + ]:      71011 :     if( bStop )
     953                 :            :     {
     954 [ +  - ][ +  - ]:       3839 :         mpToken = new FormulaByteToken( ocStop );
                 [ +  - ]
     955                 :       3839 :         return false;
     956                 :            :     }
     957         [ +  + ]:      67172 :     if( mpToken->GetOpCode() == ocSubTotal )
     958                 :          5 :         glSubTotal = true;
     959 [ +  - ][ +  + ]:      67167 :     else if ( mpToken->IsExternalRef() )
     960                 :            :     {
     961         [ +  - ]:        100 :         return HandleExternalReference(*mpToken);
     962                 :            :     }
     963         [ +  + ]:      67067 :     else if( mpToken->GetOpCode() == ocName )
     964                 :            :     {
     965         [ +  - ]:        218 :         return HandleRange();
     966                 :            :     }
     967         [ -  + ]:      66849 :     else if( mpToken->GetOpCode() == ocColRowName )
     968                 :            :     {
     969         [ #  # ]:          0 :         return HandleSingleRef();
     970                 :            :     }
     971         [ +  + ]:      66849 :     else if( mpToken->GetOpCode() == ocDBArea )
     972                 :            :     {
     973         [ +  - ]:          6 :         return HandleDbData();
     974                 :            :     }
     975         [ +  + ]:      66843 :     else if( mpToken->GetType() == svSingleRef )
     976                 :            :     {
     977                 :       4726 :         pArr->nRefs++;
     978                 :            :     }
     979         [ +  + ]:      62117 :     else if( mpToken->GetType() == svDoubleRef )
     980                 :            :     {
     981                 :       5566 :         pArr->nRefs++;
     982                 :            :     }
     983                 :      71295 :     return true;
     984                 :            : }
     985                 :            : //---------------------------------------------------------------------------
     986                 :            : // RPN creation by recursion
     987                 :            : //---------------------------------------------------------------------------
     988                 :            : 
     989                 :      30874 : void FormulaCompiler::Factor()
     990                 :            : {
     991 [ -  + ][ #  # ]:      30874 :     if ( pArr->GetCodeError() && !bIgnoreErrors )
                 [ +  - ]
     992                 :      30874 :         return;
     993                 :            : 
     994         [ +  - ]:      30874 :     CurrentFactor pFacToken( this );
     995                 :            : 
     996                 :      30874 :     OpCode eOp = mpToken->GetOpCode();
     997 [ +  - ][ +  + ]:      30874 :     if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ +  + ]
     998                 :            :             eOp == ocDBArea
     999                 :            :             || (bCompileForFAP && ((eOp == ocName) || (eOp == ocDBArea)
    1000                 :            :             || (eOp == ocColRowName) || (eOp == ocBad)))
    1001                 :            :         )
    1002                 :            :     {
    1003         [ +  - ]:      19910 :         PutCode( mpToken );
    1004         [ +  - ]:      19910 :         eOp = NextToken();
    1005         [ -  + ]:      19910 :         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         [ +  + ]:      10964 :     else if( eOp == ocOpen )
    1026                 :            :     {
    1027         [ +  - ]:        110 :         NextToken();
    1028         [ +  - ]:        110 :         eOp = Expression();
    1029 [ -  + ][ #  # ]:        110 :         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         [ -  + ]:        110 :         if (eOp != ocClose)
    1043         [ #  # ]:          0 :             SetError(errPairExpected);
    1044                 :            :         else
    1045         [ +  - ]:        110 :             eOp = NextToken();
    1046                 :            :     }
    1047                 :            :     else
    1048                 :            :     {
    1049         [ +  + ]:      10854 :         if( nNumFmt == NUMBERFORMAT_UNDEFINED )
    1050                 :       4170 :             nNumFmt = lcl_GetRetFormat( eOp );
    1051                 :            : 
    1052 [ +  - ][ +  + ]:      10854 :         if ( IsOpCodeVolatile(eOp) )
    1053                 :         66 :             pArr->SetRecalcModeAlways();
    1054                 :            :         else
    1055                 :            :         {
    1056   [ -  +  -  + ]:      10788 :             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                 :        162 :                     pArr->SetRecalcModeOnRefMove();
    1070                 :        162 :                 break;
    1071                 :            :                 case ocHyperLink :
    1072                 :          0 :                 pArr->SetHyperLink(true);
    1073                 :          0 :                 break;
    1074                 :            :                 default:
    1075                 :            :                     ;   // nothing
    1076                 :            :             }
    1077                 :            :         }
    1078 [ +  + ][ +  + ]:      10854 :         if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
    1079                 :            :         {
    1080         [ +  - ]:        156 :             pFacToken = mpToken;
    1081         [ +  - ]:        156 :             eOp = NextToken();
    1082         [ -  + ]:        312 :             if (eOp != ocOpen)
    1083                 :            :             {
    1084         [ #  # ]:          0 :                 SetError(errPairExpected);
    1085         [ #  # ]:          0 :                 PutCode( pFacToken );
    1086                 :            :             }
    1087                 :            :             else
    1088                 :            :             {
    1089         [ +  - ]:        156 :                 eOp = NextToken();
    1090         [ -  + ]:        156 :                 if (eOp != ocClose)
    1091         [ #  # ]:          0 :                     SetError(errPairExpected);
    1092         [ +  - ]:        156 :                 PutCode(pFacToken);
    1093         [ +  - ]:        156 :                 eOp = NextToken();
    1094                 :            :             }
    1095                 :            :         }
    1096                 :            :         // special cases NOT() and NEG()
    1097 [ +  - ][ +  - ]:      10698 :         else if( eOp == ocNot || eOp == ocNeg
         [ +  + ][ +  + ]
    1098                 :            :               || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
    1099                 :            :         {
    1100         [ +  - ]:        607 :             pFacToken = mpToken;
    1101         [ +  - ]:        607 :             eOp = NextToken();
    1102 [ -  + ][ #  # ]:        607 :             if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot )
    1103                 :          0 :                 nNumFmt = NUMBERFORMAT_LOGICAL;
    1104         [ +  - ]:        607 :             if (eOp == ocOpen)
    1105                 :            :             {
    1106         [ +  - ]:        607 :                 NextToken();
    1107         [ +  - ]:        607 :                 eOp = Expression();
    1108                 :            :             }
    1109                 :            :             else
    1110         [ #  # ]:          0 :                 SetError(errPairExpected);
    1111         [ -  + ]:        607 :             if (eOp != ocClose)
    1112         [ #  # ]:          0 :                 SetError(errPairExpected);
    1113         [ +  - ]:        607 :             else if ( !pArr->GetCodeError() )
    1114 [ +  - ][ +  - ]:        607 :                 pFacToken->SetByte( 1 );
    1115         [ +  - ]:        607 :             PutCode( pFacToken );
    1116         [ +  - ]:        607 :             eOp = NextToken();
    1117                 :            :         }
    1118 [ +  + ][ -  + ]:      10091 :         else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ -  + ]
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
    1119                 :            :                 || eOp == ocExternal
    1120                 :            :                 || eOp == ocMacro
    1121                 :            :                 || eOp == ocAnd
    1122                 :            :                 || eOp == ocOr
    1123                 :            :                 || eOp == ocBad
    1124                 :            :                 || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
    1125                 :            :                 || (bCompileForFAP && ((eOp == ocIf) || (eOp == ocChose)))
    1126                 :            :             )
    1127                 :            :         {
    1128         [ +  - ]:       8964 :             pFacToken = mpToken;
    1129                 :       8964 :             OpCode eMyLastOp = eOp;
    1130         [ +  - ]:       8964 :             eOp = NextToken();
    1131                 :       8964 :             bool bNoParam = false;
    1132                 :       8964 :             bool bBadName = false;
    1133         [ +  + ]:       8964 :             if (eOp == ocOpen)
    1134                 :            :             {
    1135         [ +  - ]:       8940 :                 eOp = NextToken();
    1136         [ +  + ]:       8940 :                 if (eOp == ocClose)
    1137                 :         15 :                     bNoParam = true;
    1138                 :            :                 else
    1139         [ +  - ]:       8925 :                     eOp = Expression();
    1140                 :            :             }
    1141         [ +  - ]:         24 :             else if (eMyLastOp == ocBad)
    1142                 :            :             {
    1143                 :            :                 // Just a bad name, not an unknown function, no parameters, no
    1144                 :            :                 // closing expected.
    1145                 :         24 :                 bBadName = true;
    1146                 :         24 :                 bNoParam = true;
    1147                 :            :             }
    1148                 :            :             else
    1149         [ #  # ]:          0 :                 SetError(errPairExpected);
    1150                 :       8964 :             sal_uInt8 nSepCount = 0;
    1151         [ +  + ]:       8964 :             if( !bNoParam )
    1152                 :            :             {
    1153                 :       8925 :                 nSepCount++;
    1154 [ +  + ][ -  + ]:      18229 :                 while ( (eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors) )
         [ #  # ][ +  + ]
    1155                 :            :                 {
    1156                 :       9304 :                     nSepCount++;
    1157         [ +  - ]:       9304 :                     NextToken();
    1158         [ +  - ]:       9304 :                     eOp = Expression();
    1159                 :            :                 }
    1160                 :            :             }
    1161         [ +  + ]:       8964 :             if (bBadName)
    1162                 :            :                 ;   // nothing, keep current token for return
    1163         [ -  + ]:       8940 :             else if (eOp != ocClose)
    1164         [ #  # ]:          0 :                 SetError(errPairExpected);
    1165                 :            :             else
    1166         [ +  - ]:       8940 :                 eOp = NextToken();
    1167                 :            :             // Jumps are just normal functions for the FunctionAutoPilot tree view
    1168 [ -  + ][ #  # ]:       8964 :             if ( bCompileForFAP && pFacToken->GetType() == svJump )
         [ #  # ][ -  + ]
    1169 [ #  # ][ #  # ]:          0 :                 pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
         [ #  # ][ #  # ]
                 [ #  # ]
    1170                 :            :             else
    1171 [ +  - ][ +  - ]:       8964 :                 pFacToken->SetByte( nSepCount );
    1172         [ +  - ]:       8964 :             PutCode( pFacToken );
    1173                 :            :         }
    1174 [ +  + ][ -  + ]:       1127 :         else if (eOp == ocIf || eOp == ocChose)
    1175                 :            :         {
    1176                 :            :             // the PC counters are -1
    1177         [ +  - ]:         42 :             pFacToken = mpToken;
    1178         [ +  - ]:         42 :             if ( eOp == ocIf )
    1179 [ +  - ][ +  - ]:         42 :                 pFacToken->GetJump()[ 0 ] = 3;  // if, else, behind
    1180                 :            :             else
    1181 [ #  # ][ #  # ]:          0 :                 pFacToken->GetJump()[ 0 ] = MAXJUMPCOUNT+1;
    1182         [ +  - ]:         42 :             eOp = NextToken();
    1183         [ +  - ]:         42 :             if (eOp == ocOpen)
    1184                 :            :             {
    1185         [ +  - ]:         42 :                 NextToken();
    1186         [ +  - ]:         42 :                 eOp = Expression();
    1187                 :            :             }
    1188                 :            :             else
    1189         [ #  # ]:          0 :                 SetError(errPairExpected);
    1190                 :         42 :             short nJumpCount = 0;
    1191         [ +  - ]:         42 :             PutCode( pFacToken );
    1192                 :            :             // during AutoCorrect (since pArr->GetCodeError() is
    1193                 :            :             // ignored) an unlimited ocIf would crash because
    1194                 :            :             // ScRawToken::Clone() allocates the JumpBuffer according to
    1195                 :            :             // nJump[0]*2+2, which is 3*2+2 on ocIf.
    1196                 :            :             const short nJumpMax =
    1197 [ +  - ][ +  - ]:         42 :                 (pFacToken->GetOpCode() == ocIf ? 3 : MAXJUMPCOUNT);
    1198         [ +  - ]:        138 :             while ( (nJumpCount < (MAXJUMPCOUNT - 1)) && (eOp == ocSep)
           [ +  +  -  + ]
         [ #  # ][ +  + ]
    1199                 :         48 :                     && (!pArr->GetCodeError() || bIgnoreErrors) )
    1200                 :            :             {
    1201         [ +  - ]:         48 :                 if ( ++nJumpCount <= nJumpMax )
    1202 [ +  - ][ +  - ]:         48 :                     pFacToken->GetJump()[nJumpCount] = pc-1;
    1203         [ +  - ]:         48 :                 NextToken();
    1204         [ +  - ]:         48 :                 eOp = Expression();
    1205                 :            :                 // ocSep or ocClose terminate the subexpression
    1206         [ +  - ]:         48 :                 PutCode( mpToken );
    1207                 :            :             }
    1208         [ -  + ]:         42 :             if (eOp != ocClose)
    1209         [ #  # ]:          0 :                 SetError(errPairExpected);
    1210                 :            :             else
    1211                 :            :             {
    1212         [ +  - ]:         42 :                 eOp = NextToken();
    1213                 :            :                 // always limit to nJumpMax, no arbitrary overwrites
    1214         [ +  - ]:         42 :                 if ( ++nJumpCount <= nJumpMax )
    1215 [ +  - ][ +  - ]:         42 :                     pFacToken->GetJump()[ nJumpCount ] = pc-1;
    1216 [ +  - ][ +  - ]:         42 :                 if ((pFacToken->GetOpCode() == ocIf && (nJumpCount > 3)) ||
         [ +  - ][ -  + ]
                 [ -  + ]
    1217                 :            :                                  (nJumpCount >= MAXJUMPCOUNT))
    1218         [ #  # ]:          0 :                     SetError(errIllegalParameter);
    1219                 :            :                 else
    1220 [ +  - ][ +  - ]:         42 :                     pFacToken->GetJump()[ 0 ] = nJumpCount;
    1221                 :         42 :             }
    1222                 :            :         }
    1223         [ +  + ]:       1085 :         else if ( eOp == ocMissing )
    1224                 :            :         {
    1225         [ +  - ]:         18 :             PutCode( mpToken );
    1226         [ +  - ]:         18 :             eOp = NextToken();
    1227                 :            :         }
    1228         [ -  + ]:       1067 :         else if ( eOp == ocClose )
    1229                 :            :         {
    1230         [ #  # ]:          0 :             SetError( errParameterExpected );
    1231                 :            :         }
    1232         [ -  + ]:       1067 :         else if ( eOp == ocSep )
    1233                 :            :         {   // Subsequent ocSep
    1234         [ #  # ]:          0 :             SetError( errParameterExpected );
    1235 [ #  # ][ #  # ]:          0 :             if ( bAutoCorrect && !pStack )
    1236                 :            :             {
    1237         [ #  # ]:          0 :                 aCorrectedSymbol.Erase();
    1238                 :          0 :                 bCorrected = true;
    1239                 :            :             }
    1240                 :            :         }
    1241 [ +  - ][ -  + ]:       1067 :         else if ( mpToken->IsExternalRef() )
    1242                 :            :         {
    1243         [ #  # ]:          0 :             PutCode(mpToken);
    1244         [ #  # ]:          0 :             eOp = NextToken();
    1245                 :            :         }
    1246                 :            :         else
    1247                 :            :         {
    1248         [ +  - ]:       1067 :             SetError( errUnknownToken );
    1249 [ -  + ][ #  # ]:       1067 :             if ( bAutoCorrect && !pStack )
    1250                 :            :             {
    1251         [ #  # ]:          0 :                 if ( eOp == ocStop )
    1252                 :            :                 {   // trailing operator w/o operand
    1253                 :          0 :                     xub_StrLen nLen = aCorrectedFormula.Len();
    1254         [ #  # ]:          0 :                     if ( nLen )
    1255         [ #  # ]:          0 :                         aCorrectedFormula.Erase( nLen - 1 );
    1256         [ #  # ]:          0 :                     aCorrectedSymbol.Erase();
    1257                 :          0 :                     bCorrected = true;
    1258                 :            :                 }
    1259                 :            :             }
    1260                 :            :         }
    1261         [ +  - ]:      30874 :     }
    1262                 :            : }
    1263                 :            : 
    1264                 :            : //---------------------------------------------------------------------------
    1265                 :            : 
    1266                 :      30874 : void FormulaCompiler::RangeLine()
    1267                 :            : {
    1268                 :      30874 :     Factor();
    1269         [ -  + ]:      30874 :     while (mpToken->GetOpCode() == ocRange)
    1270                 :            :     {
    1271                 :          0 :         FormulaToken** pCode1 = pCode - 1;
    1272                 :          0 :         FormulaTokenRef p = mpToken;
    1273         [ #  # ]:          0 :         NextToken();
    1274         [ #  # ]:          0 :         Factor();
    1275                 :          0 :         FormulaToken** pCode2 = pCode - 1;
    1276 [ #  # ][ #  # ]:          0 :         if (!MergeRangeReference( pCode1, pCode2))
    1277         [ #  # ]:          0 :             PutCode(p);
    1278         [ #  # ]:          0 :     }
    1279                 :      30874 : }
    1280                 :            : 
    1281                 :            : //---------------------------------------------------------------------------
    1282                 :            : 
    1283                 :      30874 : void FormulaCompiler::IntersectionLine()
    1284                 :            : {
    1285                 :      30874 :     RangeLine();
    1286         [ -  + ]:      30874 :     while (mpToken->GetOpCode() == ocIntersect)
    1287                 :            :     {
    1288                 :          0 :         FormulaTokenRef p = mpToken;
    1289         [ #  # ]:          0 :         NextToken();
    1290         [ #  # ]:          0 :         RangeLine();
    1291         [ #  # ]:          0 :         PutCode(p);
    1292         [ #  # ]:          0 :     }
    1293                 :      30874 : }
    1294                 :            : 
    1295                 :            : //---------------------------------------------------------------------------
    1296                 :            : 
    1297                 :      30874 : void FormulaCompiler::UnionLine()
    1298                 :            : {
    1299                 :      30874 :     IntersectionLine();
    1300         [ -  + ]:      30874 :     while (mpToken->GetOpCode() == ocUnion)
    1301                 :            :     {
    1302                 :          0 :         FormulaTokenRef p = mpToken;
    1303         [ #  # ]:          0 :         NextToken();
    1304         [ #  # ]:          0 :         IntersectionLine();
    1305         [ #  # ]:          0 :         PutCode(p);
    1306         [ #  # ]:          0 :     }
    1307                 :      30874 : }
    1308                 :            : 
    1309                 :            : //---------------------------------------------------------------------------
    1310                 :            : 
    1311                 :      31064 : void FormulaCompiler::UnaryLine()
    1312                 :            : {
    1313         [ -  + ]:      31064 :     if( mpToken->GetOpCode() == ocAdd )
    1314                 :          0 :         GetToken();
    1315   [ +  +  +  + ]:      40873 :     else if (SC_OPCODE_START_UN_OP <= mpToken->GetOpCode() &&
                 [ +  + ]
    1316                 :       9809 :             mpToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
    1317                 :            :     {
    1318                 :        190 :         FormulaTokenRef p = mpToken;
    1319         [ +  - ]:        190 :         NextToken();
    1320         [ +  - ]:        190 :         UnaryLine();
    1321 [ +  - ][ +  - ]:        190 :         PutCode( p );
    1322                 :            :     }
    1323                 :            :     else
    1324                 :      30874 :         UnionLine();
    1325                 :      31064 : }
    1326                 :            : 
    1327                 :            : //---------------------------------------------------------------------------
    1328                 :            : 
    1329                 :      30874 : void FormulaCompiler::PostOpLine()
    1330                 :            : {
    1331                 :      30874 :     UnaryLine();
    1332         [ -  + ]:      30874 :     while ( mpToken->GetOpCode() == ocPercentSign )
    1333                 :            :     {   // this operator _follows_ its operand
    1334                 :          0 :         PutCode( mpToken );
    1335                 :          0 :         NextToken();
    1336                 :            :     }
    1337                 :      30874 : }
    1338                 :            : 
    1339                 :            : //---------------------------------------------------------------------------
    1340                 :            : 
    1341                 :      30873 : void FormulaCompiler::PowLine()
    1342                 :            : {
    1343                 :      30873 :     PostOpLine();
    1344         [ +  + ]:      30874 :     while (mpToken->GetOpCode() == ocPow)
    1345                 :            :     {
    1346                 :          1 :         FormulaTokenRef p = mpToken;
    1347         [ +  - ]:          1 :         NextToken();
    1348         [ +  - ]:          1 :         PostOpLine();
    1349         [ +  - ]:          1 :         PutCode(p);
    1350         [ +  - ]:          1 :     }
    1351                 :      30873 : }
    1352                 :            : 
    1353                 :            : //---------------------------------------------------------------------------
    1354                 :            : 
    1355                 :      30722 : void FormulaCompiler::MulDivLine()
    1356                 :            : {
    1357                 :      30722 :     PowLine();
    1358 [ +  + ][ +  + ]:      30873 :     while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv)
                 [ +  + ]
    1359                 :            :     {
    1360                 :        151 :         FormulaTokenRef p = mpToken;
    1361         [ +  - ]:        151 :         NextToken();
    1362         [ +  - ]:        151 :         PowLine();
    1363         [ +  - ]:        151 :         PutCode(p);
    1364         [ +  - ]:        151 :     }
    1365                 :      30722 : }
    1366                 :            : 
    1367                 :            : //---------------------------------------------------------------------------
    1368                 :            : 
    1369                 :      23992 : void FormulaCompiler::AddSubLine()
    1370                 :            : {
    1371                 :      23992 :     MulDivLine();
    1372 [ +  + ][ +  + ]:      30722 :     while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub)
                 [ +  + ]
    1373                 :            :     {
    1374                 :       6730 :         FormulaTokenRef p = mpToken;
    1375         [ +  - ]:       6730 :         NextToken();
    1376         [ +  - ]:       6730 :         MulDivLine();
    1377         [ +  - ]:       6730 :         PutCode(p);
    1378         [ +  - ]:       6730 :     }
    1379                 :      23992 : }
    1380                 :            : 
    1381                 :            : //---------------------------------------------------------------------------
    1382                 :            : 
    1383                 :      23992 : void FormulaCompiler::ConcatLine()
    1384                 :            : {
    1385                 :      23992 :     AddSubLine();
    1386         [ -  + ]:      23992 :     while (mpToken->GetOpCode() == ocAmpersand)
    1387                 :            :     {
    1388                 :          0 :         FormulaTokenRef p = mpToken;
    1389         [ #  # ]:          0 :         NextToken();
    1390         [ #  # ]:          0 :         AddSubLine();
    1391         [ #  # ]:          0 :         PutCode(p);
    1392         [ #  # ]:          0 :     }
    1393                 :      23992 : }
    1394                 :            : 
    1395                 :            : //---------------------------------------------------------------------------
    1396                 :            : 
    1397                 :      23950 : void FormulaCompiler::CompareLine()
    1398                 :            : {
    1399                 :      23950 :     ConcatLine();
    1400 [ +  + ][ +  - ]:      23992 :     while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual)
                 [ +  + ]
    1401                 :            :     {
    1402                 :         42 :         FormulaTokenRef p = mpToken;
    1403         [ +  - ]:         42 :         NextToken();
    1404         [ +  - ]:         42 :         ConcatLine();
    1405         [ +  - ]:         42 :         PutCode(p);
    1406         [ +  - ]:         42 :     }
    1407                 :      23950 : }
    1408                 :            : 
    1409                 :            : //---------------------------------------------------------------------------
    1410                 :            : 
    1411                 :      23950 : void FormulaCompiler::NotLine()
    1412                 :            : {
    1413                 :      23950 :     CompareLine();
    1414         [ -  + ]:      23950 :     while (mpToken->GetOpCode() == ocNot)
    1415                 :            :     {
    1416                 :          0 :         FormulaTokenRef p = mpToken;
    1417         [ #  # ]:          0 :         NextToken();
    1418         [ #  # ]:          0 :         CompareLine();
    1419         [ #  # ]:          0 :         PutCode(p);
    1420         [ #  # ]:          0 :     }
    1421                 :      23950 : }
    1422                 :            : 
    1423                 :            : //---------------------------------------------------------------------------
    1424                 :            : 
    1425                 :      23950 : OpCode FormulaCompiler::Expression()
    1426                 :            : {
    1427                 :            :     static const short nRecursionMax = 42;
    1428                 :      23950 :     FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
    1429         [ -  + ]:      23950 :     if ( nRecursion > nRecursionMax )
    1430                 :            :     {
    1431         [ #  # ]:          0 :         SetError( errStackOverflow );
    1432                 :          0 :         return ocStop;      //! generate token instead?
    1433                 :            :     }
    1434         [ +  - ]:      23950 :     NotLine();
    1435 [ +  - ][ -  + ]:      23950 :     while (mpToken->GetOpCode() == ocAnd || mpToken->GetOpCode() == ocOr)
                 [ -  + ]
    1436                 :            :     {
    1437                 :          0 :         FormulaTokenRef p = mpToken;
    1438         [ #  # ]:          0 :         mpToken->SetByte( 2 );       // 2 parameters!
    1439         [ #  # ]:          0 :         NextToken();
    1440         [ #  # ]:          0 :         NotLine();
    1441         [ #  # ]:          0 :         PutCode(p);
    1442         [ #  # ]:          0 :     }
    1443                 :      23950 :     return mpToken->GetOpCode();
    1444                 :            : }
    1445                 :            : // -----------------------------------------------------------------------------
    1446                 :          0 : void FormulaCompiler::SetError(sal_uInt16 /*nError*/)
    1447                 :            : {
    1448                 :          0 : }
    1449                 :            : // -----------------------------------------------------------------------------
    1450                 :          0 : FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/, bool /*bReuseDoubleRef*/ )
    1451                 :            : {
    1452                 :          0 :     return FormulaTokenRef();
    1453                 :            : }
    1454                 :            : // -----------------------------------------------------------------------------
    1455                 :          0 : bool FormulaCompiler::MergeRangeReference(FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
    1456                 :            : {
    1457                 :            :     FormulaToken *p1, *p2;
    1458 [ #  # ][ #  # ]:          0 :     if (pc < 2 || !pCode1 || !pCode2 ||
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1459                 :            :             (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
    1460                 :            :             ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
    1461                 :          0 :         return false;
    1462                 :            : 
    1463         [ #  # ]:          0 :     FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
    1464         [ #  # ]:          0 :     if (!p)
    1465                 :          0 :         return false;
    1466                 :            : 
    1467                 :          0 :     p->IncRef();
    1468         [ #  # ]:          0 :     p1->DecRef();
    1469         [ #  # ]:          0 :     p2->DecRef();
    1470                 :          0 :     *pCode1 = p.get();
    1471                 :          0 :     --pCode, --pc;
    1472                 :          0 :     pArr->nRefs--;
    1473                 :            : 
    1474         [ #  # ]:          0 :     return true;
    1475                 :            : }
    1476                 :            : // -----------------------------------------------------------------------------
    1477                 :       4914 : bool FormulaCompiler::CompileTokenArray()
    1478                 :            : {
    1479                 :       4914 :     glSubTotal = false;
    1480                 :       4914 :     bCorrected = false;
    1481 [ -  + ][ #  # ]:       4914 :     if( !pArr->GetCodeError() || bIgnoreErrors )
                 [ +  - ]
    1482                 :            :     {
    1483         [ -  + ]:       4914 :         if ( bAutoCorrect )
    1484                 :            :         {
    1485         [ #  # ]:          0 :             aCorrectedFormula.Erase();
    1486         [ #  # ]:          0 :             aCorrectedSymbol.Erase();
    1487                 :            :         }
    1488                 :       4914 :         pArr->nRefs = 0;    // count from start
    1489         [ +  - ]:       4914 :         pArr->DelRPN();
    1490                 :       4914 :         pStack = NULL;
    1491                 :            :         FormulaToken* pData[ MAXCODE ];
    1492                 :       4914 :         pCode = pData;
    1493                 :       4914 :         bool bWasForced = pArr->IsRecalcModeForced();
    1494         [ -  + ]:       4914 :         if ( bWasForced )
    1495                 :            :         {
    1496         [ #  # ]:          0 :             if ( bAutoCorrect )
    1497         [ #  # ]:          0 :                 aCorrectedFormula = '=';
    1498                 :            :         }
    1499                 :       4914 :         pArr->ClearRecalcMode();
    1500                 :       4914 :         pArr->Reset();
    1501                 :       4914 :         eLastOp = ocOpen;
    1502                 :       4914 :         pc = 0;
    1503         [ +  - ]:       4914 :         NextToken();
    1504         [ +  - ]:       4914 :         OpCode eOp = Expression();
    1505                 :            :         // Some trailing garbage that doesn't form an expression?
    1506         [ +  + ]:       4914 :         if (eOp != ocStop)
    1507         [ +  - ]:       1067 :             SetError( errOperatorExpected);
    1508                 :            : 
    1509                 :       4914 :         sal_uInt16 nErrorBeforePop = pArr->GetCodeError();
    1510                 :            : 
    1511         [ -  + ]:       4914 :         while( pStack )
    1512         [ #  # ]:          0 :             PopTokenArray();
    1513         [ +  + ]:       4914 :         if( pc )
    1514                 :            :         {
    1515         [ +  - ]:       3847 :             pArr->pRPN = new FormulaToken*[ pc ];
    1516                 :       3847 :             pArr->nRPN = pc;
    1517                 :       3847 :             memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
    1518                 :            :         }
    1519                 :            : 
    1520                 :            :         // once an error, always an error
    1521 [ +  + ][ -  + ]:       4914 :         if( !pArr->GetCodeError() && nErrorBeforePop )
                 [ -  + ]
    1522                 :          0 :             pArr->SetCodeError( nErrorBeforePop);
    1523                 :            : 
    1524 [ +  + ][ +  - ]:       4914 :         if( pArr->GetCodeError() && !bIgnoreErrors )
                 [ +  + ]
    1525                 :            :         {
    1526         [ +  - ]:       1067 :             pArr->DelRPN();
    1527                 :       1067 :             pArr->SetHyperLink(false);
    1528                 :            :         }
    1529                 :            : 
    1530         [ -  + ]:       4914 :         if ( bWasForced )
    1531                 :       4914 :             pArr->SetRecalcModeForced();
    1532                 :            :     }
    1533         [ +  + ]:       4914 :     if( nNumFmt == NUMBERFORMAT_UNDEFINED )
    1534                 :        744 :         nNumFmt = NUMBERFORMAT_NUMBER;
    1535                 :       4914 :     return glSubTotal;
    1536                 :            : }
    1537                 :            : // -----------------------------------------------------------------------------
    1538                 :        284 : void FormulaCompiler::PopTokenArray()
    1539                 :            : {
    1540         [ +  - ]:        284 :     if( pStack )
    1541                 :            :     {
    1542                 :        284 :         FormulaArrayStack* p = pStack;
    1543                 :        284 :         pStack = p->pNext;
    1544                 :        284 :         p->pArr->nRefs = sal::static_int_cast<short>( p->pArr->nRefs + pArr->nRefs );
    1545                 :            :         // obtain special RecalcMode from SharedFormula
    1546         [ -  + ]:        284 :         if ( pArr->IsRecalcModeAlways() )
    1547                 :          0 :             p->pArr->SetRecalcModeAlways();
    1548 [ -  + ][ #  # ]:        284 :         else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
                 [ -  + ]
    1549                 :          0 :             p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
    1550                 :        284 :         p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
    1551         [ +  - ]:        284 :         if( p->bTemp )
    1552         [ +  - ]:        284 :             delete pArr;
    1553                 :        284 :         pArr = p->pArr;
    1554                 :        284 :         delete p;
    1555                 :            :     }
    1556                 :        284 : }
    1557                 :            : // -----------------------------------------------------------------------------
    1558                 :        134 : void FormulaCompiler::CreateStringFromTokenArray( String& rFormula )
    1559                 :            : {
    1560                 :        134 :     rtl::OUStringBuffer aBuffer( pArr->GetLen() * 5 );
    1561         [ +  - ]:        134 :     CreateStringFromTokenArray( aBuffer );
    1562 [ +  - ][ +  - ]:        134 :     rFormula = aBuffer.makeStringAndClear();
    1563                 :        134 : }
    1564                 :            : 
    1565                 :        283 : void FormulaCompiler::CreateStringFromTokenArray( rtl::OUStringBuffer& rBuffer )
    1566                 :            : {
    1567                 :        283 :     rBuffer.setLength(0);
    1568         [ -  + ]:        283 :     if( !pArr->GetLen() )
    1569                 :        283 :         return;
    1570                 :            : 
    1571                 :        283 :     FormulaTokenArray* pSaveArr = pArr;
    1572                 :        283 :     bool bODFF = FormulaGrammar::isODFF( meGrammar);
    1573 [ +  + ][ +  + ]:        283 :     if (bODFF || FormulaGrammar::isPODF( meGrammar) )
                 [ +  + ]
    1574                 :            :     {
    1575                 :            :         // Scan token array for missing args and re-write if present.
    1576                 :        146 :         MissingConvention aConv( bODFF);
    1577 [ -  + ][ +  - ]:        146 :         if (pArr->NeedsPofRewrite( aConv))
    1578         [ #  # ]:        146 :             pArr = pArr->RewriteMissingToPof( aConv);
    1579                 :            :     }
    1580                 :            : 
    1581                 :            :     // At least one character per token, plus some are references, some are
    1582                 :            :     // function names, some are numbers, ...
    1583                 :        283 :     rBuffer.ensureCapacity( pArr->GetLen() * 5 );
    1584                 :            : 
    1585         [ -  + ]:        283 :     if ( pArr->IsRecalcModeForced() )
    1586                 :          0 :         rBuffer.append(sal_Unicode('='));
    1587                 :        283 :     FormulaToken* t = pArr->First();
    1588         [ +  + ]:        822 :     while( t )
    1589                 :        539 :         t = CreateStringFromToken( rBuffer, t, true );
    1590                 :            : 
    1591         [ -  + ]:        283 :     if (pSaveArr != pArr)
    1592                 :            :     {
    1593         [ #  # ]:          0 :         delete pArr;
    1594                 :          0 :         pArr = pSaveArr;
    1595                 :            :     }
    1596                 :            : }
    1597                 :            : // -----------------------------------------------------------------------------
    1598                 :      24861 : FormulaToken* FormulaCompiler::CreateStringFromToken( String& rFormula, FormulaToken* pTokenP,bool bAllowArrAdvance )
    1599                 :            : {
    1600                 :      24861 :     rtl::OUStringBuffer aBuffer;
    1601         [ +  - ]:      24861 :     FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
    1602 [ +  - ][ +  - ]:      24861 :     rFormula += aBuffer.makeStringAndClear();
    1603                 :      24861 :     return p;
    1604                 :            : }
    1605                 :            : 
    1606                 :      25400 : FormulaToken* FormulaCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP,bool bAllowArrAdvance )
    1607                 :            : {
    1608                 :      25400 :     bool bNext = true;
    1609                 :      25400 :     bool bSpaces = false;
    1610                 :      25400 :     FormulaToken* t = pTokenP;
    1611                 :      25400 :     OpCode eOp = t->GetOpCode();
    1612 [ -  + ][ +  + ]:      25400 :     if( eOp >= ocAnd && eOp <= ocOr )
    1613                 :            :     {
    1614                 :            :         // AND, OR infix?
    1615         [ #  # ]:          0 :         if ( bAllowArrAdvance )
    1616                 :          0 :             t = pArr->Next();
    1617                 :            :         else
    1618                 :          0 :             t = pArr->PeekNext();
    1619                 :          0 :         bNext = false;
    1620 [ #  # ][ #  # ]:          0 :         bSpaces = ( !t || t->GetOpCode() != ocOpen );
    1621                 :            :     }
    1622         [ -  + ]:      25400 :     if( bSpaces )
    1623                 :          0 :         rBuffer.append(sal_Unicode(' '));
    1624                 :            : 
    1625         [ +  + ]:      25400 :     if( eOp == ocSpaces )
    1626                 :            :     {
    1627                 :          8 :         bool bIntersectionOp = mxSymbols->isODFF();
    1628         [ -  + ]:          8 :         if (bIntersectionOp)
    1629                 :            :         {
    1630                 :          0 :             const FormulaToken* p = pArr->PeekPrevNoSpaces();
    1631 [ #  # ][ #  # ]:          0 :             bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
    1632         [ #  # ]:          0 :             if (bIntersectionOp)
    1633                 :            :             {
    1634                 :          0 :                 p = pArr->PeekNextNoSpaces();
    1635 [ #  # ][ #  # ]:          0 :                 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
    1636                 :            :             }
    1637                 :            :         }
    1638         [ -  + ]:          8 :         if (bIntersectionOp)
    1639                 :          0 :             rBuffer.appendAscii( "!!");
    1640                 :            :         else
    1641                 :            :         {
    1642                 :            :             // most times it's just one blank
    1643                 :          8 :             sal_uInt8 n = t->GetByte();
    1644         [ +  + ]:         16 :             for ( sal_uInt8 j=0; j<n; ++j )
    1645                 :            :             {
    1646                 :          8 :                 rBuffer.append(sal_Unicode(' '));
    1647                 :            :             }
    1648                 :            :         }
    1649                 :            :     }
    1650 [ -  + ][ #  # ]:      25392 :     else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
    1651                 :          0 :         rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
    1652         [ +  - ]:      25392 :     else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount())        // Keyword:
    1653         [ +  - ]:      25392 :         rBuffer.append(mxSymbols->getSymbol(eOp));
    1654                 :            :     else
    1655                 :            :     {
    1656                 :            :         SAL_WARN( "formula.core","unknown OpCode");
    1657         [ #  # ]:          0 :         rBuffer.append(GetNativeSymbol( ocErrName ));
    1658                 :            :     }
    1659         [ +  - ]:      25400 :     if( bNext )
    1660                 :            :     {
    1661         [ +  + ]:      25400 :         if (t->IsExternalRef())
    1662                 :            :         {
    1663                 :         11 :             CreateStringFromExternal(rBuffer, pTokenP);
    1664                 :            :         }
    1665                 :            :         else
    1666                 :            :         {
    1667   [ +  +  +  +  :      25389 :             switch( t->GetType() )
          -  +  -  -  +  
                      - ]
    1668                 :            :             {
    1669                 :            :             case svDouble:
    1670                 :         30 :                 AppendDouble( rBuffer, t->GetDouble() );
    1671                 :         30 :             break;
    1672                 :            : 
    1673                 :            :             case svString:
    1674 [ +  + ][ +  + ]:        105 :                 if( eOp == ocBad || eOp == ocStringXML )
    1675         [ +  - ]:         96 :                     rBuffer.append(t->GetString());
    1676                 :            :                 else
    1677                 :          9 :                     AppendString( rBuffer, t->GetString() );
    1678                 :        105 :                 break;
    1679                 :            :             case svSingleRef:
    1680                 :      12382 :                 CreateStringFromSingleRef(rBuffer,t);
    1681                 :      12382 :                 break;
    1682                 :            :             case svDoubleRef:
    1683                 :      12675 :                 CreateStringFromDoubleRef(rBuffer,t);
    1684                 :      12675 :                 break;
    1685                 :            :             case svMatrix:
    1686                 :          0 :                 CreateStringFromMatrix( rBuffer, t );
    1687                 :          0 :                 break;
    1688                 :            : 
    1689                 :            :             case svIndex:
    1690                 :         16 :                 CreateStringFromIndex( rBuffer, t );
    1691                 :         16 :                 break;
    1692                 :            :             case svExternal:
    1693                 :            :             {
    1694                 :            :                 // mapped or translated name of AddIns
    1695 [ #  # ][ #  # ]:          0 :                 String aAddIn( t->GetExternal() );
    1696                 :          0 :                 bool bMapped = mxSymbols->isPODF();     // ODF 1.1 directly uses programmatical name
    1697 [ #  # ][ #  # ]:          0 :                 if (!bMapped && mxSymbols->hasExternals())
         [ #  # ][ #  # ]
    1698                 :            :                 {
    1699         [ #  # ]:          0 :                     ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
    1700 [ #  # ][ #  # ]:          0 :                     if (iLook != mxSymbols->getReverseExternalHashMap()->end())
    1701                 :            :                     {
    1702 [ #  # ][ #  # ]:          0 :                         aAddIn = (*iLook).second;
    1703                 :          0 :                         bMapped = true;
    1704                 :            :                     }
    1705                 :            :                 }
    1706 [ #  # ][ #  # ]:          0 :                 if (!bMapped && !mxSymbols->isEnglish())
                 [ #  # ]
    1707         [ #  # ]:          0 :                         LocalizeString( aAddIn );
    1708 [ #  # ][ #  # ]:          0 :                     rBuffer.append(aAddIn);
                 [ #  # ]
    1709                 :            :                 }
    1710                 :          0 :             break;
    1711                 :            :             case svError:
    1712                 :          0 :                 AppendErrorConstant( rBuffer, t->GetError());
    1713                 :          0 :             break;
    1714                 :            :             case svByte:
    1715                 :            :             case svJump:
    1716                 :            :             case svFAP:
    1717                 :            :             case svMissing:
    1718                 :            :             case svSep:
    1719                 :      25400 :                 break;      // Opcodes
    1720                 :            :             default:
    1721                 :            :                 OSL_FAIL("FormulaCompiler:: GetStringFromToken errUnknownVariable");
    1722                 :            :             } // of switch
    1723                 :            :         }
    1724                 :            :     }
    1725         [ -  + ]:      25400 :     if( bSpaces )
    1726                 :          0 :         rBuffer.append(sal_Unicode(' '));
    1727         [ +  + ]:      25400 :     if ( bAllowArrAdvance )
    1728                 :            :     {
    1729         [ +  - ]:        539 :         if( bNext )
    1730                 :        539 :             t = pArr->Next();
    1731                 :        539 :         return t;
    1732                 :            :     }
    1733                 :      25400 :     return pTokenP;
    1734                 :            : }
    1735                 :            : // -----------------------------------------------------------------------------
    1736                 :            : 
    1737                 :         30 : void FormulaCompiler::AppendDouble( rtl::OUStringBuffer& rBuffer, double fVal )
    1738                 :            : {
    1739         [ +  + ]:         30 :     if ( mxSymbols->isEnglish() )
    1740                 :            :     {
    1741                 :            :         ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
    1742                 :            :                 rtl_math_StringFormat_Automatic,
    1743                 :          6 :                 rtl_math_DecimalPlaces_Max, '.', true );
    1744                 :            :     }
    1745                 :            :     else
    1746                 :            :     {
    1747         [ +  - ]:         24 :         SvtSysLocale aSysLocale;
    1748                 :            :         ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
    1749                 :            :                 rtl_math_StringFormat_Automatic,
    1750                 :            :                 rtl_math_DecimalPlaces_Max,
    1751 [ +  - ][ +  - ]:         24 :                 aSysLocale.GetLocaleDataPtr()->getNumDecimalSep()[0],
    1752         [ +  - ]:         24 :                 true );
    1753                 :            :     }
    1754                 :         30 : }
    1755                 :            : // -----------------------------------------------------------------------------
    1756                 :          0 : void FormulaCompiler::AppendBoolean( rtl::OUStringBuffer& rBuffer, bool bVal )
    1757                 :            : {
    1758 [ #  # ][ #  # ]:          0 :     rBuffer.append( mxSymbols->getSymbol(static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
    1759                 :          0 : }
    1760                 :            : // -----------------------------------------------------------------------------
    1761                 :          9 : void FormulaCompiler::AppendString( rtl::OUStringBuffer& rBuffer, const String & rStr )
    1762                 :            : {
    1763                 :          9 :     rBuffer.append(sal_Unicode('"'));
    1764         [ +  - ]:          9 :     if ( lcl_UnicodeStrChr( rStr.GetBuffer(), '"' ) == NULL )
    1765         [ +  - ]:          9 :         rBuffer.append( rStr );
    1766                 :            :     else
    1767                 :            :     {
    1768         [ #  # ]:          0 :         String aStr( rStr );
    1769 [ #  # ][ #  # ]:          0 :         aStr.SearchAndReplaceAll( rtl::OUString('"'), rtl::OUString("\"\"") );
         [ #  # ][ #  # ]
                 [ #  # ]
    1770 [ #  # ][ #  # ]:          0 :         rBuffer.append(aStr);
                 [ #  # ]
    1771                 :            :     }
    1772                 :          9 :     rBuffer.append(sal_Unicode('"'));
    1773                 :          9 : }
    1774                 :            : 
    1775                 :        412 : void FormulaCompiler::UpdateSeparatorsNative(
    1776                 :            :     const rtl::OUString& rSep, const rtl::OUString& rArrayColSep, const rtl::OUString& rArrayRowSep )
    1777                 :            : {
    1778         [ +  - ]:        412 :     NonConstOpCodeMapPtr xSymbolsNative;
    1779         [ +  - ]:        412 :     lcl_fillNativeSymbols(xSymbolsNative);
    1780 [ +  - ][ +  - ]:        412 :     xSymbolsNative->putOpCode(rSep, ocSep);
                 [ +  - ]
    1781 [ +  - ][ +  - ]:        412 :     xSymbolsNative->putOpCode(rArrayColSep, ocArrayColSep);
                 [ +  - ]
    1782 [ +  - ][ +  - ]:        412 :     xSymbolsNative->putOpCode(rArrayRowSep, ocArrayRowSep);
         [ +  - ][ +  - ]
    1783                 :        412 : }
    1784                 :            : 
    1785                 :        412 : void FormulaCompiler::ResetNativeSymbols()
    1786                 :            : {
    1787         [ +  - ]:        412 :     NonConstOpCodeMapPtr xSymbolsNative;
    1788         [ +  - ]:        412 :     lcl_fillNativeSymbols(xSymbolsNative, true);
    1789 [ +  - ][ +  - ]:        412 :     lcl_fillNativeSymbols(xSymbolsNative);
    1790                 :        412 : }
    1791                 :            : 
    1792                 :          0 : void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr& xMap )
    1793                 :            : {
    1794         [ #  # ]:          0 :     NonConstOpCodeMapPtr xSymbolsNative;
    1795         [ #  # ]:          0 :     lcl_fillNativeSymbols(xSymbolsNative);
    1796 [ #  # ][ #  # ]:          0 :     xSymbolsNative->copyFrom(*xMap);
    1797                 :          0 : }
    1798                 :            : 
    1799                 :            : // -----------------------------------------------------------------------------
    1800                 :      70787 : OpCode FormulaCompiler::NextToken()
    1801                 :            : {
    1802         [ +  + ]:      70787 :     if( !GetToken() )
    1803                 :       3839 :         return ocStop;
    1804                 :      66948 :     OpCode eOp = mpToken->GetOpCode();
    1805                 :            :     // There must be an operator before a push
    1806 [ -  + ][ +  + ]:      66948 :     if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
                 [ +  + ]
    1807                 :            :             !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
    1808 [ +  + ][ +  - ]:       9766 :                 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
                 [ -  + ]
    1809                 :          0 :         SetError(errOperatorExpected);
    1810                 :            :     // Operator and Plus => operator
    1811 [ +  + ][ +  - ]:      66948 :     if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
         [ +  - ][ -  + ]
                 [ #  # ]
    1812                 :            :                 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
    1813                 :          0 :         eOp = NextToken();
    1814                 :            :     else
    1815                 :            :     {
    1816                 :            :         // Before an operator there must not be another operator, with the
    1817                 :            :         // exception of AND and OR.
    1818 [ +  + ][ +  + ]:      66948 :         if ( eOp != ocAnd && eOp != ocOr &&
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
    1819                 :            :                 (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP )
    1820                 :            :                 && (eLastOp == ocOpen || eLastOp == ocSep ||
    1821                 :            :                     (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
    1822                 :            :         {
    1823                 :          0 :             SetError(errVariableExpected);
    1824 [ #  # ][ #  # ]:          0 :             if ( bAutoCorrect && !pStack )
    1825                 :            :             {
    1826 [ #  # ][ #  # ]:          0 :                 if ( eOp == eLastOp || eLastOp == ocOpen )
    1827                 :            :                 {   // throw away duplicated operator
    1828                 :          0 :                     aCorrectedSymbol.Erase();
    1829                 :          0 :                     bCorrected = true;
    1830                 :            :                 }
    1831                 :            :                 else
    1832                 :            :                 {
    1833                 :          0 :                     xub_StrLen nPos = aCorrectedFormula.Len();
    1834         [ #  # ]:          0 :                     if ( nPos )
    1835                 :            :                     {
    1836                 :          0 :                         nPos--;
    1837                 :          0 :                         sal_Unicode c = aCorrectedFormula.GetChar( nPos );
    1838   [ #  #  #  #  :          0 :                         switch ( eOp )
                      # ]
    1839                 :            :                         {   // swap operators
    1840                 :            :                             case ocGreater:
    1841         [ #  # ]:          0 :                                 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
    1842                 :            :                                 {   // >= instead of =>
    1843                 :            :                                     aCorrectedFormula.SetChar( nPos,
    1844                 :          0 :                                         mxSymbols->getSymbol(ocGreater).GetChar(0) );
    1845                 :          0 :                                     aCorrectedSymbol = c;
    1846                 :          0 :                                     bCorrected = true;
    1847                 :            :                                 }
    1848                 :          0 :                             break;
    1849                 :            :                             case ocLess:
    1850         [ #  # ]:          0 :                                 if ( c == mxSymbols->getSymbol(ocEqual).GetChar(0) )
    1851                 :            :                                 {   // <= instead of =<
    1852                 :            :                                     aCorrectedFormula.SetChar( nPos,
    1853                 :          0 :                                         mxSymbols->getSymbol(ocLess).GetChar(0) );
    1854                 :          0 :                                     aCorrectedSymbol = c;
    1855                 :          0 :                                     bCorrected = true;
    1856                 :            :                                 }
    1857         [ #  # ]:          0 :                                 else if ( c == mxSymbols->getSymbol(ocGreater).GetChar(0) )
    1858                 :            :                                 {   // <> instead of ><
    1859                 :            :                                     aCorrectedFormula.SetChar( nPos,
    1860                 :          0 :                                         mxSymbols->getSymbol(ocLess).GetChar(0) );
    1861                 :          0 :                                     aCorrectedSymbol = c;
    1862                 :          0 :                                     bCorrected = true;
    1863                 :            :                                 }
    1864                 :          0 :                             break;
    1865                 :            :                             case ocMul:
    1866         [ #  # ]:          0 :                                 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
    1867                 :            :                                 {   // *- instead of -*
    1868                 :            :                                     aCorrectedFormula.SetChar( nPos,
    1869                 :          0 :                                         mxSymbols->getSymbol(ocMul).GetChar(0) );
    1870                 :          0 :                                     aCorrectedSymbol = c;
    1871                 :          0 :                                     bCorrected = true;
    1872                 :            :                                 }
    1873                 :          0 :                             break;
    1874                 :            :                             case ocDiv:
    1875         [ #  # ]:          0 :                                 if ( c == mxSymbols->getSymbol(ocSub).GetChar(0) )
    1876                 :            :                                 {   // /- instead of -/
    1877                 :            :                                     aCorrectedFormula.SetChar( nPos,
    1878                 :          0 :                                         mxSymbols->getSymbol(ocDiv).GetChar(0) );
    1879                 :          0 :                                     aCorrectedSymbol = c;
    1880                 :          0 :                                     bCorrected = true;
    1881                 :            :                                 }
    1882                 :          0 :                             break;
    1883                 :            :                             default:
    1884                 :            :                                 ;   // nothing
    1885                 :            :                         }
    1886                 :            :                     }
    1887                 :            :                 }
    1888                 :            :             }
    1889                 :            :         }
    1890                 :      66948 :         eLastOp = eOp;
    1891                 :            :     }
    1892                 :      70787 :     return eOp;
    1893                 :            : }
    1894                 :      36859 : void FormulaCompiler::PutCode( FormulaTokenRef& p )
    1895                 :            : {
    1896         [ -  + ]:      36859 :     if( pc >= MAXCODE-1 )
    1897                 :            :     {
    1898         [ #  # ]:          0 :         if ( pc == MAXCODE-1 )
    1899                 :            :         {
    1900         [ #  # ]:          0 :             p = new FormulaByteToken( ocStop );
    1901                 :          0 :             p->IncRef();
    1902                 :          0 :             *pCode++ = p.get();
    1903                 :          0 :             ++pc;
    1904                 :            :         }
    1905                 :          0 :         SetError(errCodeOverflow);
    1906                 :          0 :         return;
    1907                 :            :     }
    1908 [ -  + ][ #  # ]:      36859 :     if( pArr->GetCodeError() && !bCompileForFAP )
                 [ -  + ]
    1909                 :          0 :         return;
    1910                 :      36859 :     ForceArrayOperator( p, pCurrentFactorToken);
    1911                 :      36859 :     p->IncRef();
    1912                 :      36859 :     *pCode++ = p.get();
    1913                 :      36859 :     pc++;
    1914                 :            : }
    1915                 :            : 
    1916                 :            : // -----------------------------------------------------------------------------
    1917                 :          0 : bool FormulaCompiler::HandleExternalReference(const FormulaToken& /*_aToken*/)
    1918                 :            : {
    1919                 :          0 :     return true;
    1920                 :            : }
    1921                 :            : // -----------------------------------------------------------------------------
    1922                 :          0 : bool FormulaCompiler::HandleRange()
    1923                 :            : {
    1924                 :          0 :     return true;
    1925                 :            : }
    1926                 :            : // -----------------------------------------------------------------------------
    1927                 :          0 : bool FormulaCompiler::HandleSingleRef()
    1928                 :            : {
    1929                 :          0 :     return true;
    1930                 :            : }
    1931                 :            : // -----------------------------------------------------------------------------
    1932                 :          0 : bool FormulaCompiler::HandleDbData()
    1933                 :            : {
    1934                 :          0 :     return true;
    1935                 :            : }
    1936                 :            : // -----------------------------------------------------------------------------
    1937                 :          0 : void FormulaCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1938                 :            : {
    1939                 :          0 : }
    1940                 :            : // -----------------------------------------------------------------------------
    1941                 :          0 : void FormulaCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1942                 :            : {
    1943                 :          0 : }
    1944                 :            : // -----------------------------------------------------------------------------
    1945                 :          0 : void FormulaCompiler::CreateStringFromIndex(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1946                 :            : {
    1947                 :          0 : }
    1948                 :            : // -----------------------------------------------------------------------------
    1949                 :          0 : void FormulaCompiler::CreateStringFromMatrix(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1950                 :            : {
    1951                 :          0 : }
    1952                 :            : // -----------------------------------------------------------------------------
    1953                 :          0 : void FormulaCompiler::CreateStringFromExternal(rtl::OUStringBuffer& /*rBuffer*/,FormulaToken* /*pTokenP*/)
    1954                 :            : {
    1955                 :          0 : }
    1956                 :            : // -----------------------------------------------------------------------------
    1957                 :          0 : void FormulaCompiler::LocalizeString( String& /*rName*/ )
    1958                 :            : {
    1959                 :          0 : }
    1960                 :        284 : void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
    1961                 :            : {
    1962 [ -  + ][ #  # ]:        284 :     if ( bAutoCorrect && !pStack )
    1963                 :            :         {   // don't merge stacked subroutine code into entered formula
    1964                 :          0 :         aCorrectedFormula += aCorrectedSymbol;
    1965                 :          0 :         aCorrectedSymbol.Erase();
    1966                 :            :     }
    1967                 :        284 :     FormulaArrayStack* p = new FormulaArrayStack;
    1968                 :        284 :     p->pNext      = pStack;
    1969                 :        284 :     p->pArr       = pArr;
    1970                 :        284 :     p->bTemp      = bTemp;
    1971                 :        284 :     pStack        = p;
    1972                 :        284 :     pArr          = pa;
    1973                 :        284 : }
    1974                 :            : 
    1975                 :            : // =============================================================================
    1976                 :            : } // formula
    1977                 :            : // =============================================================================
    1978                 :            : 
    1979                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10