LCOV - code coverage report
Current view: top level - formula/source/core/api - FormulaCompiler.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 740 1071 69.1 %
Date: 2014-11-03 Functions: 69 95 72.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10