LCOV - code coverage report
Current view: top level - formula/source/core/api - FormulaCompiler.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 702 1062 66.1 %
Date: 2014-04-11 Functions: 66 92 71.7 %
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       62481 :                                 FormulaCompilerRecursionGuard( short& rRec )
      52       62481 :                                     : rRecursion( rRec ) { ++rRecursion; }
      53       62481 :                                 ~FormulaCompilerRecursionGuard() { --rRecursion; }
      54             : };
      55             : 
      56        2823 : short lcl_GetRetFormat( OpCode eOpCode )
      57             : {
      58        2823 :     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         138 :             return NUMBERFORMAT_LOGICAL;
      86             :         case ocGetActDate:
      87             :         case ocGetDate:
      88             :         case ocEasterSunday :
      89           0 :             return NUMBERFORMAT_DATE;
      90             :         case ocGetActTime:
      91           3 :             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          36 :             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          16 :             return NUMBERFORMAT_PERCENT;
     116             :         default:
     117        2630 :             return NUMBERFORMAT_NUMBER;
     118             :     }
     119             : }
     120             : 
     121       22736 : inline void lclPushOpCodeMapEntry( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
     122             :         const OUString* pTable, sal_uInt16 nOpCode )
     123             : {
     124       22736 :     sheet::FormulaOpCodeMapEntry aEntry;
     125       22736 :     aEntry.Token.OpCode = nOpCode;
     126       22736 :     aEntry.Name = pTable[nOpCode];
     127       22736 :     rVec.push_back( aEntry);
     128       22736 : }
     129             : 
     130         116 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
     131             :         const OUString* pTable, sal_uInt16 nOpCodeBeg, sal_uInt16 nOpCodeEnd )
     132             : {
     133        5394 :     for (sal_uInt16 nOpCode = nOpCodeBeg; nOpCode < nOpCodeEnd; ++nOpCode)
     134        5278 :         lclPushOpCodeMapEntry( rVec, pTable, nOpCode );
     135         116 : }
     136             : 
     137         174 : void lclPushOpCodeMapEntries( ::std::vector< sheet::FormulaOpCodeMapEntry >& rVec,
     138             :         const OUString* pTable, const sal_uInt16* pnOpCodes, size_t nCount )
     139             : {
     140        1044 :     for (const sal_uInt16* pnEnd = pnOpCodes + nCount; pnOpCodes < pnEnd; ++pnOpCodes)
     141         870 :         lclPushOpCodeMapEntry( rVec, pTable, *pnOpCodes );
     142         174 : }
     143             : 
     144         428 : 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         428 : OpCodeList::OpCodeList( sal_uInt16 nRID, FormulaCompiler::NonConstOpCodeMapPtr xMap,
     160             :         FormulaCompiler::SeparatorType eSepType ) :
     161         428 :     Resource( ResId( nRID, *ResourceManager::getResManager()))
     162         428 :     , meSepType( eSepType)
     163             : {
     164         428 :     if (meSepType == FormulaCompiler::RESOURCE_BASE)
     165             :     {
     166       14601 :         for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
     167             :         {
     168       14570 :             putDefaultOpCode( xMap, i);
     169             :         }
     170             :     }
     171             :     else
     172             :     {
     173      186987 :         for (sal_uInt16 i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; ++i)
     174             :         {
     175      186590 :             OUString aOpStr;
     176      186590 :             if ( getOpCodeString( aOpStr, i) )
     177        1191 :                 xMap->putOpCode( aOpStr, OpCode(i));
     178             :             else
     179      185399 :                 putDefaultOpCode( xMap, i);
     180      186590 :         }
     181             :     }
     182             : 
     183         428 :     FreeResource();
     184         428 : }
     185             : 
     186      186590 : bool OpCodeList::getOpCodeString( OUString& rStr, sal_uInt16 nOp )
     187             : {
     188      186590 :     switch (nOp)
     189             :     {
     190             :         case SC_OPCODE_SEP:
     191             :         {
     192         397 :             if (meSepType == FormulaCompiler::COMMA_BASE)
     193             :             {
     194           0 :                 rStr = ",";
     195           0 :                 return true;
     196             :             }
     197         397 :             else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
     198             :             {
     199         397 :                 rStr = ";";
     200         397 :                 return true;
     201             :             }
     202             :         }
     203           0 :         break;
     204             :         case SC_OPCODE_ARRAY_COL_SEP:
     205             :         {
     206         397 :             if (meSepType == FormulaCompiler::COMMA_BASE)
     207             :             {
     208           0 :                 rStr = ",";
     209           0 :                 return true;
     210             :             }
     211         397 :             else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
     212             :             {
     213         397 :                 rStr = ";";
     214         397 :                 return true;
     215             :             }
     216             :         }
     217           0 :         break;
     218             :         case SC_OPCODE_ARRAY_ROW_SEP:
     219             :         {
     220         397 :             if (meSepType == FormulaCompiler::COMMA_BASE)
     221             :             {
     222           0 :                 rStr = ";";
     223           0 :                 return true;
     224             :             }
     225         397 :             else if (meSepType == FormulaCompiler::SEMICOLON_BASE)
     226             :             {
     227         397 :                 rStr = "|";
     228         397 :                 return true;
     229             :             }
     230             :         }
     231           0 :         break;
     232             :     }
     233             : 
     234      185399 :     return false;
     235             : }
     236             : 
     237      199969 : void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap, sal_uInt16 nOp )
     238             : {
     239      199969 :     ResId aRes( nOp, *ResourceManager::getResManager());
     240      199969 :     aRes.SetRT( RSC_STRING);
     241      199969 :     if (IsAvailableRes( aRes))
     242      168297 :         xMap->putOpCode( aRes.toString(), OpCode( nOp));
     243      199969 : }
     244             : 
     245             : // static
     246          60 : const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr, sal_Unicode c )
     247             : {
     248          60 :     if ( !pStr )
     249           0 :         return NULL;
     250         348 :     while ( *pStr )
     251             :     {
     252         228 :         if ( *pStr == c )
     253           0 :             return pStr;
     254         228 :         pStr++;
     255             :     }
     256          60 :     return NULL;
     257             : }
     258             : 
     259         136 : struct OpCodeMapData
     260             : {
     261             :     FormulaCompiler::NonConstOpCodeMapPtr mxSymbolMap;
     262             :     osl::Mutex maMtx;
     263             : };
     264             : 
     265             : 
     266             : } // namespace
     267             : 
     268             : 
     269       10707 : 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       10707 :     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       10707 :     if (bOk)
     278             :     {
     279       10707 :         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       10707 : }
     285             : 
     286        1877 : void FormulaCompiler::OpCodeMap::putExternalSoftly( const OUString & rSymbol, const OUString & rAddIn )
     287             : {
     288        1877 :     bool bOk = mpReverseExternalHashMap->insert( ExternalHashMap::value_type( rAddIn, rSymbol)).second;
     289        1877 :     if (bOk)
     290          24 :         mpExternalHashMap->insert( ExternalHashMap::value_type( rSymbol, rAddIn));
     291        1877 : }
     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         348 : 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         348 :     ::std::vector< FormulaOpCodeMapEntry > aVec;
     340             : 
     341         348 :     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          58 :         const size_t nCount = sizeof(aMap)/sizeof(aMap[0]);
     365             :         // Preallocate vector elements.
     366          58 :         if (aVec.size() < nCount)
     367             :         {
     368          58 :             FormulaOpCodeMapEntry aEntry;
     369          58 :             aEntry.Token.OpCode = getOpCodeUnknown();
     370          58 :             aVec.resize( nCount, aEntry);
     371             :         } // if (aVec.size() < nCount)
     372             : 
     373          58 :         FormulaOpCodeMapEntry aEntry;
     374         812 :         for (size_t i=0; i < nCount; ++i)
     375             :         {
     376         754 :             size_t nIndex = static_cast< size_t >( aMap[i].nOff );
     377         754 :             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         754 :             aEntry.Token.OpCode = aMap[i].eOp;
     387         754 :             aVec[nIndex] = aEntry;
     388          58 :         }
     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         290 :         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          58 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     405             :         }
     406         290 :         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          58 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     415             :         }
     416         290 :         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          58 :             lclPushOpCodeMapEntry( aVec, mpTable, ocPercentSign );
     421             :             // "+" can be used as unary operator too, push only if binary group is not set
     422          58 :             if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) == 0)
     423          58 :                 lclPushOpCodeMapEntry( aVec, mpTable, ocAdd );
     424             :             // regular unary operators
     425         232 :             for (sal_uInt16 nOp = SC_OPCODE_START_UN_OP; nOp < SC_OPCODE_STOP_UN_OP && nOp < mnSymbols; ++nOp)
     426             :             {
     427         174 :                 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         116 :                         break;   // nothing,
     434             :                     default:
     435          58 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     436             :                 }
     437             :             }
     438             :         }
     439         290 :         if ((nGroups & FormulaMapGroup::BINARY_OPERATORS) != 0)
     440             :         {
     441        1044 :             for (sal_uInt16 nOp = SC_OPCODE_START_BIN_OP; nOp < SC_OPCODE_STOP_BIN_OP && nOp < mnSymbols; ++nOp)
     442             :             {
     443         986 :                 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         116 :                         break;   // nothing,
     450             :                     default:
     451         870 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     452             :                 }
     453             :             }
     454             :         }
     455         290 :         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          58 :                     ::std::min< sal_uInt16 >( SC_OPCODE_STOP_NO_PAR, mnSymbols ) );
     461             :             lclPushOpCodeMapEntries( aVec, mpTable, SC_OPCODE_START_1_PAR,
     462          58 :                     ::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          58 :             lclPushOpCodeMapEntries( aVec, mpTable, aOpCodes, sizeof(aOpCodes)/sizeof(aOpCodes[0]) );
     475             :             // functions with 2 or more parameters.
     476       15660 :             for (sal_uInt16 nOp = SC_OPCODE_START_2_PAR; nOp < SC_OPCODE_STOP_2_PAR && nOp < mnSymbols; ++nOp)
     477             :             {
     478       15602 :                 switch (nOp)
     479             :                 {
     480             :                     // NO_NAME is in SPECIAL.
     481             :                     case SC_OPCODE_NO_NAME :
     482          58 :                         break;   // nothing,
     483             :                     default:
     484       15544 :                         lclPushOpCodeMapEntry( aVec, mpTable, nOp );
     485             :                 }
     486             :             }
     487             :             // If AddIn functions are present in this mapping, use them, and only those.
     488          58 :             if (hasExternals())
     489             :             {
     490        6380 :                 for (ExternalHashMap::const_iterator it( mpExternalHashMap->begin());it != mpExternalHashMap->end(); ++it)
     491             :                 {
     492        6322 :                     FormulaOpCodeMapEntry aEntry;
     493        6322 :                     aEntry.Name = (*it).first;
     494        6322 :                     aEntry.Token.Data <<= OUString( (*it).second);
     495        6322 :                     aEntry.Token.OpCode = ocExternal;
     496        6322 :                     aVec.push_back( aEntry);
     497        6322 :                 }
     498             :             }
     499             :             else
     500             :             {
     501           0 :                 rCompiler.fillAddInToken( aVec, isEnglish());
     502             :             }
     503             :         }
     504             :     }
     505         348 :     const FormulaOpCodeMapEntry* pRet = aVec.empty() ? 0 : &aVec[0];
     506         348 :     return uno::Sequence< FormulaOpCodeMapEntry >( pRet, aVec.size());
     507             : }
     508             : 
     509             : 
     510      193705 : 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      193705 :     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      193705 :         mpTable[eOp] = rStr;
     522      193705 :         mpHashMap->insert( OpCodeHashMap::value_type( rStr, eOp));
     523             :     }
     524      193705 : }
     525             : 
     526             : // class FormulaCompiler
     527             : 
     528        6608 : 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             :         bCompileForFAP( false ),
     541             :         bIgnoreErrors( false ),
     542        6608 :         glSubTotal( false )
     543             : 
     544             : {
     545        6608 : }
     546             : 
     547       29224 : FormulaCompiler::FormulaCompiler()
     548             :         :
     549             :         pArr( NULL ),
     550             :         pStack( NULL ),
     551             :         nRecursion(0),
     552             :         nNumFmt( NUMBERFORMAT_UNDEFINED ),
     553             :         meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ),
     554             :         bAutoCorrect( false ),
     555             :         bCorrected( false ),
     556             :         bCompileForFAP( false ),
     557       29224 :         bIgnoreErrors( false )
     558             : 
     559             : {
     560       29224 : }
     561             : 
     562       35833 : FormulaCompiler::~FormulaCompiler()
     563             : {
     564       35833 : }
     565             : 
     566       36309 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage ) const
     567             : {
     568       36309 :     FormulaCompiler::OpCodeMapPtr xMap;
     569             :     using namespace sheet;
     570       36309 :     switch (nLanguage)
     571             :     {
     572             :         case FormulaLanguage::ODFF :
     573        2514 :             if (!mxSymbolsODFF)
     574        2224 :                 InitSymbolsODFF();
     575        2514 :             xMap = mxSymbolsODFF;
     576        2514 :             break;
     577             :         case FormulaLanguage::ODF_11 :
     578         346 :             if (!mxSymbolsPODF)
     579         346 :                 InitSymbolsPODF();
     580         346 :             xMap = mxSymbolsPODF;
     581         346 :             break;
     582             :         case FormulaLanguage::ENGLISH :
     583         139 :             if (!mxSymbolsEnglish)
     584         139 :                 InitSymbolsEnglish();
     585         139 :             xMap = mxSymbolsEnglish;
     586         139 :             break;
     587             :         case FormulaLanguage::NATIVE :
     588       32898 :             if (!mxSymbolsNative)
     589       32830 :                 InitSymbolsNative();
     590       32898 :             xMap = mxSymbolsNative;
     591       32898 :             break;
     592             :         case FormulaLanguage::XL_ENGLISH:
     593         229 :             if (!mxSymbolsEnglishXL)
     594         229 :                 InitSymbolsEnglishXL();
     595         229 :             xMap = mxSymbolsEnglishXL;
     596         229 :             break;
     597             :         case FormulaLanguage::OOXML:
     598         183 :             if (!mxSymbolsOOXML)
     599         183 :                 InitSymbolsOOXML();
     600         183 :             xMap = mxSymbolsOOXML;
     601         183 :             break;
     602             :         default:
     603             :             ;   // nothing, NULL map returned
     604             :     }
     605       36309 :     return xMap;
     606             : }
     607             : 
     608           0 : OUString FormulaCompiler::FindAddInFunction( const OUString& /*rUpperName*/, bool /*bLocalFirst*/ ) const
     609             : {
     610           0 :     return OUString();
     611             : }
     612             : 
     613          58 : FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap(
     614             :         const uno::Sequence<
     615             :         const sheet::FormulaOpCodeMapEntry > & rMapping,
     616             :         bool bEnglish )
     617             : {
     618             :     using sheet::FormulaOpCodeMapEntry;
     619             :     // Filter / API maps are never Core
     620             :     NonConstOpCodeMapPtr xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, false,
     621             :                 FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(
     622          58 :                         FormulaGrammar::GRAM_EXTERNAL, bEnglish), FormulaGrammar::CONV_UNSPECIFIED)));
     623          58 :     FormulaOpCodeMapEntry const * pArr2 = rMapping.getConstArray();
     624          58 :     FormulaOpCodeMapEntry const * const pStop = pArr2 + rMapping.getLength();
     625       29092 :     for ( ; pArr2 < pStop; ++pArr2)
     626             :     {
     627       29034 :         OpCode eOp = OpCode(pArr2->Token.OpCode);
     628       29034 :         if (eOp != ocExternal)
     629       22360 :             xMap->putOpCode( pArr2->Name, eOp);
     630             :         else
     631             :         {
     632        6674 :             OUString aExternalName;
     633        6674 :             if (pArr2->Token.Data >>= aExternalName)
     634        6674 :                 xMap->putExternal( pArr2->Name, aExternalName);
     635             :             else
     636             :             {
     637             :                 SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
     638        6674 :             }
     639             :         }
     640             :     }
     641          58 :     return xMap;
     642             : }
     643             : 
     644       64704 : void lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& xMap, bool bDestroy = false )
     645             : {
     646       64704 :     static OpCodeMapData aSymbolMap;
     647       64704 :     osl::MutexGuard aGuard(&aSymbolMap.maMtx);
     648             : 
     649       64704 :     if ( bDestroy )
     650             :     {
     651         390 :         aSymbolMap.mxSymbolMap.reset();
     652             :     }
     653       64314 :     else if (!aSymbolMap.mxSymbolMap)
     654             :     {
     655             :         // Core
     656             :         aSymbolMap.mxSymbolMap.reset(
     657             :             new FormulaCompiler::OpCodeMap(
     658         391 :                 SC_OPCODE_LAST_OPCODE_ID + 1, true, FormulaGrammar::GRAM_NATIVE_UI));
     659         391 :         OModuleClient aModuleClient;
     660         391 :         OpCodeList aOpCodeListNative(RID_STRLIST_FUNCTION_NAMES, aSymbolMap.mxSymbolMap);
     661             :         // No AddInMap for native core mapping.
     662             :     }
     663             : 
     664       64704 :     xMap = aSymbolMap.mxSymbolMap;
     665       64704 : }
     666             : 
     667       30704 : const OUString& FormulaCompiler::GetNativeSymbol( OpCode eOp )
     668             : {
     669       30704 :     NonConstOpCodeMapPtr xSymbolsNative;
     670       30704 :     lcl_fillNativeSymbols( xSymbolsNative);
     671       30704 :     return xSymbolsNative->getSymbol( eOp );
     672             : }
     673             : 
     674       28493 : sal_Unicode FormulaCompiler::GetNativeSymbolChar( OpCode eOp )
     675             : {
     676       28493 :     return GetNativeSymbol(eOp)[0];
     677             : }
     678             : 
     679       32830 : void FormulaCompiler::InitSymbolsNative() const
     680             : {
     681       32830 :     lcl_fillNativeSymbols( mxSymbolsNative);
     682       32830 : }
     683             : 
     684         139 : void FormulaCompiler::InitSymbolsEnglish() const
     685             : {
     686         139 :     static OpCodeMapData aMap;
     687         139 :     osl::MutexGuard aGuard(&aMap.maMtx);
     688         139 :     if (!aMap.mxSymbolMap)
     689           3 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
     690         139 :     mxSymbolsEnglish = aMap.mxSymbolMap;
     691         139 : }
     692             : 
     693         346 : void FormulaCompiler::InitSymbolsPODF() const
     694             : {
     695         346 :     static OpCodeMapData aMap;
     696         346 :     osl::MutexGuard aGuard(&aMap.maMtx);
     697         346 :     if (!aMap.mxSymbolMap)
     698           7 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_PODF, aMap.mxSymbolMap, RESOURCE_BASE);
     699         346 :     mxSymbolsPODF = aMap.mxSymbolMap;
     700         346 : }
     701             : 
     702        2224 : void FormulaCompiler::InitSymbolsODFF() const
     703             : {
     704        2224 :     static OpCodeMapData aMap;
     705        2224 :     osl::MutexGuard aGuard(&aMap.maMtx);
     706        2224 :     if (!aMap.mxSymbolMap)
     707          21 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF, FormulaGrammar::GRAM_ODFF, aMap.mxSymbolMap, RESOURCE_BASE);
     708        2224 :     mxSymbolsODFF = aMap.mxSymbolMap;
     709        2224 : }
     710             : 
     711         229 : void FormulaCompiler::InitSymbolsEnglishXL() const
     712             : {
     713         229 :     static OpCodeMapData aMap;
     714         229 :     osl::MutexGuard aGuard(&aMap.maMtx);
     715         229 :     if (!aMap.mxSymbolMap)
     716           3 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap);
     717         229 :     mxSymbolsEnglishXL = aMap.mxSymbolMap;
     718             : 
     719             :     // TODO: For now, just replace the separators to the Excel English
     720             :     // variants. Later, if we want to properly map Excel functions with Calc
     721             :     // functions, we'll need to do a little more work here.
     722         229 :     mxSymbolsEnglishXL->putOpCode( OUString(','), ocSep);
     723         229 :     mxSymbolsEnglishXL->putOpCode( OUString(','), ocArrayColSep);
     724         229 :     mxSymbolsEnglishXL->putOpCode( OUString(';'), ocArrayRowSep);
     725         229 : }
     726             : 
     727         183 : void FormulaCompiler::InitSymbolsOOXML() const
     728             : {
     729         183 :     static OpCodeMapData aMap;
     730         183 :     osl::MutexGuard aGuard(&aMap.maMtx);
     731         183 :     if (!aMap.mxSymbolMap)
     732           3 :         loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML, FormulaGrammar::GRAM_OOXML, aMap.mxSymbolMap, RESOURCE_BASE);
     733         183 :     mxSymbolsOOXML = aMap.mxSymbolMap;
     734         183 : }
     735             : 
     736             : 
     737          37 : void FormulaCompiler::loadSymbols( sal_uInt16 nSymbols, FormulaGrammar::Grammar eGrammar,
     738             :         NonConstOpCodeMapPtr& rxMap, SeparatorType eSepType) const
     739             : {
     740          37 :     if ( !rxMap.get() )
     741             :     {
     742             :         // not Core
     743          37 :         rxMap.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID + 1, eGrammar != FormulaGrammar::GRAM_ODFF, eGrammar ));
     744          37 :         OModuleClient aModuleClient;
     745          74 :         OpCodeList aOpCodeList( nSymbols, rxMap, eSepType);
     746             : 
     747          37 :         fillFromAddInMap( rxMap, eGrammar);
     748             :         // Fill from collection for AddIns not already present.
     749          37 :         if ( FormulaGrammar::GRAM_ENGLISH != eGrammar )
     750          31 :             fillFromAddInCollectionUpperName( rxMap);
     751             :         else
     752          43 :             fillFromAddInCollectionEnglishName( rxMap);
     753             :     }
     754          37 : }
     755             : 
     756           0 : void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr /*xMap */) const
     757             : {
     758           0 : }
     759             : 
     760           0 : void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr /*xMap */) const
     761             : {
     762           0 : }
     763             : 
     764           0 : void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr /*xMap*/, FormulaGrammar::Grammar /*_eGrammar */) const
     765             : {
     766           0 : }
     767             : 
     768           0 : OpCode FormulaCompiler::GetEnglishOpCode( const OUString& rName ) const
     769             : {
     770           0 :     FormulaCompiler::OpCodeMapPtr xMap = GetOpCodeMap( sheet::FormulaLanguage::ENGLISH);
     771             : 
     772           0 :     formula::OpCodeHashMap::const_iterator iLook( xMap->getHashMap()->find( rName ) );
     773           0 :     bool bFound = (iLook != xMap->getHashMap()->end());
     774           0 :     return bFound ? (*iLook).second : OpCode(ocNone);
     775             : }
     776             : 
     777       13550 : bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp )
     778             : {
     779       13550 :     bool bRet = false;
     780       13550 :     switch (eOp)
     781             :     {
     782             :         // no parameters:
     783             :         case ocRandom:
     784             :         case ocGetActDate:
     785             :         case ocGetActTime:
     786             :         // one parameter:
     787             :         case ocFormula:
     788             :         case ocInfo:
     789             :         // more than one parameters:
     790             :             // ocIndirect/ocIndirectXL otherwise would have to do
     791             :             // StopListening and StartListening on a reference for every
     792             :             // interpreted value.
     793             :         case ocIndirect:
     794             :         case ocIndirectXL:
     795             :             // ocOffset results in indirect references.
     796             :         case ocOffset:
     797             :             // ocDebugVar shows internal value that may change as the internal state changes.
     798             :         case ocDebugVar:
     799          61 :             bRet = true;
     800          61 :             break;
     801             :         default:
     802       13489 :             bRet = false;
     803       13489 :             break;
     804             :     }
     805       13550 :     return bRet;
     806             : }
     807             : 
     808             : // Remove quotes, escaped quotes are unescaped.
     809          19 : bool FormulaCompiler::DeQuote( OUString& rStr )
     810             : {
     811          19 :     sal_Int32 nLen = rStr.getLength();
     812          19 :     if ( nLen > 1 && rStr[0] == '\'' && rStr[ nLen-1 ] == '\'' )
     813             :     {
     814           0 :         rStr = rStr.copy( 1, nLen-2 );
     815           0 :         rStr = rStr.replaceAll( "\\\'", "\'" );
     816           0 :         return true;
     817             :     }
     818          19 :     return false;
     819             : }
     820             : 
     821           0 : void FormulaCompiler::fillAddInToken(
     822             :         ::std::vector< sheet::FormulaOpCodeMapEntry >& /*_rVec*/,
     823             :         bool /*_bIsEnglish*/) const
     824             : {
     825           0 : }
     826             : 
     827           0 : bool FormulaCompiler::IsMatrixFunction( OpCode eOpCode )
     828             : {
     829           0 :     switch (eOpCode)
     830             :     {
     831             :         case ocDde :
     832             :         case ocGrowth :
     833             :         case ocTrend :
     834             :         case ocRKP :
     835             :         case ocRGP :
     836             :         case ocFrequency :
     837             :         case ocMatTrans :
     838             :         case ocMatMult :
     839             :         case ocMatInv :
     840             :         case ocMatrixUnit :
     841             :         case ocModalValue_Multi :
     842           0 :             return true;
     843             :         default:
     844             :         {
     845             :             // added to avoid warnings
     846             :         }
     847             :     }
     848           0 :     return false;
     849             : }
     850             : 
     851             : 
     852         972 : FormulaCompiler::OpCodeMap::~OpCodeMap()
     853             : {
     854         486 :     delete mpReverseExternalHashMap;
     855         486 :     delete mpExternalHashMap;
     856         486 :     delete [] mpTable;
     857         486 :     delete mpHashMap;
     858         972 : }
     859             : 
     860           0 : void FormulaCompiler::OpCodeMap::putCopyOpCode( const OUString& rSymbol, OpCode eOp )
     861             : {
     862             :     SAL_WARN_IF( !mpTable[eOp].isEmpty() && rSymbol.isEmpty(), "formula.core",
     863             :             "OpCodeMap::putCopyOpCode: NOT replacing OpCode " << eOp << " '" << mpTable[eOp] << "' with empty name!");
     864           0 :     if (!mpTable[eOp].isEmpty() && rSymbol.isEmpty())
     865           0 :         mpHashMap->insert( OpCodeHashMap::value_type( mpTable[eOp], eOp));
     866             :     else
     867             :     {
     868           0 :         mpTable[eOp] = rSymbol;
     869           0 :         mpHashMap->insert( OpCodeHashMap::value_type( rSymbol, eOp));
     870             :     }
     871           0 : }
     872             : 
     873           0 : void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap& r, bool bOverrideKnownBad )
     874             : {
     875           0 :     delete mpHashMap;
     876           0 :     mpHashMap = new OpCodeHashMap( mnSymbols);
     877             : 
     878           0 :     sal_uInt16 n = r.getSymbolCount();
     879             :     SAL_WARN_IF( n != mnSymbols, "formula.core",
     880             :             "OpCodeMap::copyFrom: unequal size, this: " << mnSymbols << "  that: " << n);
     881           0 :     if (n > mnSymbols)
     882           0 :         n = mnSymbols;
     883             : 
     884             :     // OpCode 0 (ocPush) should never be in a map.
     885             :     SAL_WARN_IF( !mpTable[0].isEmpty() || !r.mpTable[0].isEmpty(), "formula.core",
     886             :             "OpCodeMap::copyFrom: OpCode 0 assigned, this: '"
     887             :             << mpTable[0] << "'  that: '" << r.mpTable[0] << "'");
     888             : 
     889             :     // For bOverrideKnownBad when copying from the English core map (ODF 1.1
     890             :     // and API) to the native map (UI "use English function names") replace the
     891             :     // known bad legacy function names with correct ones.
     892           0 :     if (bOverrideKnownBad && r.mbCore &&
     893           0 :             FormulaGrammar::extractFormulaLanguage( meGrammar) == sheet::FormulaLanguage::NATIVE &&
     894           0 :             FormulaGrammar::extractFormulaLanguage( r.meGrammar) == sheet::FormulaLanguage::ENGLISH)
     895             :     {
     896           0 :         for (sal_uInt16 i = 1; i < n; ++i)
     897             :         {
     898           0 :             OUString aSymbol;
     899           0 :             OpCode eOp = OpCode(i);
     900           0 :             switch (eOp)
     901             :             {
     902             :                 case ocZGZ:
     903           0 :                     aSymbol = "RRI";
     904           0 :                     break;
     905             :                 case ocTableOp:
     906           0 :                     aSymbol = "MULTIPLE.OPERATIONS";
     907           0 :                     break;
     908             :                 default:
     909           0 :                     aSymbol = r.mpTable[i];
     910             :             }
     911           0 :             putCopyOpCode( aSymbol, eOp);
     912           0 :         }
     913             :     }
     914             :     else
     915             :     {
     916           0 :         for (sal_uInt16 i = 1; i < n; ++i)
     917             :         {
     918           0 :             OpCode eOp = OpCode(i);
     919           0 :             const OUString& rSymbol = r.mpTable[i];
     920           0 :             putCopyOpCode( rSymbol, eOp);
     921             :         }
     922             :     }
     923             : 
     924             :     // TODO: maybe copy the external maps too?
     925           0 : }
     926             : 
     927             : 
     928          37 : sal_uInt16 FormulaCompiler::GetErrorConstant( const OUString& rName ) const
     929             : {
     930          37 :     sal_uInt16 nError = 0;
     931          37 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
     932          37 :     if (iLook != mxSymbols->getHashMap()->end())
     933             :     {
     934          37 :         switch ((*iLook).second)
     935             :         {
     936             :             // Not all may make sense in a formula, but these we know as
     937             :             // opcodes.
     938             :             case ocErrNull:
     939           0 :                 nError = errNoCode;
     940           0 :                 break;
     941             :             case ocErrDivZero:
     942           4 :                 nError = errDivisionByZero;
     943           4 :                 break;
     944             :             case ocErrValue:
     945           0 :                 nError = errNoValue;
     946           0 :                 break;
     947             :             case ocErrRef:
     948          23 :                 nError = errNoRef;
     949          23 :                 break;
     950             :             case ocErrName:
     951           0 :                 nError = errNoName;
     952           0 :                 break;
     953             :             case ocErrNum:
     954           0 :                 nError = errIllegalFPOperation;
     955           0 :                 break;
     956             :             case ocErrNA:
     957          10 :                 nError = NOTAVAILABLE;
     958          10 :                 break;
     959             :             default:
     960             :                 ;   // nothing
     961             :         }
     962             :     }
     963          37 :     return nError;
     964             : }
     965             : 
     966             : 
     967           0 : void FormulaCompiler::AppendErrorConstant( OUStringBuffer& rBuffer, sal_uInt16 nError ) const
     968             : {
     969             :     OpCode eOp;
     970           0 :     switch (nError)
     971             :     {
     972             :         default:
     973             :         case errNoCode:
     974           0 :             eOp = ocErrNull;
     975           0 :             break;
     976             :         case errDivisionByZero:
     977           0 :             eOp = ocErrDivZero;
     978           0 :             break;
     979             :         case errNoValue:
     980           0 :             eOp = ocErrValue;
     981           0 :             break;
     982             :         case errNoRef:
     983           0 :             eOp = ocErrRef;
     984           0 :             break;
     985             :         case errNoName:
     986           0 :             eOp = ocErrName;
     987           0 :             break;
     988             :         case errIllegalFPOperation:
     989           0 :             eOp = ocErrNum;
     990           0 :             break;
     991             :         case NOTAVAILABLE:
     992           0 :             eOp = ocErrNA;
     993           0 :             break;
     994             :     }
     995           0 :     rBuffer.append( mxSymbols->getSymbol( eOp));
     996           0 : }
     997             : 
     998             : 
     999         116 : sal_Int32 FormulaCompiler::OpCodeMap::getOpCodeUnknown()
    1000             : {
    1001             :     static const sal_Int32 kOpCodeUnknown = -1;
    1002         116 :     return kOpCodeUnknown;
    1003             : }
    1004             : 
    1005       46755 : bool FormulaCompiler::GetToken()
    1006             : {
    1007             :     static const short nRecursionMax = 42;
    1008       46755 :     FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
    1009       46755 :     if ( nRecursion > nRecursionMax )
    1010             :     {
    1011           0 :         SetError( errStackOverflow );
    1012           0 :         mpToken = new FormulaByteToken( ocStop );
    1013           0 :         return false;
    1014             :     }
    1015       46755 :     if ( bAutoCorrect && !pStack )
    1016             :     {   // don't merge stacked subroutine code into entered formula
    1017           0 :         aCorrectedFormula += aCorrectedSymbol;
    1018           0 :         aCorrectedSymbol = "";
    1019             :     }
    1020       46755 :     bool bStop = false;
    1021       46755 :     if( pArr->GetCodeError() && !bIgnoreErrors )
    1022           0 :         bStop = true;
    1023             :     else
    1024             :     {
    1025             :         short nWasColRowName;
    1026       46755 :         if ( pArr->nIndex
    1027       46755 :           && pArr->pCode[ pArr->nIndex-1 ]->GetOpCode() == ocColRowName )
    1028           0 :              nWasColRowName = 1;
    1029             :         else
    1030       46755 :              nWasColRowName = 0;
    1031       46755 :         mpToken = pArr->Next();
    1032       93661 :         while( mpToken && mpToken->GetOpCode() == ocSpaces )
    1033             :         {
    1034         151 :             if ( nWasColRowName )
    1035           0 :                 nWasColRowName++;
    1036         151 :             if ( bAutoCorrect && !pStack )
    1037           0 :                 CreateStringFromToken( aCorrectedFormula, mpToken.get(), false );
    1038         151 :             mpToken = pArr->Next();
    1039             :         }
    1040       46755 :         if ( bAutoCorrect && !pStack && mpToken )
    1041           0 :             CreateStringFromToken( aCorrectedSymbol, mpToken.get(), false );
    1042       46755 :         if( !mpToken )
    1043             :         {
    1044        5512 :             if( pStack )
    1045             :             {
    1046         132 :                 PopTokenArray();
    1047         132 :                 return GetToken();
    1048             :             }
    1049             :             else
    1050        5380 :                 bStop = true;
    1051             :         }
    1052             :         else
    1053             :         {
    1054       41243 :             if ( nWasColRowName >= 2 && mpToken->GetOpCode() == ocColRowName )
    1055             :             {   // convert an ocSpaces to ocIntersect in RPN
    1056           0 :                 mpToken = new FormulaByteToken( ocIntersect );
    1057           0 :                 pArr->nIndex--;     // we advanced to the second ocColRowName, step back
    1058             :             }
    1059             :         }
    1060             :     }
    1061       46623 :     if( bStop )
    1062             :     {
    1063        5380 :         mpToken = new FormulaByteToken( ocStop );
    1064        5380 :         return false;
    1065             :     }
    1066       41243 :     if( mpToken->GetOpCode() == ocSubTotal )
    1067           5 :         glSubTotal = true;
    1068       41238 :     else if ( mpToken->IsExternalRef() )
    1069             :     {
    1070          52 :         return HandleExternalReference(*mpToken);
    1071             :     }
    1072       41186 :     else if( mpToken->GetOpCode() == ocName )
    1073             :     {
    1074         102 :         return HandleRange();
    1075             :     }
    1076       41084 :     else if( mpToken->GetOpCode() == ocColRowName )
    1077             :     {
    1078           0 :         return HandleSingleRef();
    1079             :     }
    1080       41084 :     else if( mpToken->GetOpCode() == ocDBArea )
    1081             :     {
    1082           2 :         return HandleDbData();
    1083             :     }
    1084       41082 :     else if( mpToken->GetType() == svSingleRef )
    1085             :     {
    1086        6778 :         pArr->nRefs++;
    1087             :     }
    1088       34304 :     else if( mpToken->GetType() == svDoubleRef )
    1089             :     {
    1090        2546 :         pArr->nRefs++;
    1091             :     }
    1092       41087 :     return true;
    1093             : }
    1094             : 
    1095             : 
    1096             : // RPN creation by recursion
    1097       21306 : void FormulaCompiler::Factor()
    1098             : {
    1099       21306 :     if ( pArr->GetCodeError() && !bIgnoreErrors )
    1100       21306 :         return;
    1101             : 
    1102       21306 :     CurrentFactor pFacToken( this );
    1103             : 
    1104       21306 :     OpCode eOp = mpToken->GetOpCode();
    1105       21306 :     if( eOp == ocPush || eOp == ocColRowNameAuto || eOp == ocMatRef ||
    1106             :             eOp == ocDBArea
    1107        6154 :             || (bCompileForFAP && ((eOp == ocName) || (eOp == ocDBArea)
    1108           0 :             || (eOp == ocColRowName) || (eOp == ocBad)))
    1109             :         )
    1110             :     {
    1111       15152 :         PutCode( mpToken );
    1112       15152 :         eOp = NextToken();
    1113       30304 :         if( eOp == ocOpen )
    1114             :         {
    1115             :             // PUSH( is an error that may be caused by an unknown function.
    1116             :             SetError(
    1117           0 :                 ( mpToken->GetType() == svString
    1118           0 :                || mpToken->GetType() == svSingleRef )
    1119           0 :                ? errNoName : errOperatorExpected );
    1120           0 :             if ( bAutoCorrect && !pStack )
    1121             :             {   // assume multiplication
    1122           0 :                 aCorrectedFormula += mxSymbols->getSymbol( ocMul);
    1123           0 :                 bCorrected = true;
    1124           0 :                 NextToken();
    1125           0 :                 eOp = Expression();
    1126           0 :                 if( eOp != ocClose )
    1127           0 :                     SetError( errPairExpected);
    1128             :                 else
    1129           0 :                     eOp = NextToken();
    1130             :             }
    1131             :         }
    1132             :     }
    1133        6154 :     else if( eOp == ocOpen )
    1134             :     {
    1135        1011 :         NextToken();
    1136        1011 :         eOp = Expression();
    1137        2022 :         while ((eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors))
    1138             :         {   // range list  (A1;A2)  converted to  (A1~A2)
    1139           0 :             pFacToken = mpToken;
    1140           0 :             NextToken();
    1141           0 :             eOp = Expression();
    1142             :             // Do not ignore error here, regardless of bIgnoreErrors, otherwise
    1143             :             // errors like =(1;) would also result in display of =(1~)
    1144           0 :             if (!pArr->GetCodeError())
    1145             :             {
    1146           0 :                 pFacToken->NewOpCode( ocUnion, FormulaToken::PrivateAccess());
    1147           0 :                 PutCode( pFacToken);
    1148             :             }
    1149             :         }
    1150        1011 :         if (eOp != ocClose)
    1151           0 :             SetError( errPairExpected);
    1152             :         else
    1153        1011 :             eOp = NextToken();
    1154             :     }
    1155             :     else
    1156             :     {
    1157        5143 :         if( nNumFmt == NUMBERFORMAT_UNDEFINED )
    1158        2823 :             nNumFmt = lcl_GetRetFormat( eOp );
    1159             : 
    1160        5143 :         if ( IsOpCodeVolatile( eOp) )
    1161          25 :             pArr->SetExclusiveRecalcModeAlways();
    1162             :         else
    1163             :         {
    1164        5118 :             switch( eOp )
    1165             :             {
    1166             :                     // Functions recalculated on every document load.
    1167             :                     // Don't use SetExclusiveRecalcModeOnLoad() which would
    1168             :                     // override ModeAlways, use
    1169             :                     // AddRecalcMode(RECALCMODE_ONLOAD) instead.
    1170             :                 case ocConvert :
    1171             :                 case ocDde:
    1172             :                 case ocMacro:
    1173             :                 case ocExternal:
    1174          73 :                     pArr->AddRecalcMode( RECALCMODE_ONLOAD );
    1175          73 :                 break;
    1176             :                     // If the referred cell is moved the value changes.
    1177             :                 case ocColumn :
    1178             :                 case ocRow :
    1179          53 :                     pArr->SetRecalcModeOnRefMove();
    1180          53 :                 break;
    1181             :                     // ocCell needs recalc on move for some possible type values.
    1182             :                     // and recalc mode on load, fdo#60646
    1183             :                 case ocCell :
    1184          28 :                     pArr->SetRecalcModeOnRefMove();
    1185          28 :                     pArr->AddRecalcMode( RECALCMODE_ONLOAD );
    1186          28 :                 break;
    1187             :                 case ocHyperLink :
    1188             :                     // cell with hyperlink needs to be calculated on load to
    1189             :                     // get its matrix result generated.
    1190           0 :                     pArr->AddRecalcMode( RECALCMODE_ONLOAD );
    1191           0 :                     pArr->SetHyperLink( true);
    1192           0 :                 break;
    1193             :                 default:
    1194             :                     ;   // nothing
    1195             :             }
    1196             :         }
    1197        5143 :         if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
    1198             :         {
    1199          54 :             pFacToken = mpToken;
    1200          54 :             eOp = NextToken();
    1201         108 :             if (eOp != ocOpen)
    1202             :             {
    1203           0 :                 SetError( errPairExpected);
    1204           0 :                 PutCode( pFacToken );
    1205             :             }
    1206             :             else
    1207             :             {
    1208          54 :                 eOp = NextToken();
    1209          54 :                 if (eOp != ocClose)
    1210           0 :                     SetError( errPairExpected);
    1211          54 :                 PutCode( pFacToken);
    1212          54 :                 eOp = NextToken();
    1213             :             }
    1214             :         }
    1215             :         // special cases NOT() and NEG()
    1216        5089 :         else if( eOp == ocNot || eOp == ocNeg
    1217        5089 :               || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) )
    1218             :         {
    1219         288 :             pFacToken = mpToken;
    1220         288 :             eOp = NextToken();
    1221         288 :             if( nNumFmt == NUMBERFORMAT_UNDEFINED && eOp == ocNot )
    1222           0 :                 nNumFmt = NUMBERFORMAT_LOGICAL;
    1223         288 :             if (eOp == ocOpen)
    1224             :             {
    1225         288 :                 NextToken();
    1226         288 :                 eOp = Expression();
    1227             :             }
    1228             :             else
    1229           0 :                 SetError( errPairExpected);
    1230         288 :             if (eOp != ocClose)
    1231           0 :                 SetError( errPairExpected);
    1232         288 :             else if ( !pArr->GetCodeError() )
    1233         288 :                 pFacToken->SetByte( 1 );
    1234         288 :             PutCode( pFacToken );
    1235         288 :             eOp = NextToken();
    1236             :         }
    1237        4801 :         else if ((SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR)
    1238         857 :                 || eOp == ocExternal
    1239         793 :                 || eOp == ocMacro
    1240         792 :                 || eOp == ocAnd
    1241         779 :                 || eOp == ocOr
    1242         761 :                 || eOp == ocBad
    1243         743 :                 || ( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
    1244         743 :                 || ( bCompileForFAP
    1245           0 :                      && ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose ) )
    1246             :             )
    1247             :         {
    1248        4058 :             pFacToken = mpToken;
    1249        4058 :             OpCode eMyLastOp = eOp;
    1250        4058 :             eOp = NextToken();
    1251        4058 :             bool bNoParam = false;
    1252        4058 :             bool bBadName = false;
    1253        4058 :             if (eOp == ocOpen)
    1254             :             {
    1255        4043 :                 eOp = NextToken();
    1256        4043 :                 if (eOp == ocClose)
    1257          32 :                     bNoParam = true;
    1258             :                 else
    1259        4011 :                     eOp = Expression();
    1260             :             }
    1261          15 :             else if (eMyLastOp == ocBad)
    1262             :             {
    1263             :                 // Just a bad name, not an unknown function, no parameters, no
    1264             :                 // closing expected.
    1265          15 :                 bBadName = true;
    1266          15 :                 bNoParam = true;
    1267             :             }
    1268             :             else
    1269           0 :                 SetError( errPairExpected);
    1270        4058 :             sal_uInt8 nSepCount = 0;
    1271        4058 :             if( !bNoParam )
    1272             :             {
    1273        4011 :                 nSepCount++;
    1274       12275 :                 while ( (eOp == ocSep) && (!pArr->GetCodeError() || bIgnoreErrors) )
    1275             :                 {
    1276        4253 :                     nSepCount++;
    1277        4253 :                     NextToken();
    1278        4253 :                     eOp = Expression();
    1279             :                 }
    1280             :             }
    1281        4058 :             if (bBadName)
    1282             :                 ;   // nothing, keep current token for return
    1283        4043 :             else if (eOp != ocClose)
    1284           0 :                 SetError( errPairExpected);
    1285             :             else
    1286        4043 :                 eOp = NextToken();
    1287             :             // Jumps are just normal functions for the FunctionAutoPilot tree view
    1288        4058 :             if ( bCompileForFAP && pFacToken->GetType() == svJump )
    1289           0 :                 pFacToken = new FormulaFAPToken( pFacToken->GetOpCode(), nSepCount, pFacToken );
    1290             :             else
    1291        4058 :                 pFacToken->SetByte( nSepCount );
    1292        4058 :             PutCode( pFacToken );
    1293             :         }
    1294         743 :         else if (eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChose)
    1295             :         {
    1296             :             // the PC counters are -1
    1297          37 :             pFacToken = mpToken;
    1298          37 :             switch (eOp)
    1299             :             {
    1300             :                 case ocIf:
    1301          25 :                     pFacToken->GetJump()[ 0 ] = 3;  // if, else, behind
    1302          25 :                     break;
    1303             :                 case ocChose:
    1304           0 :                     pFacToken->GetJump()[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
    1305           0 :                     break;
    1306             :                 case ocIfError:
    1307             :                 case ocIfNA:
    1308          12 :                     pFacToken->GetJump()[ 0 ] = 2;  // if, behind
    1309          12 :                     break;
    1310             :                 default:
    1311             :                     SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump count case?");
    1312             :             }
    1313          37 :             eOp = NextToken();
    1314          37 :             if (eOp == ocOpen)
    1315             :             {
    1316          37 :                 NextToken();
    1317          37 :                 eOp = Expression();
    1318             :             }
    1319             :             else
    1320           0 :                 SetError( errPairExpected);
    1321          37 :             PutCode( pFacToken );
    1322             :             // During AutoCorrect (since pArr->GetCodeError() is
    1323             :             // ignored) an unlimited ocIf would crash because
    1324             :             // ScRawToken::Clone() allocates the JumpBuffer according to
    1325             :             // nJump[0]*2+2, which is 3*2+2 on ocIf and 2*2+2 ocIfError and ocIfNA.
    1326             :             short nJumpMax;
    1327          37 :             OpCode eFacOpCode = pFacToken->GetOpCode();
    1328          37 :             switch (eFacOpCode)
    1329             :             {
    1330             :                 case ocIf:
    1331          25 :                     nJumpMax = 3;
    1332          25 :                     break;
    1333             :                 case ocChose:
    1334           0 :                     nJumpMax = FORMULA_MAXJUMPCOUNT;
    1335           0 :                     break;
    1336             :                 case ocIfError:
    1337             :                 case ocIfNA:
    1338          12 :                     nJumpMax = 2;
    1339          12 :                     break;
    1340             :                 default:
    1341           0 :                     nJumpMax = 0;
    1342             :                     SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump max case?");
    1343             :             }
    1344          37 :             short nJumpCount = 0;
    1345         203 :             while ( (nJumpCount < (FORMULA_MAXJUMPCOUNT - 1)) && (eOp == ocSep)
    1346         129 :                     && (!pArr->GetCodeError() || bIgnoreErrors) )
    1347             :             {
    1348          46 :                 if ( ++nJumpCount <= nJumpMax )
    1349          46 :                     pFacToken->GetJump()[nJumpCount] = pc-1;
    1350          46 :                 NextToken();
    1351          46 :                 eOp = Expression();
    1352             :                 // ocSep or ocClose terminate the subexpression
    1353          46 :                 PutCode( mpToken );
    1354             :             }
    1355          37 :             if (eOp != ocClose)
    1356           0 :                 SetError( errPairExpected);
    1357             :             else
    1358             :             {
    1359          37 :                 eOp = NextToken();
    1360             :                 // always limit to nJumpMax, no arbitrary overwrites
    1361          37 :                 if ( ++nJumpCount <= nJumpMax )
    1362          37 :                     pFacToken->GetJump()[ nJumpCount ] = pc-1;
    1363          37 :                 eFacOpCode = pFacToken->GetOpCode();
    1364             :                 bool bLimitOk;
    1365          37 :                 switch (eFacOpCode)
    1366             :                 {
    1367             :                     case ocIf:
    1368          25 :                         bLimitOk = (nJumpCount <= 3);
    1369          25 :                         break;
    1370             :                     case ocChose:
    1371           0 :                         bLimitOk = (nJumpCount < FORMULA_MAXJUMPCOUNT); /* TODO: check, really <, not <=? */
    1372           0 :                         break;
    1373             :                     case ocIfError:
    1374             :                     case ocIfNA:
    1375          12 :                         bLimitOk = (nJumpCount <= 2);
    1376          12 :                         break;
    1377             :                     default:
    1378           0 :                         bLimitOk = false;
    1379             :                         SAL_WARN( "formula.core", "FormulaCompiler::Factor: forgot to add a jump limit case?");
    1380             :                 }
    1381          37 :                 if (bLimitOk)
    1382          37 :                     pFacToken->GetJump()[ 0 ] = nJumpCount;
    1383             :                 else
    1384           0 :                     SetError( errIllegalParameter);
    1385          37 :             }
    1386             :         }
    1387         706 :         else if ( eOp == ocMissing )
    1388             :         {
    1389           9 :             PutCode( mpToken );
    1390           9 :             eOp = NextToken();
    1391             :         }
    1392         697 :         else if ( eOp == ocClose )
    1393             :         {
    1394           0 :             SetError( errParameterExpected );
    1395             :         }
    1396         697 :         else if ( eOp == ocSep )
    1397             :         {   // Subsequent ocSep
    1398           0 :             SetError( errParameterExpected );
    1399           0 :             if ( bAutoCorrect && !pStack )
    1400             :             {
    1401           0 :                 aCorrectedSymbol = "";
    1402           0 :                 bCorrected = true;
    1403             :             }
    1404             :         }
    1405         697 :         else if ( mpToken->IsExternalRef() )
    1406             :         {
    1407           0 :             PutCode( mpToken);
    1408           0 :             eOp = NextToken();
    1409             :         }
    1410             :         else
    1411             :         {
    1412         697 :             SetError( errUnknownToken );
    1413         697 :             if ( bAutoCorrect && !pStack )
    1414             :             {
    1415           0 :                 if ( eOp == ocStop )
    1416             :                 {   // trailing operator w/o operand
    1417           0 :                     sal_Int32 nLen = aCorrectedFormula.getLength();
    1418           0 :                     if ( nLen )
    1419           0 :                         aCorrectedFormula = aCorrectedFormula.copy( 0, nLen - 1 );
    1420           0 :                     aCorrectedSymbol = "";
    1421           0 :                     bCorrected = true;
    1422             :                 }
    1423             :             }
    1424             :         }
    1425       21306 :     }
    1426             : }
    1427             : 
    1428       21306 : void FormulaCompiler::RangeLine()
    1429             : {
    1430       21306 :     Factor();
    1431       42612 :     while (mpToken->GetOpCode() == ocRange)
    1432             :     {
    1433           0 :         FormulaToken** pCode1 = pCode - 1;
    1434           0 :         FormulaTokenRef p = mpToken;
    1435           0 :         NextToken();
    1436           0 :         Factor();
    1437           0 :         FormulaToken** pCode2 = pCode - 1;
    1438           0 :         if (!MergeRangeReference( pCode1, pCode2))
    1439           0 :             PutCode(p);
    1440           0 :     }
    1441       21306 : }
    1442             : 
    1443       21306 : void FormulaCompiler::IntersectionLine()
    1444             : {
    1445       21306 :     RangeLine();
    1446       42612 :     while (mpToken->GetOpCode() == ocIntersect)
    1447             :     {
    1448           0 :         FormulaTokenRef p = mpToken;
    1449           0 :         NextToken();
    1450           0 :         RangeLine();
    1451           0 :         PutCode(p);
    1452           0 :     }
    1453       21306 : }
    1454             : 
    1455       21306 : void FormulaCompiler::UnionLine()
    1456             : {
    1457       21306 :     IntersectionLine();
    1458       42612 :     while (mpToken->GetOpCode() == ocUnion)
    1459             :     {
    1460           0 :         FormulaTokenRef p = mpToken;
    1461           0 :         NextToken();
    1462           0 :         IntersectionLine();
    1463           0 :         PutCode(p);
    1464           0 :     }
    1465       21306 : }
    1466             : 
    1467       21402 : void FormulaCompiler::UnaryLine()
    1468             : {
    1469       21402 :     if( mpToken->GetOpCode() == ocAdd )
    1470           0 :         GetToken();
    1471       25784 :     else if (SC_OPCODE_START_UN_OP <= mpToken->GetOpCode() &&
    1472        4382 :             mpToken->GetOpCode() < SC_OPCODE_STOP_UN_OP)
    1473             :     {
    1474          96 :         FormulaTokenRef p = mpToken;
    1475          96 :         NextToken();
    1476          96 :         UnaryLine();
    1477          96 :         PutCode( p );
    1478             :     }
    1479             :     else
    1480       21306 :         UnionLine();
    1481       21402 : }
    1482             : 
    1483       21306 : void FormulaCompiler::PostOpLine()
    1484             : {
    1485       21306 :     UnaryLine();
    1486       42612 :     while ( mpToken->GetOpCode() == ocPercentSign )
    1487             :     {   // this operator _follows_ its operand
    1488           0 :         PutCode( mpToken );
    1489           0 :         NextToken();
    1490             :     }
    1491       21306 : }
    1492             : 
    1493       21305 : void FormulaCompiler::PowLine()
    1494             : {
    1495       21305 :     PostOpLine();
    1496       42611 :     while (mpToken->GetOpCode() == ocPow)
    1497             :     {
    1498           1 :         FormulaTokenRef p = mpToken;
    1499           1 :         NextToken();
    1500           1 :         PostOpLine();
    1501           1 :         PutCode(p);
    1502           1 :     }
    1503       21305 : }
    1504             : 
    1505       19391 : void FormulaCompiler::MulDivLine()
    1506             : {
    1507       19391 :     PowLine();
    1508       40696 :     while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv)
    1509             :     {
    1510        1914 :         FormulaTokenRef p = mpToken;
    1511        1914 :         NextToken();
    1512        1914 :         PowLine();
    1513        1914 :         PutCode(p);
    1514        1914 :     }
    1515       19391 : }
    1516             : 
    1517       15766 : void FormulaCompiler::AddSubLine()
    1518             : {
    1519       15766 :     MulDivLine();
    1520       35157 :     while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub)
    1521             :     {
    1522        3625 :         FormulaTokenRef p = mpToken;
    1523        3625 :         NextToken();
    1524        3625 :         MulDivLine();
    1525        3625 :         PutCode(p);
    1526        3625 :     }
    1527       15766 : }
    1528             : 
    1529       15758 : void FormulaCompiler::ConcatLine()
    1530             : {
    1531       15758 :     AddSubLine();
    1532       31524 :     while (mpToken->GetOpCode() == ocAmpersand)
    1533             :     {
    1534           8 :         FormulaTokenRef p = mpToken;
    1535           8 :         NextToken();
    1536           8 :         AddSubLine();
    1537           8 :         PutCode(p);
    1538           8 :     }
    1539       15758 : }
    1540             : 
    1541       15726 : void FormulaCompiler::CompareLine()
    1542             : {
    1543       15726 :     ConcatLine();
    1544       31484 :     while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual)
    1545             :     {
    1546          32 :         FormulaTokenRef p = mpToken;
    1547          32 :         NextToken();
    1548          32 :         ConcatLine();
    1549          32 :         PutCode(p);
    1550          32 :     }
    1551       15726 : }
    1552             : 
    1553       15726 : void FormulaCompiler::NotLine()
    1554             : {
    1555       15726 :     CompareLine();
    1556       31452 :     while (mpToken->GetOpCode() == ocNot)
    1557             :     {
    1558           0 :         FormulaTokenRef p = mpToken;
    1559           0 :         NextToken();
    1560           0 :         CompareLine();
    1561           0 :         PutCode(p);
    1562           0 :     }
    1563       15726 : }
    1564             : 
    1565       15726 : OpCode FormulaCompiler::Expression()
    1566             : {
    1567             :     static const short nRecursionMax = 42;
    1568       15726 :     FormulaCompilerRecursionGuard aRecursionGuard( nRecursion );
    1569       15726 :     if ( nRecursion > nRecursionMax )
    1570             :     {
    1571           0 :         SetError( errStackOverflow );
    1572           0 :         return ocStop;      //! generate token instead?
    1573             :     }
    1574       15726 :     NotLine();
    1575       31452 :     while (mpToken->GetOpCode() == ocAnd || mpToken->GetOpCode() == ocOr)
    1576             :     {
    1577           0 :         FormulaTokenRef p = mpToken;
    1578           0 :         mpToken->SetByte( 2 );       // 2 parameters!
    1579           0 :         NextToken();
    1580           0 :         NotLine();
    1581           0 :         PutCode(p);
    1582           0 :     }
    1583       15726 :     return mpToken->GetOpCode();
    1584             : }
    1585             : 
    1586             : 
    1587           0 : void FormulaCompiler::SetError( sal_uInt16 /*nError*/ )
    1588             : {
    1589           0 : }
    1590             : 
    1591           0 : FormulaTokenRef FormulaCompiler::ExtendRangeReference( FormulaToken & /*rTok1*/, FormulaToken & /*rTok2*/,
    1592             :         bool /*bReuseDoubleRef*/ )
    1593             : {
    1594           0 :     return FormulaTokenRef();
    1595             : }
    1596             : 
    1597           0 : bool FormulaCompiler::MergeRangeReference( FormulaToken * * const pCode1, FormulaToken * const * const pCode2 )
    1598             : {
    1599             :     FormulaToken *p1, *p2;
    1600           0 :     if (pc < 2 || !pCode1 || !pCode2 ||
    1601           0 :             (pCode2 - pCode1 != 1) || (pCode - pCode2 != 1) ||
    1602           0 :             ((p1 = *pCode1) == 0) || ((p2 = *pCode2) == 0) )
    1603           0 :         return false;
    1604             : 
    1605           0 :     FormulaTokenRef p = ExtendRangeReference( *p1, *p2, true);
    1606           0 :     if (!p)
    1607           0 :         return false;
    1608             : 
    1609           0 :     p->IncRef();
    1610           0 :     p1->DecRef();
    1611           0 :     p2->DecRef();
    1612           0 :     *pCode1 = p.get();
    1613           0 :     --pCode, --pc;
    1614           0 :     pArr->nRefs--;
    1615             : 
    1616           0 :     return true;
    1617             : }
    1618             : 
    1619        6080 : bool FormulaCompiler::CompileTokenArray()
    1620             : {
    1621        6080 :     glSubTotal = false;
    1622        6080 :     bCorrected = false;
    1623        6080 :     if( !pArr->GetCodeError() || bIgnoreErrors )
    1624             :     {
    1625        6080 :         if ( bAutoCorrect )
    1626             :         {
    1627           0 :             aCorrectedFormula = "";
    1628           0 :             aCorrectedSymbol = "";
    1629             :         }
    1630        6080 :         pArr->nRefs = 0;    // count from start
    1631        6080 :         pArr->DelRPN();
    1632        6080 :         pStack = NULL;
    1633             :         FormulaToken* pData[ FORMULA_MAXTOKENS ];
    1634        6080 :         pCode = pData;
    1635        6080 :         bool bWasForced = pArr->IsRecalcModeForced();
    1636        6080 :         if ( bWasForced )
    1637             :         {
    1638           0 :             if ( bAutoCorrect )
    1639           0 :                 aCorrectedFormula = "=";
    1640             :         }
    1641        6080 :         pArr->ClearRecalcMode();
    1642        6080 :         pArr->Reset();
    1643        6080 :         eLastOp = ocOpen;
    1644        6080 :         pc = 0;
    1645        6080 :         NextToken();
    1646        6080 :         OpCode eOp = Expression();
    1647             :         // Some trailing garbage that doesn't form an expression?
    1648        6080 :         if (eOp != ocStop)
    1649         698 :             SetError( errOperatorExpected);
    1650             : 
    1651        6080 :         sal_uInt16 nErrorBeforePop = pArr->GetCodeError();
    1652             : 
    1653       12160 :         while( pStack )
    1654           0 :             PopTokenArray();
    1655        6080 :         if( pc )
    1656             :         {
    1657        5383 :             pArr->pRPN = new FormulaToken*[ pc ];
    1658        5383 :             pArr->nRPN = pc;
    1659        5383 :             memcpy( pArr->pRPN, pData, pc * sizeof( FormulaToken* ) );
    1660             :         }
    1661             : 
    1662             :         // once an error, always an error
    1663        6080 :         if( !pArr->GetCodeError() && nErrorBeforePop )
    1664           0 :             pArr->SetCodeError( nErrorBeforePop);
    1665             : 
    1666        6080 :         if( pArr->GetCodeError() && !bIgnoreErrors )
    1667             :         {
    1668         698 :             pArr->DelRPN();
    1669         698 :             pArr->SetHyperLink( false);
    1670             :         }
    1671             : 
    1672        6080 :         if ( bWasForced )
    1673           0 :             pArr->SetRecalcModeForced();
    1674             :     }
    1675        6080 :     if( nNumFmt == NUMBERFORMAT_UNDEFINED )
    1676        3257 :         nNumFmt = NUMBERFORMAT_NUMBER;
    1677        6080 :     return glSubTotal;
    1678             : }
    1679             : 
    1680         132 : void FormulaCompiler::PopTokenArray()
    1681             : {
    1682         132 :     if( pStack )
    1683             :     {
    1684         132 :         FormulaArrayStack* p = pStack;
    1685         132 :         pStack = p->pNext;
    1686         132 :         p->pArr->nRefs = sal::static_int_cast<short>( p->pArr->nRefs + pArr->nRefs );
    1687             :         // obtain special RecalcMode from SharedFormula
    1688         132 :         if ( pArr->IsRecalcModeAlways() )
    1689           0 :             p->pArr->SetExclusiveRecalcModeAlways();
    1690         132 :         else if ( !pArr->IsRecalcModeNormal() && p->pArr->IsRecalcModeNormal() )
    1691           0 :             p->pArr->SetMaskedRecalcMode( pArr->GetRecalcMode() );
    1692         132 :         p->pArr->SetCombinedBitsRecalcMode( pArr->GetRecalcMode() );
    1693         132 :         if( p->bTemp )
    1694         132 :             delete pArr;
    1695         132 :         pArr = p->pArr;
    1696         132 :         delete p;
    1697             :     }
    1698         132 : }
    1699             : 
    1700         144 : void FormulaCompiler::CreateStringFromTokenArray( OUString& rFormula )
    1701             : {
    1702         144 :     OUStringBuffer aBuffer( pArr->GetLen() * 5 );
    1703         144 :     CreateStringFromTokenArray( aBuffer );
    1704         144 :     rFormula = aBuffer.makeStringAndClear();
    1705         144 : }
    1706             : 
    1707         799 : void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer )
    1708             : {
    1709         799 :     rBuffer.setLength(0);
    1710         799 :     if( !pArr->GetLen() )
    1711         799 :         return;
    1712             : 
    1713         799 :     FormulaTokenArray* pSaveArr = pArr;
    1714         799 :     bool bODFF = FormulaGrammar::isODFF( meGrammar);
    1715         799 :     if (bODFF || FormulaGrammar::isPODF( meGrammar) )
    1716             :     {
    1717             :         // Scan token array for missing args and re-write if present.
    1718         236 :         MissingConvention aConv( bODFF);
    1719         236 :         if (pArr->NeedsPofRewrite( aConv))
    1720           0 :             pArr = pArr->RewriteMissingToPof( aConv);
    1721             :     }
    1722             : 
    1723             :     // At least one character per token, plus some are references, some are
    1724             :     // function names, some are numbers, ...
    1725         799 :     rBuffer.ensureCapacity( pArr->GetLen() * 5 );
    1726             : 
    1727         799 :     if ( pArr->IsRecalcModeForced() )
    1728           0 :         rBuffer.append( '=');
    1729         799 :     FormulaToken* t = pArr->First();
    1730        3785 :     while( t )
    1731        2187 :         t = CreateStringFromToken( rBuffer, t, true );
    1732             : 
    1733         799 :     if (pSaveArr != pArr)
    1734             :     {
    1735           0 :         delete pArr;
    1736           0 :         pArr = pSaveArr;
    1737             :     }
    1738             : }
    1739             : 
    1740       25001 : FormulaToken* FormulaCompiler::CreateStringFromToken( OUString& rFormula, FormulaToken* pTokenP,bool bAllowArrAdvance )
    1741             : {
    1742       25001 :     OUStringBuffer aBuffer;
    1743       25001 :     FormulaToken* p = CreateStringFromToken( aBuffer, pTokenP, bAllowArrAdvance );
    1744       25001 :     rFormula += aBuffer.makeStringAndClear();
    1745       25001 :     return p;
    1746             : }
    1747             : 
    1748       27188 : FormulaToken* FormulaCompiler::CreateStringFromToken( OUStringBuffer& rBuffer, FormulaToken* pTokenP, bool bAllowArrAdvance )
    1749             : {
    1750       27188 :     bool bNext = true;
    1751       27188 :     bool bSpaces = false;
    1752       27188 :     FormulaToken* t = pTokenP;
    1753       27188 :     OpCode eOp = t->GetOpCode();
    1754       27188 :     if( eOp >= ocAnd && eOp <= ocOr )
    1755             :     {
    1756             :         // AND, OR infix?
    1757          20 :         if ( bAllowArrAdvance )
    1758          20 :             t = pArr->Next();
    1759             :         else
    1760           0 :             t = pArr->PeekNext();
    1761          20 :         bNext = false;
    1762          20 :         bSpaces = ( !t || t->GetOpCode() != ocOpen );
    1763             :     }
    1764       27188 :     if( bSpaces )
    1765           0 :         rBuffer.append( ' ');
    1766             : 
    1767       27188 :     if( eOp == ocSpaces )
    1768             :     {
    1769          12 :         bool bIntersectionOp = mxSymbols->isODFF();
    1770          12 :         if (bIntersectionOp)
    1771             :         {
    1772           0 :             const FormulaToken* p = pArr->PeekPrevNoSpaces();
    1773           0 :             bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
    1774           0 :             if (bIntersectionOp)
    1775             :             {
    1776           0 :                 p = pArr->PeekNextNoSpaces();
    1777           0 :                 bIntersectionOp = (p && p->GetOpCode() == ocColRowName);
    1778             :             }
    1779             :         }
    1780          12 :         if (bIntersectionOp)
    1781           0 :             rBuffer.appendAscii( "!!");
    1782             :         else
    1783             :         {
    1784             :             // most times it's just one blank
    1785          12 :             sal_uInt8 n = t->GetByte();
    1786          24 :             for ( sal_uInt8 j=0; j<n; ++j )
    1787             :             {
    1788          12 :                 rBuffer.append( ' ');
    1789             :             }
    1790             :         }
    1791             :     }
    1792       27176 :     else if( eOp >= ocInternalBegin && eOp <= ocInternalEnd )
    1793           0 :         rBuffer.appendAscii( pInternal[ eOp - ocInternalBegin ] );
    1794       27176 :     else if( (sal_uInt16) eOp < mxSymbols->getSymbolCount())        // Keyword:
    1795       27176 :         rBuffer.append( mxSymbols->getSymbol( eOp));
    1796             :     else
    1797             :     {
    1798             :         SAL_WARN( "formula.core","unknown OpCode");
    1799           0 :         rBuffer.append( GetNativeSymbol( ocErrName ));
    1800             :     }
    1801       27188 :     if( bNext )
    1802             :     {
    1803       27168 :         if (t->IsExternalRef())
    1804             :         {
    1805          20 :             CreateStringFromExternal( rBuffer, pTokenP);
    1806             :         }
    1807             :         else
    1808             :         {
    1809       27148 :             switch( t->GetType() )
    1810             :             {
    1811             :             case svDouble:
    1812         213 :                 AppendDouble( rBuffer, t->GetDouble() );
    1813         213 :             break;
    1814             : 
    1815             :             case svString:
    1816         120 :                 if( eOp == ocBad || eOp == ocStringXML )
    1817          60 :                     rBuffer.append( t->GetString().getString());
    1818             :                 else
    1819          60 :                     AppendString( rBuffer, t->GetString().getString() );
    1820         120 :                 break;
    1821             :             case svSingleRef:
    1822       13125 :                 CreateStringFromSingleRef( rBuffer, t);
    1823       13125 :                 break;
    1824             :             case svDoubleRef:
    1825       12620 :                 CreateStringFromDoubleRef( rBuffer, t);
    1826       12620 :                 break;
    1827             :             case svMatrix:
    1828           0 :                 CreateStringFromMatrix( rBuffer, t );
    1829           0 :                 break;
    1830             : 
    1831             :             case svIndex:
    1832          12 :                 CreateStringFromIndex( rBuffer, t );
    1833          12 :                 break;
    1834             :             case svExternal:
    1835             :             {
    1836             :                 // mapped or translated name of AddIns
    1837           0 :                 OUString aAddIn( t->GetExternal() );
    1838           0 :                 bool bMapped = mxSymbols->isPODF();     // ODF 1.1 directly uses programmatical name
    1839           0 :                 if (!bMapped && mxSymbols->hasExternals())
    1840             :                 {
    1841           0 :                     ExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
    1842           0 :                     if (iLook != mxSymbols->getReverseExternalHashMap()->end())
    1843             :                     {
    1844           0 :                         aAddIn = (*iLook).second;
    1845           0 :                         bMapped = true;
    1846             :                     }
    1847             :                 }
    1848           0 :                 if (!bMapped && !mxSymbols->isEnglish())
    1849           0 :                     LocalizeString( aAddIn );
    1850           0 :                 rBuffer.append( aAddIn);
    1851             :             }
    1852           0 :             break;
    1853             :             case svError:
    1854           0 :                 AppendErrorConstant( rBuffer, t->GetError());
    1855           0 :             break;
    1856             :             case svByte:
    1857             :             case svJump:
    1858             :             case svFAP:
    1859             :             case svMissing:
    1860             :             case svSep:
    1861        1058 :                 break;      // Opcodes
    1862             :             default:
    1863             :                 OSL_FAIL("FormulaCompiler:: GetStringFromToken errUnknownVariable");
    1864             :             } // of switch
    1865             :         }
    1866             :     }
    1867       27188 :     if( bSpaces )
    1868           0 :         rBuffer.append( ' ');
    1869       27188 :     if ( bAllowArrAdvance )
    1870             :     {
    1871        2187 :         if( bNext )
    1872        2167 :             t = pArr->Next();
    1873        2187 :         return t;
    1874             :     }
    1875       25001 :     return pTokenP;
    1876             : }
    1877             : 
    1878             : 
    1879         213 : void FormulaCompiler::AppendDouble( OUStringBuffer& rBuffer, double fVal ) const
    1880             : {
    1881         213 :     if ( mxSymbols->isEnglish() )
    1882             :     {
    1883             :         ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
    1884             :                 rtl_math_StringFormat_Automatic,
    1885         173 :                 rtl_math_DecimalPlaces_Max, '.', true );
    1886             :     }
    1887             :     else
    1888             :     {
    1889          40 :         SvtSysLocale aSysLocale;
    1890             :         ::rtl::math::doubleToUStringBuffer( rBuffer, fVal,
    1891             :                 rtl_math_StringFormat_Automatic,
    1892             :                 rtl_math_DecimalPlaces_Max,
    1893          40 :                 aSysLocale.GetLocaleDataPtr()->getNumDecimalSep()[0],
    1894          40 :                 true );
    1895             :     }
    1896         213 : }
    1897             : 
    1898           0 : void FormulaCompiler::AppendBoolean( OUStringBuffer& rBuffer, bool bVal ) const
    1899             : {
    1900           0 :     rBuffer.append( mxSymbols->getSymbol( static_cast<OpCode>(bVal ? ocTrue : ocFalse)) );
    1901           0 : }
    1902             : 
    1903          60 : void FormulaCompiler::AppendString( OUStringBuffer& rBuffer, const OUString & rStr ) const
    1904             : {
    1905          60 :     rBuffer.append( '"');
    1906          60 :     if ( lcl_UnicodeStrChr( rStr.getStr(), '"' ) == NULL )
    1907          60 :         rBuffer.append( rStr );
    1908             :     else
    1909             :     {
    1910           0 :         OUString aStr = rStr.replaceAll( "\"", "\"\"" );
    1911           0 :         rBuffer.append(aStr);
    1912             :     }
    1913          60 :     rBuffer.append( '"');
    1914          60 : }
    1915             : 
    1916         390 : void FormulaCompiler::UpdateSeparatorsNative(
    1917             :     const OUString& rSep, const OUString& rArrayColSep, const OUString& rArrayRowSep )
    1918             : {
    1919         390 :     NonConstOpCodeMapPtr xSymbolsNative;
    1920         390 :     lcl_fillNativeSymbols( xSymbolsNative);
    1921         390 :     xSymbolsNative->putOpCode( rSep, ocSep);
    1922         390 :     xSymbolsNative->putOpCode( rArrayColSep, ocArrayColSep);
    1923         390 :     xSymbolsNative->putOpCode( rArrayRowSep, ocArrayRowSep);
    1924         390 : }
    1925             : 
    1926         390 : void FormulaCompiler::ResetNativeSymbols()
    1927             : {
    1928         390 :     NonConstOpCodeMapPtr xSymbolsNative;
    1929         390 :     lcl_fillNativeSymbols( xSymbolsNative, true);
    1930         390 :     lcl_fillNativeSymbols( xSymbolsNative);
    1931         390 : }
    1932             : 
    1933           0 : void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr& xMap )
    1934             : {
    1935           0 :     NonConstOpCodeMapPtr xSymbolsNative;
    1936           0 :     lcl_fillNativeSymbols( xSymbolsNative);
    1937           0 :     xSymbolsNative->copyFrom( *xMap, true);
    1938           0 : }
    1939             : 
    1940             : 
    1941       46519 : OpCode FormulaCompiler::NextToken()
    1942             : {
    1943       46519 :     if( !GetToken() )
    1944        5380 :         return ocStop;
    1945       41139 :     OpCode eOp = mpToken->GetOpCode();
    1946             :     // There must be an operator before a push
    1947       56161 :     if ( (eOp == ocPush || eOp == ocColRowNameAuto) &&
    1948       22146 :             !( (eLastOp == ocOpen) || (eLastOp == ocSep) ||
    1949        2929 :                 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)) )
    1950           0 :         SetError( errOperatorExpected);
    1951             :     // Operator and Plus => operator
    1952       43952 :     if (eOp == ocAdd && (eLastOp == ocOpen || eLastOp == ocSep ||
    1953        2813 :                 (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
    1954           0 :         eOp = NextToken();
    1955             :     else
    1956             :     {
    1957             :         // Before an operator there must not be another operator, with the
    1958             :         // exception of AND and OR.
    1959       41139 :         if ( eOp != ocAnd && eOp != ocOr &&
    1960        9962 :                 (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP )
    1961       11160 :                 && (eLastOp == ocOpen || eLastOp == ocSep ||
    1962        5580 :                     (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_UN_OP)))
    1963             :         {
    1964           0 :             SetError( errVariableExpected);
    1965           0 :             if ( bAutoCorrect && !pStack )
    1966             :             {
    1967           0 :                 if ( eOp == eLastOp || eLastOp == ocOpen )
    1968             :                 {   // throw away duplicated operator
    1969           0 :                     aCorrectedSymbol = "";
    1970           0 :                     bCorrected = true;
    1971             :                 }
    1972             :                 else
    1973             :                 {
    1974           0 :                     sal_Int32 nPos = aCorrectedFormula.getLength();
    1975           0 :                     if ( nPos )
    1976             :                     {
    1977           0 :                         nPos--;
    1978           0 :                         sal_Unicode c = aCorrectedFormula[ nPos ];
    1979           0 :                         switch ( eOp )
    1980             :                         {   // swap operators
    1981             :                             case ocGreater:
    1982           0 :                                 if ( c == mxSymbols->getSymbolChar( ocEqual) )
    1983             :                                 {   // >= instead of =>
    1984           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    1985           0 :                                         OUString( mxSymbols->getSymbolChar(ocGreater) ) );
    1986           0 :                                     aCorrectedSymbol = OUString(c);
    1987           0 :                                     bCorrected = true;
    1988             :                                 }
    1989           0 :                             break;
    1990             :                             case ocLess:
    1991           0 :                                 if ( c == mxSymbols->getSymbolChar( ocEqual) )
    1992             :                                 {   // <= instead of =<
    1993           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    1994           0 :                                         OUString( mxSymbols->getSymbolChar(ocLess) ) );
    1995           0 :                                     aCorrectedSymbol = OUString(c);
    1996           0 :                                     bCorrected = true;
    1997             :                                 }
    1998           0 :                                 else if ( c == mxSymbols->getSymbolChar( ocGreater) )
    1999             :                                 {   // <> instead of ><
    2000           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    2001           0 :                                         OUString( mxSymbols->getSymbolChar(ocLess) ) );
    2002           0 :                                     aCorrectedSymbol = OUString(c);
    2003           0 :                                     bCorrected = true;
    2004             :                                 }
    2005           0 :                             break;
    2006             :                             case ocMul:
    2007           0 :                                 if ( c == mxSymbols->getSymbolChar( ocSub) )
    2008             :                                 {   // *- instead of -*
    2009           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    2010           0 :                                         OUString( mxSymbols->getSymbolChar(ocMul) ) );
    2011           0 :                                     aCorrectedSymbol = OUString(c);
    2012           0 :                                     bCorrected = true;
    2013             :                                 }
    2014           0 :                             break;
    2015             :                             case ocDiv:
    2016           0 :                                 if ( c == mxSymbols->getSymbolChar( ocSub) )
    2017             :                                 {   // /- instead of -/
    2018           0 :                                     aCorrectedFormula = aCorrectedFormula.replaceAt( nPos, 1,
    2019           0 :                                         OUString( mxSymbols->getSymbolChar(ocDiv) ) );
    2020           0 :                                     aCorrectedSymbol = OUString(c);
    2021           0 :                                     bCorrected = true;
    2022             :                                 }
    2023           0 :                             break;
    2024             :                             default:
    2025             :                                 ;   // nothing
    2026             :                         }
    2027             :                     }
    2028             :                 }
    2029             :             }
    2030             :         }
    2031       41139 :         eLastOp = eOp;
    2032             :     }
    2033       41139 :     return eOp;
    2034             : }
    2035       25320 : void FormulaCompiler::PutCode( FormulaTokenRef& p )
    2036             : {
    2037       25320 :     if( pc >= FORMULA_MAXTOKENS - 1 )
    2038             :     {
    2039           0 :         if ( pc == FORMULA_MAXTOKENS - 1 )
    2040             :         {
    2041           0 :             p = new FormulaByteToken( ocStop );
    2042           0 :             p->IncRef();
    2043           0 :             *pCode++ = p.get();
    2044           0 :             ++pc;
    2045             :         }
    2046           0 :         SetError( errCodeOverflow);
    2047           0 :         return;
    2048             :     }
    2049       25320 :     if( pArr->GetCodeError() && !bCompileForFAP )
    2050           0 :         return;
    2051       25320 :     ForceArrayOperator( p, pCurrentFactorToken);
    2052       25320 :     p->IncRef();
    2053       25320 :     *pCode++ = p.get();
    2054       25320 :     pc++;
    2055             : }
    2056             : 
    2057             : 
    2058           0 : bool FormulaCompiler::HandleExternalReference( const FormulaToken& /*_aToken*/)
    2059             : {
    2060           0 :     return true;
    2061             : }
    2062             : 
    2063           0 : bool FormulaCompiler::HandleRange()
    2064             : {
    2065           0 :     return true;
    2066             : }
    2067             : 
    2068           0 : bool FormulaCompiler::HandleSingleRef()
    2069             : {
    2070           0 :     return true;
    2071             : }
    2072             : 
    2073           0 : bool FormulaCompiler::HandleDbData()
    2074             : {
    2075           0 :     return true;
    2076             : }
    2077             : 
    2078           0 : void FormulaCompiler::CreateStringFromSingleRef( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
    2079             : {
    2080           0 : }
    2081             : 
    2082           0 : void FormulaCompiler::CreateStringFromDoubleRef( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
    2083             : {
    2084           0 : }
    2085             : 
    2086           0 : void FormulaCompiler::CreateStringFromIndex( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
    2087             : {
    2088           0 : }
    2089             : 
    2090           0 : void FormulaCompiler::CreateStringFromMatrix( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
    2091             : {
    2092           0 : }
    2093             : 
    2094           0 : void FormulaCompiler::CreateStringFromExternal( OUStringBuffer& /*rBuffer*/, FormulaToken* /*pTokenP*/) const
    2095             : {
    2096           0 : }
    2097             : 
    2098           0 : void FormulaCompiler::LocalizeString( OUString& /*rName*/ ) const
    2099             : {
    2100           0 : }
    2101             : 
    2102         132 : void FormulaCompiler::PushTokenArray( FormulaTokenArray* pa, bool bTemp )
    2103             : {
    2104         132 :     if ( bAutoCorrect && !pStack )
    2105             :     {   // don't merge stacked subroutine code into entered formula
    2106           0 :         aCorrectedFormula += aCorrectedSymbol;
    2107           0 :         aCorrectedSymbol = "";
    2108             :     }
    2109         132 :     FormulaArrayStack* p = new FormulaArrayStack;
    2110         132 :     p->pNext      = pStack;
    2111         132 :     p->pArr       = pArr;
    2112         132 :     p->bTemp      = bTemp;
    2113         132 :     pStack        = p;
    2114         132 :     pArr          = pa;
    2115         132 : }
    2116             : 
    2117             : } // namespace formula
    2118             : 
    2119             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10