LCOV - code coverage report
Current view: top level - sc/source/core/tool - compiler.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1399 2619 53.4 %
Date: 2015-06-13 12:38:46 Functions: 116 158 73.4 %
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             : 
      20             : #include <config_features.h>
      21             : 
      22             : #include "compiler.hxx"
      23             : 
      24             : #include <sfx2/app.hxx>
      25             : #include <sfx2/objsh.hxx>
      26             : #include <basic/sbmeth.hxx>
      27             : #include <basic/sbstar.hxx>
      28             : #include <svl/zforlist.hxx>
      29             : #include <svl/sharedstringpool.hxx>
      30             : #include <sal/macros.h>
      31             : #include <tools/rcid.h>
      32             : #include <tools/solar.h>
      33             : #include <unotools/charclass.hxx>
      34             : #include <com/sun/star/lang/Locale.hpp>
      35             : #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
      36             : #include <com/sun/star/sheet/FormulaLanguage.hpp>
      37             : #include <com/sun/star/sheet/FormulaMapGroup.hpp>
      38             : #include <comphelper/processfactory.hxx>
      39             : #include <comphelper/string.hxx>
      40             : #include <unotools/transliterationwrapper.hxx>
      41             : #include <tools/urlobj.hxx>
      42             : #include <rtl/math.hxx>
      43             : #include <rtl/ustring.hxx>
      44             : #include <svtools/miscopt.hxx>
      45             : #include <ctype.h>
      46             : #include <stdlib.h>
      47             : #include <string.h>
      48             : #include <math.h>
      49             : #include "rangenam.hxx"
      50             : #include "dbdata.hxx"
      51             : #include "document.hxx"
      52             : #include "callform.hxx"
      53             : #include "addincol.hxx"
      54             : #include "refupdat.hxx"
      55             : #include "scresid.hxx"
      56             : #include "sc.hrc"
      57             : #include "globstr.hrc"
      58             : #include "formulacell.hxx"
      59             : #include "dociter.hxx"
      60             : #include "docoptio.hxx"
      61             : #include <formula/errorcodes.hxx>
      62             : #include "parclass.hxx"
      63             : #include "autonamecache.hxx"
      64             : #include "externalrefmgr.hxx"
      65             : #include "rangeutl.hxx"
      66             : #include "convuno.hxx"
      67             : #include "tokenuno.hxx"
      68             : #include "formulaparserpool.hxx"
      69             : #include "tokenarray.hxx"
      70             : #include "scmatrix.hxx"
      71             : #include <tokenstringcontext.hxx>
      72             : 
      73             : using namespace formula;
      74             : using namespace ::com::sun::star;
      75             : using ::std::vector;
      76             : 
      77             : CharClass*                          ScCompiler::pCharClassEnglish = NULL;
      78             : const ScCompiler::Convention*       ScCompiler::pConventions[ ]   = { NULL, NULL, NULL, NULL, NULL, NULL };
      79             : 
      80             : enum ScanState
      81             : {
      82             :     ssGetChar,
      83             :     ssGetBool,
      84             :     ssGetValue,
      85             :     ssGetString,
      86             :     ssSkipString,
      87             :     ssGetIdent,
      88             :     ssGetReference,
      89             :     ssSkipReference,
      90             :     ssGetErrorConstant,
      91             :     ssGetTableRefItem,
      92             :     ssGetTableRefColumn,
      93             :     ssStop
      94             : };
      95             : 
      96             : static const sal_Char* pInternal[2] = { "TTT", "__DEBUG_VAR" };
      97             : 
      98             : using namespace ::com::sun::star::i18n;
      99             : 
     100          55 : void ScCompiler::fillFromAddInMap( NonConstOpCodeMapPtr xMap,FormulaGrammar::Grammar _eGrammar  ) const
     101             : {
     102             :     size_t nSymbolOffset;
     103          55 :     switch( _eGrammar )
     104             :     {
     105             :         case FormulaGrammar::GRAM_PODF:
     106          13 :             nSymbolOffset = offsetof( AddInMap, pUpper);
     107          13 :             break;
     108             :         default:
     109             :         case FormulaGrammar::GRAM_ODFF:
     110          38 :             nSymbolOffset = offsetof( AddInMap, pODFF);
     111          38 :             break;
     112             :         case FormulaGrammar::GRAM_ENGLISH:
     113           4 :             nSymbolOffset = offsetof( AddInMap, pEnglish);
     114           4 :             break;
     115             :     }
     116          55 :     const AddInMap* pMap = GetAddInMap();
     117          55 :     const AddInMap* const pStop = pMap + GetAddInMapCount();
     118        6050 :     for ( ; pMap < pStop; ++pMap)
     119             :     {
     120             :         char const * const * ppSymbol =
     121             :             reinterpret_cast< char const * const * >(
     122        5995 :                     reinterpret_cast< char const * >(pMap) + nSymbolOffset);
     123             :         xMap->putExternal( OUString::createFromAscii( *ppSymbol),
     124        5995 :                 OUString::createFromAscii( pMap->pOriginal));
     125             :     }
     126          55 : }
     127             : 
     128          51 : void ScCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr xMap ) const
     129             : {
     130          51 :     ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
     131          51 :     long nCount = pColl->GetFuncCount();
     132        4385 :     for (long i=0; i < nCount; ++i)
     133             :     {
     134        4334 :         const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
     135        4334 :         if (pFuncData)
     136        2914 :             xMap->putExternalSoftly( pFuncData->GetUpperName(),
     137        5828 :                     pFuncData->GetOriginalName());
     138             :     }
     139          51 : }
     140             : 
     141           4 : void ScCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr xMap ) const
     142             : {
     143           4 :     ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
     144           4 :     long nCount = pColl->GetFuncCount();
     145         406 :     for (long i=0; i < nCount; ++i)
     146             :     {
     147         402 :         const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
     148         402 :         if (pFuncData)
     149             :         {
     150         242 :             OUString aName;
     151         242 :             if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
     152         242 :                 xMap->putExternalSoftly( aName, pFuncData->GetOriginalName());
     153             :             else
     154           0 :                 xMap->putExternalSoftly( pFuncData->GetUpperName(),
     155           0 :                         pFuncData->GetOriginalName());
     156             :         }
     157             :     }
     158           4 : }
     159             : 
     160          16 : void ScCompiler::DeInit()
     161             : {
     162          16 :     if (pCharClassEnglish)
     163             :     {
     164          10 :         delete pCharClassEnglish;
     165          10 :         pCharClassEnglish = NULL;
     166             :     }
     167          16 : }
     168             : 
     169           0 : bool ScCompiler::IsEnglishSymbol( const OUString& rName )
     170             : {
     171             :     // function names are always case-insensitive
     172           0 :     OUString aUpper = ScGlobal::pCharClass->uppercase(rName);
     173             : 
     174             :     // 1. built-in function name
     175           0 :     OpCode eOp = ScCompiler::GetEnglishOpCode( aUpper );
     176           0 :     if ( eOp != ocNone )
     177             :     {
     178           0 :         return true;
     179             :     }
     180             :     // 2. old add in functions
     181           0 :     if (ScGlobal::GetFuncCollection()->findByName(aUpper))
     182             :     {
     183           0 :         return true;
     184             :     }
     185             : 
     186             :     // 3. new (uno) add in functions
     187           0 :     OUString aIntName = ScGlobal::GetAddInCollection()->FindFunction(aUpper, false);
     188           0 :     if (!aIntName.isEmpty())
     189             :     {
     190           0 :         return true;
     191             :     }
     192           0 :     return false;       // no valid function name
     193             : }
     194             : 
     195          37 : void ScCompiler::InitCharClassEnglish()
     196             : {
     197          37 :     ::com::sun::star::lang::Locale aLocale( "en", "US", "");
     198             :     pCharClassEnglish = new CharClass(
     199          37 :             ::comphelper::getProcessComponentContext(), LanguageTag( aLocale));
     200          37 : }
     201             : 
     202       45501 : void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar )
     203             : {
     204             :     OSL_ENSURE( eGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "ScCompiler::SetGrammar: don't pass FormulaGrammar::GRAM_UNSPECIFIED");
     205       45501 :     if (eGrammar == GetGrammar())
     206       45611 :         return;     // nothing to be done
     207             : 
     208       45391 :     if( eGrammar == FormulaGrammar::GRAM_EXTERNAL )
     209             :     {
     210           0 :         meGrammar = eGrammar;
     211           0 :         mxSymbols = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE);
     212             :     }
     213             :     else
     214             :     {
     215       45391 :         FormulaGrammar::Grammar eMyGrammar = eGrammar;
     216       45391 :         const sal_Int32 nFormulaLanguage = FormulaGrammar::extractFormulaLanguage( eMyGrammar);
     217       45391 :         OpCodeMapPtr xMap = GetOpCodeMap( nFormulaLanguage);
     218             :         OSL_ENSURE( xMap, "ScCompiler::SetGrammar: unknown formula language");
     219       45391 :         if (!xMap)
     220             :         {
     221           0 :             xMap = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE);
     222           0 :             eMyGrammar = xMap->getGrammar();
     223             :         }
     224             : 
     225             :         // Save old grammar for call to SetGrammarAndRefConvention().
     226       45391 :         FormulaGrammar::Grammar eOldGrammar = GetGrammar();
     227             :         // This also sets the grammar associated with the map!
     228       45391 :         SetFormulaLanguage( xMap);
     229             : 
     230             :         // Override if necessary.
     231       45391 :         if (eMyGrammar != GetGrammar())
     232        5664 :             SetGrammarAndRefConvention( eMyGrammar, eOldGrammar);
     233             :     }
     234             : }
     235             : 
     236             : // Unclear how this was intended to be refreshed when the
     237             : // grammar or sheet count is changed ? Ideally this would be
     238             : // a method on Document that would globally cache these.
     239       28654 : std::vector<OUString> &ScCompiler::GetSetupTabNames() const
     240             : {
     241       28654 :     std::vector<OUString> &rTabNames = const_cast<ScCompiler *>(this)->maTabNames;
     242             : 
     243       28654 :     if (pDoc && rTabNames.empty())
     244             :     {
     245       26563 :         rTabNames = pDoc->GetAllTableNames();
     246       26563 :         std::vector<OUString>::iterator it = rTabNames.begin(), itEnd = rTabNames.end();
     247       54895 :         for (; it != itEnd; ++it)
     248       28332 :             ScCompiler::CheckTabQuotes(*it, formula::FormulaGrammar::extractRefConvention(meGrammar));
     249             :     }
     250             : 
     251       28654 :     return rTabNames;
     252             : }
     253             : 
     254         725 : void ScCompiler::SetNumberFormatter( SvNumberFormatter* pFormatter )
     255             : {
     256         725 :     mpFormatter = pFormatter;
     257         725 : }
     258             : 
     259       45844 : void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr & xMap )
     260             : {
     261       45844 :     if (xMap.get())
     262             :     {
     263       45844 :         mxSymbols = xMap;
     264       45844 :         if (mxSymbols->isEnglish())
     265             :         {
     266        7689 :             if (!pCharClassEnglish)
     267          37 :                 InitCharClassEnglish();
     268        7689 :             pCharClass = pCharClassEnglish;
     269             :         }
     270             :         else
     271       38155 :             pCharClass = ScGlobal::pCharClass;
     272       45844 :         SetGrammarAndRefConvention( mxSymbols->getGrammar(), GetGrammar());
     273             :     }
     274       45844 : }
     275             : 
     276       51508 : void ScCompiler::SetGrammarAndRefConvention(
     277             :         const FormulaGrammar::Grammar eNewGrammar, const FormulaGrammar::Grammar eOldGrammar )
     278             : {
     279       51508 :     meGrammar = eNewGrammar;    // SetRefConvention needs the new grammar set!
     280       51508 :     FormulaGrammar::AddressConvention eConv = FormulaGrammar::extractRefConvention( meGrammar);
     281       51508 :     if (eConv == FormulaGrammar::CONV_UNSPECIFIED && eOldGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
     282             :     {
     283       85618 :         if (pDoc)
     284       42809 :             SetRefConvention( pDoc->GetAddressConvention());
     285             :         else
     286           0 :             SetRefConvention( GetRefConvention( FormulaGrammar::CONV_OOO ) );
     287             :     }
     288             :     else
     289        8699 :         SetRefConvention( eConv );
     290       51508 : }
     291             : 
     292           0 : OUString ScCompiler::FindAddInFunction( const OUString& rUpperName, bool bLocalFirst ) const
     293             : {
     294           0 :     return ScGlobal::GetAddInCollection()->FindFunction(rUpperName, bLocalFirst);    // bLocalFirst=false for english
     295             : }
     296             : 
     297          87 : ScCompiler::Convention::~Convention()
     298             : {
     299          87 :     delete [] mpCharTable;
     300          87 :     mpCharTable = NULL;
     301          87 : }
     302             : 
     303          87 : ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv )
     304             :         :
     305          87 :     meConv( eConv )
     306             : {
     307             :     int i;
     308          87 :     sal_uLong *t= new sal_uLong [128];
     309             : 
     310          87 :     ScCompiler::pConventions[ meConv ] = this;
     311          87 :     mpCharTable = t;
     312             : 
     313       11223 :     for (i = 0; i < 128; i++)
     314       11136 :         t[i] = SC_COMPILER_C_ILLEGAL;
     315             : 
     316             : // tdf#56036: Allow tabs/newlines in imported formulas (for now simply treat them as (and convert to) space)
     317             : // TODO: tdf#76310: allow saving newlines as is (as per OpenFormula specification v.1.2, clause 5.14 "Whitespace")
     318             : // This is compliant with the OASIS decision (see https://issues.oasis-open.org/browse/OFFICE-701)
     319             : // Also, this would enable correct roundtrip from/to OOXML without loosing tabs/newlines
     320             : // This requires saving actual space characters in ocSpaces token, using them in UI and saving
     321          87 : /* tab */   t[ 9] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     322          87 : /* lf  */   t[10] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     323          87 : /* cr  */   t[13] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     324             : 
     325          87 : /*   */     t[32] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     326          87 : /* ! */     t[33] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     327          87 :             if (FormulaGrammar::CONV_ODF == meConv)
     328          37 : /* ! */         t[33] |= SC_COMPILER_C_ODF_LABEL_OP;
     329          87 : /* " */     t[34] = SC_COMPILER_C_CHAR_STRING | SC_COMPILER_C_STRING_SEP;
     330          87 : /* # */     t[35] = SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_CHAR_ERRCONST;
     331          87 : /* $ */     t[36] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT;
     332          87 :             if (FormulaGrammar::CONV_ODF == meConv)
     333          37 : /* $ */         t[36] |= SC_COMPILER_C_ODF_NAME_MARKER;
     334          87 : /* % */     t[37] = SC_COMPILER_C_VALUE;
     335          87 : /* & */     t[38] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     336          87 : /* ' */     t[39] = SC_COMPILER_C_NAME_SEP;
     337          87 : /* ( */     t[40] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     338          87 : /* ) */     t[41] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     339          87 : /* * */     t[42] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     340          87 : /* + */     t[43] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
     341          87 : /* , */     t[44] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE;
     342          87 : /* - */     t[45] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
     343          87 : /* . */     t[46] = SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME;
     344          87 : /* / */     t[47] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     345             : 
     346         957 :             for (i = 48; i < 58; i++)
     347         870 : /* 0-9 */       t[i] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_WORD | SC_COMPILER_C_VALUE | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME;
     348             : 
     349          87 : /* : */     t[58] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD;
     350          87 : /* ; */     t[59] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     351          87 : /* < */     t[60] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     352          87 : /* = */     t[61] = SC_COMPILER_C_CHAR | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     353          87 : /* > */     t[62] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     354          87 : /* ? */     t[63] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_NAME;
     355             : /* @ */     // FREE
     356             : 
     357        2349 :     for (i = 65; i < 91; i++)
     358        2262 : /* A-Z */   t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME;
     359             : 
     360          87 :     if (FormulaGrammar::CONV_ODF == meConv)
     361             :     {
     362          37 : /* [ */     t[91] = SC_COMPILER_C_ODF_LBRACKET;
     363             : /* \ */     // FREE
     364          37 : /* ] */     t[93] = SC_COMPILER_C_ODF_RBRACKET;
     365             :     }
     366          50 :     else if (FormulaGrammar::CONV_OOO == meConv)
     367             :     {
     368          38 : /* [ */     t[91] = SC_COMPILER_C_CHAR;
     369             : /* \ */     // FREE
     370          38 : /* ] */     t[93] = SC_COMPILER_C_CHAR;
     371             :     }
     372          12 :     else if (FormulaGrammar::CONV_XL_OOX == meConv)
     373             :     {
     374           5 : /* [ */     t[91] = SC_COMPILER_C_CHAR | SC_COMPILER_C_CHAR_IDENT;
     375             : /* \ */     // FREE
     376           5 : /* ] */     t[93] = SC_COMPILER_C_CHAR | SC_COMPILER_C_IDENT;
     377             :     }
     378           7 :     else if (FormulaGrammar::CONV_XL_A1 == meConv)
     379             :     {
     380           4 : /* [ */     t[91] = SC_COMPILER_C_CHAR;
     381             : /* \ */     // FREE
     382           4 : /* ] */     t[93] = SC_COMPILER_C_CHAR;
     383             :     }
     384           3 :     else if( FormulaGrammar::CONV_XL_R1C1 == meConv )
     385             :     {
     386           3 : /* [ */     t[91] = SC_COMPILER_C_IDENT;
     387             : /* \ */     // FREE
     388           3 : /* ] */     t[93] = SC_COMPILER_C_IDENT;
     389             :     }
     390             :     else
     391             :     {
     392             : /* [ */     // FREE
     393             : /* \ */     // FREE
     394             : /* ] */     // FREE
     395             :     }
     396             : 
     397          87 : /* ^ */     t[94] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     398          87 : /* _ */     t[95] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME;
     399             : /* ` */     // FREE
     400             : 
     401        2349 :             for (i = 97; i < 123; i++)
     402        2262 : /* a-z */       t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME;
     403             : 
     404          87 : /* { */     t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open
     405          87 : /* | */     t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific)
     406          87 : /* } */     t[125] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array close
     407          87 : /* ~ */     t[126] = SC_COMPILER_C_CHAR;        // OOo specific
     408             : /* 127 */   // FREE
     409             : 
     410          87 :     if( FormulaGrammar::CONV_XL_A1 == meConv || FormulaGrammar::CONV_XL_R1C1 == meConv || FormulaGrammar::CONV_XL_OOX == meConv )
     411             :     {
     412          12 : /*   */     t[32] |=   SC_COMPILER_C_WORD;
     413          12 : /* ! */     t[33] |=   SC_COMPILER_C_IDENT | SC_COMPILER_C_WORD;
     414          12 : /* " */     t[34] |=   SC_COMPILER_C_WORD;
     415          12 : /* # */     t[35] &= (~SC_COMPILER_C_WORD_SEP);
     416          12 : /* # */     t[35] |=   SC_COMPILER_C_WORD;
     417          12 : /* % */     t[37] |=   SC_COMPILER_C_WORD;
     418          12 : /* ' */     t[39] |=   SC_COMPILER_C_WORD;
     419             : 
     420          12 : /* % */     t[37] |=   SC_COMPILER_C_WORD;
     421          12 : /* & */     t[38] |=   SC_COMPILER_C_WORD;
     422          12 : /* ' */     t[39] |=   SC_COMPILER_C_WORD;
     423          12 : /* ( */     t[40] |=   SC_COMPILER_C_WORD;
     424          12 : /* ) */     t[41] |=   SC_COMPILER_C_WORD;
     425          12 : /* * */     t[42] |=   SC_COMPILER_C_WORD;
     426          12 : /* + */     t[43] |=   SC_COMPILER_C_WORD;
     427             : #if 0 /* this really needs to be locale specific. */
     428             : /* , */     t[44]  =   SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     429             : #else
     430          12 : /* , */     t[44] |=   SC_COMPILER_C_WORD;
     431             : #endif
     432          12 : /* - */     t[45] |=   SC_COMPILER_C_WORD;
     433             : 
     434          12 : /* ; */     t[59] |=   SC_COMPILER_C_WORD;
     435          12 : /* < */     t[60] |=   SC_COMPILER_C_WORD;
     436          12 : /* = */     t[61] |=   SC_COMPILER_C_WORD;
     437          12 : /* > */     t[62] |=   SC_COMPILER_C_WORD;
     438             : /* ? */     // question really is not permitted in sheet name
     439          12 : /* @ */     t[64] |=   SC_COMPILER_C_WORD;
     440          12 : /* [ */     t[91] |=   SC_COMPILER_C_WORD;
     441          12 : /* ] */     t[93] |=   SC_COMPILER_C_WORD;
     442          12 : /* { */     t[123]|=   SC_COMPILER_C_WORD;
     443          12 : /* | */     t[124]|=   SC_COMPILER_C_WORD;
     444          12 : /* } */     t[125]|=   SC_COMPILER_C_WORD;
     445          12 : /* ~ */     t[126]|=   SC_COMPILER_C_WORD;
     446             :     }
     447          87 : }
     448             : 
     449         463 : static bool lcl_isValidQuotedText( const OUString& rFormula, sal_Int32 nSrcPos, ParseResult& rRes )
     450             : {
     451             :     // Tokens that start at ' can have anything in them until a final '
     452             :     // but '' marks an escaped '
     453             :     // We've earlier guaranteed that a string containing '' will be
     454             :     // surrounded by '
     455         463 :     if (nSrcPos < rFormula.getLength() && rFormula[nSrcPos] == '\'')
     456             :     {
     457         173 :         sal_Int32 nPos = nSrcPos+1;
     458        2615 :         while (nPos < rFormula.getLength())
     459             :         {
     460        2442 :             if (rFormula[nPos] == '\'')
     461             :             {
     462         177 :                 if ( (nPos+1 == rFormula.getLength()) || (rFormula[nPos+1] != '\'') )
     463             :                 {
     464         173 :                     rRes.TokenType = KParseType::SINGLE_QUOTE_NAME;
     465         173 :                     rRes.EndPos = nPos+1;
     466         173 :                     return true;
     467             :                 }
     468           4 :                 ++nPos;
     469             :             }
     470        2269 :             ++nPos;
     471             :         }
     472             :     }
     473             : 
     474         290 :     return false;
     475             : }
     476             : 
     477          30 : static bool lcl_parseExternalName(
     478             :         const OUString& rSymbol,
     479             :         OUString& rFile,
     480             :         OUString& rName,
     481             :         const sal_Unicode cSep,
     482             :         const ScDocument* pDoc = NULL,
     483             :         const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks = NULL )
     484             : {
     485             :     /* TODO: future versions will have to support sheet-local names too, thus
     486             :      * return a possible sheet name as well. */
     487          30 :     const sal_Unicode* const pStart = rSymbol.getStr();
     488          30 :     const sal_Unicode* p = pStart;
     489          30 :     sal_Int32 nLen = rSymbol.getLength();
     490          60 :     OUString aTmpFile, aTmpName;
     491          30 :     sal_Int32 i = 0;
     492          30 :     bool bInName = false;
     493          30 :     if (cSep == '!')
     494             :     {
     495             :         // For XL use existing parser that resolves bracketed and quoted and
     496             :         // indexed external document names.
     497           3 :         ScRange aRange;
     498           3 :         OUString aStartTabName, aEndTabName;
     499           3 :         sal_uInt16 nFlags = 0;
     500             :         p = aRange.Parse_XL_Header( p, pDoc, aTmpFile, aStartTabName,
     501           3 :                 aEndTabName, nFlags, true, pExternalLinks );
     502           3 :         if (!p || p == pStart)
     503           3 :             return false;
     504           0 :         i = sal_Int32(p - pStart);
     505             :     }
     506         188 :     for ( ; i < nLen; ++i, ++p)
     507             :     {
     508         162 :         sal_Unicode c = *p;
     509         162 :         if (i == 0)
     510             :         {
     511          27 :             if (c == '.' || c == cSep)
     512           0 :                 return false;
     513             : 
     514          27 :             if (c == '\'')
     515             :             {
     516             :                 // Move to the next char and loop until the second single
     517             :                 // quote.
     518           1 :                 sal_Unicode cPrev = c;
     519           1 :                 ++i; ++p;
     520          27 :                 for (sal_Int32 j = i; j < nLen; ++j, ++p)
     521             :                 {
     522          27 :                     c = *p;
     523          27 :                     if (c == '\'')
     524             :                     {
     525           1 :                         if (j == i)
     526             :                         {
     527             :                             // empty quote e.g. (=''!Name)
     528           0 :                             return false;
     529             :                         }
     530             : 
     531           1 :                         if (cPrev == '\'')
     532             :                         {
     533             :                             // two consecutive quotes equal a single quote in
     534             :                             // the file name.
     535           0 :                             aTmpFile += OUString(c);
     536           0 :                             cPrev = 'a';
     537             :                         }
     538             :                         else
     539           1 :                             cPrev = c;
     540             : 
     541           1 :                         continue;
     542             :                     }
     543             : 
     544          26 :                     if (cPrev == '\'' && j != i)
     545             :                     {
     546             :                         // this is not a quote but the previous one is.  This
     547             :                         // ends the parsing of the quoted segment.  At this
     548             :                         // point, the current char must equal the separator
     549             :                         // char.
     550             : 
     551           1 :                         i = j;
     552           1 :                         bInName = true;
     553           1 :                         aTmpName += OUString(c); // Keep the separator as part of the name.
     554           1 :                         break;
     555             :                     }
     556          25 :                     aTmpFile += OUString(c);
     557          25 :                     cPrev = c;
     558             :                 }
     559             : 
     560           1 :                 if (!bInName)
     561             :                 {
     562             :                     // premature ending of the quoted segment.
     563           0 :                     return false;
     564             :                 }
     565             : 
     566           1 :                 if (c != cSep)
     567             :                 {
     568             :                     // only the separator is allowed after the closing quote.
     569           0 :                     return false;
     570             :                 }
     571             : 
     572           1 :                 continue;
     573             :             }
     574             :         }
     575             : 
     576         161 :         if (bInName)
     577             :         {
     578          11 :             if (c == cSep)
     579             :             {
     580             :                 // A second separator ?  Not a valid external name.
     581           0 :                 return false;
     582             :             }
     583          11 :             aTmpName += OUString(c);
     584             :         }
     585             :         else
     586             :         {
     587         150 :             if (c == cSep)
     588             :             {
     589           0 :                 bInName = true;
     590           0 :                 aTmpName += OUString(c); // Keep the separator as part of the name.
     591             :             }
     592             :             else
     593             :             {
     594             :                 do
     595             :                 {
     596         150 :                     if (rtl::isAsciiAlphanumeric(c))
     597             :                         // allowed.
     598         149 :                         break;
     599             : 
     600           1 :                     if (c > 128)
     601             :                         // non-ASCII character is allowed.
     602           0 :                         break;
     603             : 
     604           1 :                     bool bValid = false;
     605           1 :                     switch (c)
     606             :                     {
     607             :                         case '_':
     608             :                         case '-':
     609             :                         case '.':
     610             :                             // these special characters are allowed.
     611           0 :                             bValid = true;
     612           0 :                             break;
     613             :                     }
     614           1 :                     if (bValid)
     615           0 :                         break;
     616             : 
     617           1 :                     return false;
     618             :                 }
     619             :                 while (false);
     620         149 :                 aTmpFile += OUString(c);
     621             :             }
     622             :         }
     623             :     }
     624             : 
     625          26 :     if (!bInName)
     626             :     {
     627             :         // No name found - most likely the symbol has no '!'s.
     628          25 :         return false;
     629             :     }
     630             : 
     631           1 :     sal_Int32 nNameLen = aTmpName.getLength();
     632           1 :     if (nNameLen < 2)
     633             :     {
     634             :         // Name must be at least 2-char long (separator plus name).
     635           0 :         return false;
     636             :     }
     637             : 
     638           1 :     if (aTmpName[0] != cSep)
     639             :     {
     640             :         // 1st char of the name must equal the separator.
     641           0 :         return false;
     642             :     }
     643             : 
     644           1 :     if (aTmpName[nNameLen-1] == '!')
     645             :     {
     646             :         // Check against #REF!.
     647           0 :         if (aTmpName == "#REF!")
     648           0 :             return false;
     649             :     }
     650             : 
     651           1 :     rFile = aTmpFile;
     652           1 :     rName = aTmpName.copy(1); // Skip the first char as it is always the separator.
     653          31 :     return true;
     654             : }
     655             : 
     656           0 : static OUString lcl_makeExternalNameStr(const OUString& rFile, const OUString& rName,
     657             :         const sal_Unicode cSep, bool bODF )
     658             : {
     659           0 :     OUString aEscQuote("''");
     660           0 :     OUString aFile(rFile.replaceAll("'", aEscQuote));
     661           0 :     OUString aName(rName);
     662           0 :     if (bODF)
     663           0 :         aName = aName.replaceAll("'", aEscQuote);
     664           0 :     OUStringBuffer aBuf(aFile.getLength() + aName.getLength() + 9);
     665           0 :     if (bODF)
     666           0 :         aBuf.append( '[');
     667           0 :     aBuf.append( "'" + aFile + "'" + OUString(cSep));
     668           0 :     if (bODF)
     669           0 :         aBuf.append( "$$'" );
     670           0 :     aBuf.append( aName);
     671           0 :     if (bODF)
     672           0 :         aBuf.append( "']" );
     673           0 :     return aBuf.makeStringAndClear();
     674             : }
     675             : 
     676           0 : static bool lcl_getLastTabName( OUString& rTabName2, const OUString& rTabName1,
     677             :                                 const vector<OUString>& rTabNames, const ScRange& rRef )
     678             : {
     679           0 :     SCsTAB nTabSpan = rRef.aEnd.Tab() - rRef.aStart.Tab();
     680           0 :     if (nTabSpan > 0)
     681             :     {
     682           0 :         size_t nCount = rTabNames.size();
     683           0 :         vector<OUString>::const_iterator itrBeg = rTabNames.begin(), itrEnd = rTabNames.end();
     684           0 :         vector<OUString>::const_iterator itr = ::std::find(itrBeg, itrEnd, rTabName1);
     685           0 :         if (itr == rTabNames.end())
     686             :         {
     687           0 :             rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
     688           0 :             return false;
     689             :         }
     690             : 
     691           0 :         size_t nDist = ::std::distance(itrBeg, itr);
     692           0 :         if (nDist + static_cast<size_t>(nTabSpan) >= nCount)
     693             :         {
     694           0 :             rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
     695           0 :             return false;
     696             :         }
     697             : 
     698           0 :         rTabName2 = rTabNames[nDist+nTabSpan];
     699             :     }
     700             :     else
     701           0 :         rTabName2 = rTabName1;
     702             : 
     703           0 :     return true;
     704             : }
     705             : 
     706          84 : struct Convention_A1 : public ScCompiler::Convention
     707             : {
     708          84 :     Convention_A1( FormulaGrammar::AddressConvention eConv ) : ScCompiler::Convention( eConv ) { }
     709             :     static void MakeColStr( OUStringBuffer& rBuffer, SCCOL nCol );
     710             :     static void MakeRowStr( OUStringBuffer& rBuffer, SCROW nRow );
     711             : 
     712         459 :     ParseResult parseAnyToken( const OUString& rFormula,
     713             :                                sal_Int32 nSrcPos,
     714             :                                const CharClass* pCharClass) const SAL_OVERRIDE
     715             :     {
     716         459 :         ParseResult aRet;
     717         459 :         if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
     718         173 :             return aRet;
     719             : 
     720             :         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
     721             :             KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
     722             :         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
     723             :         // '?' allowed in range names because of Xcl :-/
     724             :         static const char aAddAllowed[] = "?#";
     725             :         return pCharClass->parseAnyToken( rFormula,
     726         286 :                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
     727             :     }
     728             : 
     729      129151 :     virtual sal_uLong getCharTableFlags( sal_Unicode c, sal_Unicode /*cLast*/ ) const SAL_OVERRIDE
     730             :     {
     731      129151 :         return mpCharTable[static_cast<sal_uInt8>(c)];
     732             :     }
     733             : };
     734             : 
     735       44971 : void Convention_A1::MakeColStr( OUStringBuffer& rBuffer, SCCOL nCol )
     736             : {
     737       44971 :     if ( !ValidCol( nCol) )
     738           0 :         rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
     739             :     else
     740       44971 :         ::ScColToAlpha( rBuffer, nCol);
     741       44971 : }
     742             : 
     743       44974 : void Convention_A1::MakeRowStr( OUStringBuffer& rBuffer, SCROW nRow )
     744             : {
     745       44974 :     if ( !ValidRow(nRow) )
     746           0 :         rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
     747             :     else
     748       44974 :         rBuffer.append(sal_Int32(nRow + 1));
     749       44974 : }
     750             : 
     751          75 : struct ConventionOOO_A1 : public Convention_A1
     752             : {
     753          38 :     ConventionOOO_A1() : Convention_A1 (FormulaGrammar::CONV_OOO) { }
     754          37 :     ConventionOOO_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1 (eConv) { }
     755             : 
     756       26207 :     static void MakeTabStr( OUStringBuffer &rBuf, const std::vector<OUString>& rTabNames, SCTAB nTab )
     757             :     {
     758       26207 :         if (static_cast<size_t>(nTab) >= rTabNames.size())
     759           0 :             rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
     760             :         else
     761       26207 :             rBuf.append(rTabNames[nTab]);
     762       26207 :         rBuf.append('.');
     763       26207 :     }
     764             : 
     765       40631 :     static void MakeOneRefStrImpl(
     766             :         OUStringBuffer& rBuffer,
     767             :         const OUString& rErrRef, const std::vector<OUString>& rTabNames,
     768             :         const ScSingleRefData& rRef, const ScAddress& rAbsRef,
     769             :         bool bForceTab, bool bODF )
     770             :     {
     771       40631 :         if( rRef.IsFlag3D() || bForceTab )
     772             :         {
     773       26216 :             if (!ValidTab(rAbsRef.Tab()) || rRef.IsTabDeleted())
     774             :             {
     775           9 :                 if (!rRef.IsTabRel())
     776           3 :                     rBuffer.append('$');
     777           9 :                 rBuffer.append(rErrRef);
     778           9 :                 rBuffer.append('.');
     779             :             }
     780             :             else
     781             :             {
     782       26207 :                 if (!rRef.IsTabRel())
     783       25756 :                     rBuffer.append('$');
     784       26207 :                 MakeTabStr(rBuffer, rTabNames, rAbsRef.Tab());
     785             :             }
     786             :         }
     787       14415 :         else if (bODF)
     788         773 :             rBuffer.append('.');
     789       40631 :         if (!rRef.IsColRel())
     790       38870 :             rBuffer.append('$');
     791       40631 :         if (!ValidCol(rAbsRef.Col()) || rRef.IsColDeleted())
     792           3 :             rBuffer.append(rErrRef);
     793             :         else
     794       40628 :             MakeColStr(rBuffer, rAbsRef.Col());
     795       40631 :         if (!rRef.IsRowRel())
     796       38895 :             rBuffer.append('$');
     797       40631 :         if (!ValidRow(rAbsRef.Row()) || rRef.IsRowDeleted())
     798           0 :             rBuffer.append(rErrRef);
     799             :         else
     800       40631 :             MakeRowStr(rBuffer, rAbsRef.Row());
     801       40631 :     }
     802             : 
     803       26674 :     void makeRefStr( OUStringBuffer&   rBuffer,
     804             :                      formula::FormulaGrammar::Grammar /*eGram*/,
     805             :                      const ScAddress& rPos,
     806             :                      const OUString& rErrRef, const std::vector<OUString>& rTabNames,
     807             :                      const ScComplexRefData& rRef,
     808             :                      bool bSingleRef ) const SAL_OVERRIDE
     809             :     {
     810       26674 :         ScComplexRefData aRef( rRef );
     811             :         // In case absolute/relative positions weren't separately available:
     812             :         // transform relative to absolute!
     813       26674 :         ScAddress aAbs1 = aRef.Ref1.toAbs(rPos), aAbs2;
     814       26674 :         if( !bSingleRef )
     815       13122 :             aAbs2 = aRef.Ref2.toAbs(rPos);
     816             : 
     817       26674 :         MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref1, aAbs1, false, false);
     818       26674 :         if (!bSingleRef)
     819             :         {
     820       13122 :             rBuffer.append(':');
     821       13122 :             MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref2, aAbs2, aAbs1.Tab() != aAbs2.Tab(), false);
     822             :         }
     823       26674 :     }
     824             : 
     825       45586 :     virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const SAL_OVERRIDE
     826             :     {
     827       45586 :         switch (eSymType)
     828             :         {
     829             :             case ScCompiler::Convention::ABS_SHEET_PREFIX:
     830       22793 :                 return '$';
     831             :             case ScCompiler::Convention::SHEET_SEPARATOR:
     832       22793 :                 return '.';
     833             :         }
     834             : 
     835           0 :         return sal_Unicode(0);
     836             :     }
     837             : 
     838          27 :     virtual bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
     839             :             const ScDocument* pDoc,
     840             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks ) const SAL_OVERRIDE
     841             :     {
     842          27 :         return lcl_parseExternalName(rSymbol, rFile, rName, '#', pDoc, pExternalLinks);
     843             :     }
     844             : 
     845           0 :     virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const OUString& rFile,
     846             :             const OUString& rName ) const SAL_OVERRIDE
     847             :     {
     848           0 :         return lcl_makeExternalNameStr( rFile, rName, '#', false);
     849             :     }
     850             : 
     851          76 :     static bool makeExternalSingleRefStr(
     852             :         OUStringBuffer& rBuffer, const OUString& rFileName, const OUString& rTabName,
     853             :         const ScSingleRefData& rRef, const ScAddress& rPos, bool bDisplayTabName, bool bEncodeUrl )
     854             :     {
     855          76 :         ScAddress aAbsRef = rRef.toAbs(rPos);
     856          76 :         if (bDisplayTabName)
     857             :         {
     858          56 :             OUString aFile;
     859          56 :             if (bEncodeUrl)
     860          35 :                 aFile = rFileName;
     861             :             else
     862          21 :                 aFile = INetURLObject::decode(rFileName, INetURLObject::DECODE_UNAMBIGUOUS);
     863             : 
     864          56 :             rBuffer.append("'" + aFile.replaceAll("'", "''") + "'#");
     865             : 
     866          56 :             if (!rRef.IsTabRel())
     867          56 :                 rBuffer.append('$');
     868          56 :             ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
     869             : 
     870          56 :             rBuffer.append('.');
     871             :         }
     872             : 
     873          76 :         if (!rRef.IsColRel())
     874           2 :             rBuffer.append('$');
     875          76 :         MakeColStr( rBuffer, aAbsRef.Col());
     876          76 :         if (!rRef.IsRowRel())
     877          31 :             rBuffer.append('$');
     878          76 :         MakeRowStr( rBuffer, aAbsRef.Row());
     879             : 
     880          76 :         return true;
     881             :     }
     882             : 
     883          36 :     static void makeExternalRefStrImpl(
     884             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     885             :         const OUString& rTabName, const ScSingleRefData& rRef, bool bODF )
     886             :     {
     887          36 :         if (bODF)
     888          19 :             rBuffer.append( '[');
     889             : 
     890          36 :         bool bEncodeUrl = bODF;
     891          36 :         makeExternalSingleRefStr(rBuffer, rFileName, rTabName, rRef, rPos, true, bEncodeUrl);
     892          36 :         if (bODF)
     893          19 :             rBuffer.append( ']');
     894          36 :     }
     895             : 
     896          17 :     virtual void makeExternalRefStr(
     897             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
     898             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
     899             :     {
     900          17 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabName, rRef, false);
     901          17 :     }
     902             : 
     903          20 :     static void makeExternalRefStrImpl(
     904             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     905             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
     906             :         const ScComplexRefData& rRef, bool bODF )
     907             :     {
     908          20 :         ScRange aAbsRange = rRef.toAbs(rPos);
     909             : 
     910          20 :         if (bODF)
     911          16 :             rBuffer.append( '[');
     912             :         // Ensure that there's always a closing bracket, no premature returns.
     913          20 :         bool bEncodeUrl = bODF;
     914             : 
     915             :         do
     916             :         {
     917          20 :             if (!makeExternalSingleRefStr(rBuffer, rFileName, rTabName, rRef.Ref1, rPos, true, bEncodeUrl))
     918           0 :                 break;
     919             : 
     920          20 :             rBuffer.append(':');
     921             : 
     922          20 :             OUString aLastTabName;
     923          20 :             bool bDisplayTabName = (aAbsRange.aStart.Tab() != aAbsRange.aEnd.Tab());
     924          20 :             if (bDisplayTabName)
     925             :             {
     926             :                 // Get the name of the last table.
     927           0 :                 if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, aAbsRange))
     928             :                 {
     929             :                     OSL_FAIL( "ConventionOOO_A1::makeExternalRefStrImpl: sheet name not found");
     930             :                     // aLastTabName contains #REF!, proceed.
     931             :                 }
     932             :             }
     933          20 :             else if (bODF)
     934          16 :                 rBuffer.append( '.');      // need at least the sheet separator in ODF
     935             :             makeExternalSingleRefStr(
     936          20 :                 rBuffer, rFileName, aLastTabName, rRef.Ref2, rPos, bDisplayTabName, bEncodeUrl);
     937             :         } while (false);
     938             : 
     939          20 :         if (bODF)
     940          16 :             rBuffer.append( ']');
     941          20 :     }
     942             : 
     943           4 :     virtual void makeExternalRefStr(
     944             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
     945             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
     946             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
     947             :     {
     948           4 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabNames, rTabName, rRef, false);
     949           4 :     }
     950             : };
     951             : 
     952          37 : struct ConventionOOO_A1_ODF : public ConventionOOO_A1
     953             : {
     954          37 :     ConventionOOO_A1_ODF() : ConventionOOO_A1 (FormulaGrammar::CONV_ODF) { }
     955         568 :     void makeRefStr( OUStringBuffer&   rBuffer,
     956             :                      formula::FormulaGrammar::Grammar eGram,
     957             :                      const ScAddress& rPos,
     958             :                      const OUString& rErrRef, const std::vector<OUString>& rTabNames,
     959             :                      const ScComplexRefData& rRef,
     960             :                      bool bSingleRef ) const SAL_OVERRIDE
     961             :     {
     962         568 :         rBuffer.append('[');
     963         568 :         ScComplexRefData aRef( rRef );
     964             :         // In case absolute/relative positions weren't separately available:
     965             :         // transform relative to absolute!
     966         568 :         ScAddress aAbs1 = aRef.Ref1.toAbs(rPos), aAbs2;
     967         568 :         if( !bSingleRef )
     968         267 :             aAbs2 = aRef.Ref2.toAbs(rPos);
     969             : 
     970         568 :         if (FormulaGrammar::isODFF(eGram) && (!ValidAddress(aAbs1) || !ValidAddress(aAbs2)))
     971             :         {
     972           0 :             rBuffer.append(rErrRef);
     973             :             // For ODFF write [#REF!], but not for PODF so apps reading ODF
     974             :             // 1.0/1.1 may have a better chance if they implemented the old
     975             :             // form.
     976             :         }
     977             :         else
     978             :         {
     979         568 :             MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref1, aAbs1, false, true);
     980         568 :             if (!bSingleRef)
     981             :             {
     982         267 :                 rBuffer.append(':');
     983         267 :                 MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref2, aAbs2, aAbs1.Tab() != aAbs2.Tab(), true);
     984             :             }
     985             :         }
     986         568 :         rBuffer.append(']');
     987         568 :     }
     988             : 
     989           0 :     virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const OUString& rFile,
     990             :             const OUString& rName ) const SAL_OVERRIDE
     991             :     {
     992           0 :         return lcl_makeExternalNameStr( rFile, rName, '#', true);
     993             :     }
     994             : 
     995          19 :     virtual void makeExternalRefStr(
     996             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
     997             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
     998             :     {
     999          19 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabName, rRef, true);
    1000          19 :     }
    1001             : 
    1002          16 :     virtual void makeExternalRefStr(
    1003             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
    1004             :         const std::vector<OUString>& rTabNames,
    1005             :         const OUString& rTabName, const ScComplexRefData& rRef ) const SAL_OVERRIDE
    1006             :     {
    1007          16 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabNames, rTabName, rRef, true);
    1008          16 :     }
    1009             : };
    1010             : 
    1011          12 : struct ConventionXL
    1012             : {
    1013          12 :     virtual ~ConventionXL()
    1014          12 :     {
    1015          12 :     }
    1016             : 
    1017         198 :     static void GetTab(
    1018             :         const ScAddress& rPos, const std::vector<OUString>& rTabNames,
    1019             :         const ScSingleRefData& rRef, OUString& rTabName )
    1020             :     {
    1021         198 :         ScAddress aAbs = rRef.toAbs(rPos);
    1022         198 :         if (rRef.IsTabDeleted() || static_cast<size_t>(aAbs.Tab()) >= rTabNames.size())
    1023             :         {
    1024           0 :             rTabName = ScGlobal::GetRscString( STR_NO_REF_TABLE );
    1025         198 :             return;
    1026             :         }
    1027         198 :         rTabName = rTabNames[aAbs.Tab()];
    1028             :     }
    1029             : 
    1030        3629 :     static void MakeTabStr( OUStringBuffer& rBuf,
    1031             :                             const ScAddress& rPos,
    1032             :                             const std::vector<OUString>& rTabNames,
    1033             :                             const ScComplexRefData& rRef,
    1034             :                             bool bSingleRef )
    1035             :     {
    1036        3629 :         if( rRef.Ref1.IsFlag3D() )
    1037             :         {
    1038         396 :             OUString aStartTabName, aEndTabName;
    1039             : 
    1040         198 :             GetTab(rPos, rTabNames, rRef.Ref1, aStartTabName);
    1041             : 
    1042         198 :             if( !bSingleRef && rRef.Ref2.IsFlag3D() )
    1043             :             {
    1044           0 :                 GetTab(rPos, rTabNames, rRef.Ref2, aEndTabName);
    1045             :             }
    1046             : 
    1047         198 :             rBuf.append( aStartTabName );
    1048         198 :             if( !bSingleRef && rRef.Ref2.IsFlag3D() && aStartTabName != aEndTabName )
    1049             :             {
    1050           0 :                 rBuf.append( ':' );
    1051           0 :                 rBuf.append( aEndTabName );
    1052             :             }
    1053             : 
    1054         396 :             rBuf.append( '!' );
    1055             :         }
    1056        3629 :     }
    1057             : 
    1058       16032 :     static sal_Unicode getSpecialSymbol( ScCompiler::Convention::SpecialSymbolType eSymType )
    1059             :     {
    1060       16032 :         switch (eSymType)
    1061             :         {
    1062             :             case ScCompiler::Convention::ABS_SHEET_PREFIX:
    1063        8016 :                 return sal_Unicode(0);
    1064             :             case ScCompiler::Convention::SHEET_SEPARATOR:
    1065        8016 :                 return '!';
    1066             :         }
    1067           0 :         return sal_Unicode(0);
    1068             :     }
    1069             : 
    1070           3 :     static bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
    1071             :             const ScDocument* pDoc,
    1072             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks )
    1073             :     {
    1074           3 :         return lcl_parseExternalName( rSymbol, rFile, rName, '!', pDoc, pExternalLinks);
    1075             :     }
    1076             : 
    1077           0 :     static OUString makeExternalNameStr( const OUString& rFile, const OUString& rName )
    1078             :     {
    1079           0 :         return lcl_makeExternalNameStr( rFile, rName, '!', false);
    1080             :     }
    1081             : 
    1082           0 :     static void makeExternalDocStr( OUStringBuffer& rBuffer, const OUString& rFullName, bool bEncodeUrl )
    1083             :     {
    1084             :         // Format that is easier to deal with inside OOo, because we use file
    1085             :         // URL, and all characetrs are allowed.  Check if it makes sense to do
    1086             :         // it the way Gnumeric does it.  Gnumeric doesn't use the URL form
    1087             :         // and allows relative file path.
    1088             :         //
    1089             :         //   ['file:///path/to/source/filename.xls']
    1090             : 
    1091           0 :         rBuffer.append('[');
    1092           0 :         rBuffer.append('\'');
    1093           0 :         OUString aFullName;
    1094           0 :         if (bEncodeUrl)
    1095           0 :             aFullName = rFullName;
    1096             :         else
    1097           0 :             aFullName = INetURLObject::decode(rFullName, INetURLObject::DECODE_UNAMBIGUOUS);
    1098             : 
    1099           0 :         const sal_Unicode* pBuf = aFullName.getStr();
    1100           0 :         sal_Int32 nLen = aFullName.getLength();
    1101           0 :         for (sal_Int32 i = 0; i < nLen; ++i)
    1102             :         {
    1103           0 :             const sal_Unicode c = pBuf[i];
    1104           0 :             if (c == '\'')
    1105           0 :                 rBuffer.append(c);
    1106           0 :             rBuffer.append(c);
    1107             :         }
    1108           0 :         rBuffer.append('\'');
    1109           0 :         rBuffer.append(']');
    1110           0 :     }
    1111             : 
    1112           0 :     static void makeExternalTabNameRange( OUStringBuffer& rBuf, const OUString& rTabName,
    1113             :                                           const vector<OUString>& rTabNames,
    1114             :                                           const ScRange& rRef )
    1115             :     {
    1116           0 :         OUString aLastTabName;
    1117           0 :         if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, rRef))
    1118             :         {
    1119           0 :             ScRangeStringConverter::AppendTableName(rBuf, aLastTabName);
    1120           0 :             return;
    1121             :         }
    1122             : 
    1123           0 :         ScRangeStringConverter::AppendTableName(rBuf, rTabName);
    1124           0 :         if (rTabName != aLastTabName)
    1125             :         {
    1126           0 :             rBuf.append(':');
    1127           0 :             ScRangeStringConverter::AppendTableName(rBuf, rTabName);
    1128           0 :         }
    1129             :     }
    1130             : 
    1131           0 :     virtual void parseExternalDocName( const OUString& rFormula, sal_Int32& rSrcPos ) const
    1132             :     {
    1133           0 :         sal_Int32 nLen = rFormula.getLength();
    1134           0 :         const sal_Unicode* p = rFormula.getStr();
    1135           0 :         sal_Unicode cPrev = 0;
    1136           0 :         for (sal_Int32 i = rSrcPos; i < nLen; ++i)
    1137             :         {
    1138           0 :             sal_Unicode c = p[i];
    1139           0 :             if (i == rSrcPos)
    1140             :             {
    1141             :                 // first character must be '['.
    1142           0 :                 if (c != '[')
    1143           0 :                     return;
    1144             :             }
    1145           0 :             else if (i == rSrcPos + 1)
    1146             :             {
    1147             :                 // second character must be a single quote.
    1148           0 :                 if (c != '\'')
    1149           0 :                     return;
    1150             :             }
    1151           0 :             else if (c == '\'')
    1152             :             {
    1153           0 :                 if (cPrev == '\'')
    1154             :                     // two successive single quote is treated as a single
    1155             :                     // valid character.
    1156           0 :                     c = 'a';
    1157             :             }
    1158           0 :             else if (c == ']')
    1159             :             {
    1160           0 :                 if (cPrev == '\'')
    1161             :                 {
    1162             :                     // valid source document path found.  Increment the
    1163             :                     // current position to skip the source path.
    1164           0 :                     rSrcPos = i + 1;
    1165           0 :                     if (rSrcPos >= nLen)
    1166           0 :                         rSrcPos = nLen - 1;
    1167           0 :                     return;
    1168             :                 }
    1169             :                 else
    1170           0 :                     return;
    1171             :             }
    1172             :             else
    1173             :             {
    1174             :                 // any other character
    1175           0 :                 if (i > rSrcPos + 2 && cPrev == '\'')
    1176             :                     // unless it's the 3rd character, a normal character
    1177             :                     // following immediately a single quote is invalid.
    1178           0 :                     return;
    1179             :             }
    1180           0 :             cPrev = c;
    1181             :         }
    1182             :     }
    1183             : };
    1184             : 
    1185           9 : struct ConventionXL_A1 : public Convention_A1, public ConventionXL
    1186             : {
    1187           4 :     ConventionXL_A1() : Convention_A1( FormulaGrammar::CONV_XL_A1 ) { }
    1188           5 :     ConventionXL_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1( eConv ) { }
    1189             : 
    1190        4267 :     static void makeSingleCellStr( OUStringBuffer& rBuf, const ScSingleRefData& rRef, const ScAddress& rAbs )
    1191             :     {
    1192        4267 :         if (!rRef.IsColRel())
    1193        1591 :             rBuf.append('$');
    1194        4267 :         MakeColStr(rBuf, rAbs.Col());
    1195        4267 :         if (!rRef.IsRowRel())
    1196        1591 :             rBuf.append('$');
    1197        4267 :         MakeRowStr(rBuf, rAbs.Row());
    1198        4267 :     }
    1199             : 
    1200        3556 :     void makeRefStr( OUStringBuffer&   rBuf,
    1201             :                      formula::FormulaGrammar::Grammar /*eGram*/,
    1202             :                      const ScAddress& rPos,
    1203             :                      const OUString& /*rErrRef*/, const std::vector<OUString>& rTabNames,
    1204             :                      const ScComplexRefData& rRef,
    1205             :                      bool bSingleRef ) const SAL_OVERRIDE
    1206             :     {
    1207        3556 :         ScComplexRefData aRef( rRef );
    1208             : 
    1209             :         // Play fast and loose with invalid refs.  There is not much point in producing
    1210             :         // Foo!A1:#REF! versus #REF! at this point
    1211        3556 :         ScAddress aAbs1 = aRef.Ref1.toAbs(rPos), aAbs2;
    1212             : 
    1213        3556 :         MakeTabStr(rBuf, rPos, rTabNames, aRef, bSingleRef);
    1214             : 
    1215        3556 :         if (!ValidAddress(aAbs1))
    1216             :         {
    1217           0 :             rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1218           0 :             return;
    1219             :         }
    1220             : 
    1221        3556 :         if( !bSingleRef )
    1222             :         {
    1223         708 :             aAbs2 = aRef.Ref2.toAbs(rPos);
    1224         708 :             if (!ValidAddress(aAbs2))
    1225             :             {
    1226           0 :                 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1227           0 :                 return;
    1228             :             }
    1229             : 
    1230         708 :             if (aAbs1.Col() == 0 && aAbs2.Col() >= MAXCOL)
    1231             :             {
    1232           0 :                 if (!aRef.Ref1.IsRowRel())
    1233           0 :                     rBuf.append( '$' );
    1234           0 :                 MakeRowStr(rBuf, aAbs1.Row());
    1235           0 :                 rBuf.append( ':' );
    1236           0 :                 if (!aRef.Ref2.IsRowRel())
    1237           0 :                     rBuf.append( '$' );
    1238           0 :                 MakeRowStr(rBuf, aAbs2.Row());
    1239           0 :                 return;
    1240             :             }
    1241             : 
    1242         708 :             if (aAbs1.Row() == 0 && aAbs2.Row() >= MAXROW)
    1243             :             {
    1244           0 :                 if (!aRef.Ref1.IsColRel())
    1245           0 :                     rBuf.append( '$' );
    1246           0 :                 MakeColStr(rBuf, aAbs1.Col());
    1247           0 :                 rBuf.append( ':' );
    1248           0 :                 if (!aRef.Ref2.IsColRel())
    1249           0 :                     rBuf.append( '$' );
    1250           0 :                 MakeColStr(rBuf, aAbs2.Col());
    1251           0 :                 return;
    1252             :             }
    1253             :         }
    1254             : 
    1255        3556 :         makeSingleCellStr(rBuf, aRef.Ref1, aAbs1);
    1256        3556 :         if (!bSingleRef)
    1257             :         {
    1258         708 :             rBuf.append( ':' );
    1259         708 :             makeSingleCellStr(rBuf, aRef.Ref2, aAbs2);
    1260             :         }
    1261             :     }
    1262             : 
    1263           4 :     virtual ParseResult parseAnyToken( const OUString& rFormula,
    1264             :                                        sal_Int32 nSrcPos,
    1265             :                                        const CharClass* pCharClass) const SAL_OVERRIDE
    1266             :     {
    1267           4 :         parseExternalDocName(rFormula, nSrcPos);
    1268             : 
    1269           4 :         ParseResult aRet;
    1270           4 :         if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
    1271           0 :             return aRet;
    1272             : 
    1273             :         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
    1274             :             KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
    1275             :         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
    1276             :         // '?' allowed in range names
    1277           8 :         const OUString aAddAllowed("?!");
    1278             :         return pCharClass->parseAnyToken( rFormula,
    1279           8 :                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
    1280             :     }
    1281             : 
    1282       14680 :     virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const SAL_OVERRIDE
    1283             :     {
    1284       14680 :         return ConventionXL::getSpecialSymbol(eSymType);
    1285             :     }
    1286             : 
    1287           3 :     virtual bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
    1288             :             const ScDocument* pDoc,
    1289             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks ) const SAL_OVERRIDE
    1290             :     {
    1291           3 :         return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks);
    1292             :     }
    1293             : 
    1294           0 :     virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const OUString& rFile,
    1295             :             const OUString& rName ) const SAL_OVERRIDE
    1296             :     {
    1297           0 :         return ConventionXL::makeExternalNameStr(rFile, rName);
    1298             :     }
    1299             : 
    1300           0 :     virtual void makeExternalRefStr(
    1301             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
    1302             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
    1303             :     {
    1304             :         // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
    1305             :         // This is a little different from the format Excel uses, as Excel
    1306             :         // puts [] only around the file name.  But we need to enclose the
    1307             :         // whole file path with [] because the file name can contain any
    1308             :         // characters.
    1309             : 
    1310           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1311           0 :         ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
    1312           0 :         rBuffer.append('!');
    1313             : 
    1314           0 :         makeSingleCellStr(rBuffer, rRef, rRef.toAbs(rPos));
    1315           0 :     }
    1316             : 
    1317           0 :     virtual void makeExternalRefStr(
    1318             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
    1319             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
    1320             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
    1321             :     {
    1322           0 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1323             : 
    1324           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1325           0 :         ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, aAbsRef);
    1326           0 :         rBuffer.append('!');
    1327             : 
    1328           0 :         makeSingleCellStr(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1329           0 :         if (aAbsRef.aStart != aAbsRef.aEnd)
    1330             :         {
    1331           0 :             rBuffer.append(':');
    1332           0 :             makeSingleCellStr(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1333             :         }
    1334           0 :     }
    1335             : };
    1336             : 
    1337           5 : struct ConventionXL_OOX : public ConventionXL_A1
    1338             : {
    1339           5 :     ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX ) { }
    1340             : 
    1341           0 :     virtual OUString makeExternalNameStr( sal_uInt16 nFileId, const OUString& /*rFile*/,
    1342             :             const OUString& rName ) const SAL_OVERRIDE
    1343             :     {
    1344             :         // [N]!DefinedName is a workbook global name.
    1345           0 :         return OUString( "[" + OUString::number(nFileId+1) + "]!" + rName );
    1346             : 
    1347             :         /* TODO: add support for sheet local names, would be
    1348             :          * [N]'Sheet Name'!DefinedName
    1349             :          * Similar to makeExternalRefStr() but with DefinedName instead of
    1350             :          * CellStr. */
    1351             :     }
    1352             : 
    1353           4 :     virtual void parseExternalDocName(const OUString& rFormula, sal_Int32& rSrcPos) const SAL_OVERRIDE
    1354             :     {
    1355           4 :         sal_Int32 nLen = rFormula.getLength();
    1356           4 :         const sal_Unicode* p = rFormula.getStr();
    1357           4 :         for (sal_Int32 i = rSrcPos; i < nLen; ++i)
    1358             :         {
    1359           4 :             sal_Unicode c = p[i];
    1360           4 :             if (i == rSrcPos)
    1361             :             {
    1362             :                 // first character must be '['.
    1363           4 :                 if (c != '[')
    1364           4 :                     return;
    1365             :             }
    1366           0 :             else if (c == ']')
    1367             :             {
    1368           0 :                 rSrcPos = i + 1;
    1369           0 :                 return;
    1370             :             }
    1371             :         }
    1372             :     }
    1373             : 
    1374           3 :     virtual void makeExternalRefStr(
    1375             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, const OUString& /*rFileName*/,
    1376             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
    1377             :     {
    1378             :         // [N]'Sheet Name'!$A$1
    1379             :         // Where N is a 1-based positive integer number of a file name in OOXML
    1380             :         // xl/externalLinks/externalLinkN.xml
    1381             : 
    1382           3 :         ConventionXL_OOX::makeExternalDocStr(rBuffer, nFileId);
    1383           3 :         ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
    1384           3 :         rBuffer.append('!');
    1385             : 
    1386           3 :         makeSingleCellStr(rBuffer, rRef, rRef.toAbs(rPos));
    1387           3 :     }
    1388             : 
    1389           0 :     virtual void makeExternalRefStr(
    1390             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, const OUString& /*rFileName*/,
    1391             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
    1392             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
    1393             :     {
    1394           0 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1395             : 
    1396           0 :         ConventionXL_OOX::makeExternalDocStr(rBuffer, nFileId);
    1397           0 :         ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, aAbsRef);
    1398           0 :         rBuffer.append('!');
    1399             : 
    1400           0 :         makeSingleCellStr(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1401           0 :         if (aAbsRef.aStart != aAbsRef.aEnd)
    1402             :         {
    1403           0 :             rBuffer.append(':');
    1404           0 :             makeSingleCellStr(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1405             :         }
    1406           0 :     }
    1407             : 
    1408           3 :     static void makeExternalDocStr( OUStringBuffer& rBuffer, sal_uInt16 nFileId )
    1409             :     {
    1410           3 :         rBuffer.append('[').append( OUString::number( nFileId+1)).append(']');
    1411           3 :     }
    1412             : };
    1413             : 
    1414             : static void
    1415          76 : r1c1_add_col( OUStringBuffer &rBuf, const ScSingleRefData& rRef, const ScAddress& rAbsRef )
    1416             : {
    1417          76 :     rBuf.append( 'C' );
    1418          76 :     if( rRef.IsColRel() )
    1419             :     {
    1420          67 :         SCCOL nCol = rRef.Col();
    1421          67 :         if (nCol != 0)
    1422          43 :             rBuf.append("[").append(OUString::number(nCol)).append("]");
    1423             :     }
    1424             :     else
    1425           9 :         rBuf.append( OUString::number( rAbsRef.Col() + 1 ) );
    1426          76 : }
    1427             : static void
    1428          76 : r1c1_add_row( OUStringBuffer &rBuf, const ScSingleRefData& rRef, const ScAddress& rAbsRef )
    1429             : {
    1430          76 :     rBuf.append( 'R' );
    1431          76 :     if( rRef.IsRowRel() )
    1432             :     {
    1433          67 :         if (rRef.Row() != 0)
    1434             :         {
    1435          10 :             rBuf.append("[").append( OUString::number(rRef.Row()) ).append("]");
    1436             :         }
    1437             :     }
    1438             :     else
    1439           9 :         rBuf.append( OUString::number( rAbsRef.Row() + 1 ) );
    1440          76 : }
    1441             : 
    1442           3 : struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
    1443             : {
    1444           3 :     ConventionXL_R1C1() : ScCompiler::Convention( FormulaGrammar::CONV_XL_R1C1 ) { }
    1445          73 :     void makeRefStr( OUStringBuffer&   rBuf,
    1446             :                      formula::FormulaGrammar::Grammar /*eGram*/,
    1447             :                      const ScAddress& rPos,
    1448             :                      const OUString& /*rErrRef*/, const std::vector<OUString>& rTabNames,
    1449             :                      const ScComplexRefData& rRef,
    1450             :                      bool bSingleRef ) const SAL_OVERRIDE
    1451             :     {
    1452          73 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1453          73 :         ScComplexRefData aRef( rRef );
    1454             : 
    1455          73 :         MakeTabStr(rBuf, rPos, rTabNames, aRef, bSingleRef);
    1456             : 
    1457             :         // Play fast and loose with invalid refs.  There is not much point in producing
    1458             :         // Foo!A1:#REF! versus #REF! at this point
    1459          73 :         if (!ValidCol(aAbsRef.aStart.Col()) || !ValidRow(aAbsRef.aStart.Row()))
    1460             :         {
    1461           0 :             rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1462           0 :             return;
    1463             :         }
    1464             : 
    1465          73 :         if( !bSingleRef )
    1466             :         {
    1467           3 :             if (!ValidCol(aAbsRef.aEnd.Col()) || !ValidRow(aAbsRef.aEnd.Row()))
    1468             :             {
    1469           0 :                 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1470           0 :                 return;
    1471             :             }
    1472             : 
    1473           3 :             if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= MAXCOL)
    1474             :             {
    1475           0 :                 r1c1_add_row(rBuf,  rRef.Ref1, aAbsRef.aStart);
    1476           0 :                 if (aAbsRef.aStart.Row() != aAbsRef.aEnd.Row() ||
    1477           0 :                     rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel() )
    1478             :                 {
    1479           0 :                     rBuf.append( ':' );
    1480           0 :                     r1c1_add_row(rBuf,  rRef.Ref2, aAbsRef.aEnd);
    1481             :                 }
    1482           0 :                 return;
    1483             : 
    1484             :             }
    1485             : 
    1486           3 :             if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= MAXROW)
    1487             :             {
    1488           0 :                 r1c1_add_col(rBuf, rRef.Ref1, aAbsRef.aStart);
    1489           0 :                 if (aAbsRef.aStart.Col() != aAbsRef.aEnd.Col() ||
    1490           0 :                     rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel())
    1491             :                 {
    1492           0 :                     rBuf.append( ':' );
    1493           0 :                     r1c1_add_col(rBuf, rRef.Ref2, aAbsRef.aEnd);
    1494             :                 }
    1495           0 :                 return;
    1496             :             }
    1497             :         }
    1498             : 
    1499          73 :         r1c1_add_row(rBuf, rRef.Ref1, aAbsRef.aStart);
    1500          73 :         r1c1_add_col(rBuf, rRef.Ref1, aAbsRef.aStart);
    1501          73 :         if (!bSingleRef)
    1502             :         {
    1503           3 :             rBuf.append( ':' );
    1504           3 :             r1c1_add_row(rBuf, rRef.Ref2, aAbsRef.aEnd);
    1505           3 :             r1c1_add_col(rBuf, rRef.Ref2, aAbsRef.aEnd);
    1506             :         }
    1507             :     }
    1508             : 
    1509           0 :     ParseResult parseAnyToken( const OUString& rFormula,
    1510             :                                sal_Int32 nSrcPos,
    1511             :                                const CharClass* pCharClass) const SAL_OVERRIDE
    1512             :     {
    1513           0 :         parseExternalDocName(rFormula, nSrcPos);
    1514             : 
    1515           0 :         ParseResult aRet;
    1516           0 :         if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
    1517           0 :             return aRet;
    1518             : 
    1519             :         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
    1520             :             KParseTokens::ASC_UNDERSCORE ;
    1521             :         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
    1522             :         // '?' allowed in range names
    1523           0 :         const OUString aAddAllowed("?-[]!");
    1524             : 
    1525             :         return pCharClass->parseAnyToken( rFormula,
    1526           0 :                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
    1527             :     }
    1528             : 
    1529        1352 :     virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const SAL_OVERRIDE
    1530             :     {
    1531        1352 :         return ConventionXL::getSpecialSymbol(eSymType);
    1532             :     }
    1533             : 
    1534           0 :     virtual bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
    1535             :             const ScDocument* pDoc,
    1536             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks ) const SAL_OVERRIDE
    1537             :     {
    1538           0 :         return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks);
    1539             :     }
    1540             : 
    1541           0 :     virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const OUString& rFile,
    1542             :             const OUString& rName ) const SAL_OVERRIDE
    1543             :     {
    1544           0 :         return ConventionXL::makeExternalNameStr(rFile, rName);
    1545             :     }
    1546             : 
    1547           0 :     virtual void makeExternalRefStr(
    1548             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
    1549             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
    1550             :     {
    1551             :         // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
    1552             :         // This is a little different from the format Excel uses, as Excel
    1553             :         // puts [] only around the file name.  But we need to enclose the
    1554             :         // whole file path with [] because the file name can contain any
    1555             :         // characters.
    1556             : 
    1557           0 :         ScAddress aAbsRef = rRef.toAbs(rPos);
    1558           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1559           0 :         ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
    1560           0 :         rBuffer.append('!');
    1561             : 
    1562           0 :         r1c1_add_row(rBuffer, rRef, aAbsRef);
    1563           0 :         r1c1_add_col(rBuffer, rRef, aAbsRef);
    1564           0 :     }
    1565             : 
    1566           0 :     virtual void makeExternalRefStr(
    1567             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
    1568             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
    1569             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
    1570             :     {
    1571           0 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1572             : 
    1573           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1574           0 :         ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, aAbsRef);
    1575           0 :         rBuffer.append('!');
    1576             : 
    1577           0 :         if (!ValidCol(aAbsRef.aEnd.Col()) || !ValidRow(aAbsRef.aEnd.Row()))
    1578             :         {
    1579           0 :             rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1580           0 :             return;
    1581             :         }
    1582             : 
    1583           0 :         if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= MAXCOL)
    1584             :         {
    1585           0 :             r1c1_add_row(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1586           0 :             if (aAbsRef.aStart.Row() != aAbsRef.aEnd.Row() || rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel())
    1587             :             {
    1588           0 :                 rBuffer.append(':');
    1589           0 :                 r1c1_add_row(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1590             :             }
    1591           0 :             return;
    1592             :         }
    1593             : 
    1594           0 :         if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= MAXROW)
    1595             :         {
    1596           0 :             r1c1_add_col(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1597           0 :             if (aAbsRef.aStart.Col() != aAbsRef.aEnd.Col() || rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel())
    1598             :             {
    1599           0 :                 rBuffer.append(':');
    1600           0 :                 r1c1_add_col(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1601             :             }
    1602           0 :             return;
    1603             :         }
    1604             : 
    1605           0 :         r1c1_add_row(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1606           0 :         r1c1_add_col(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1607           0 :         rBuffer.append(':');
    1608           0 :         r1c1_add_row(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1609           0 :         r1c1_add_col(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1610             :     }
    1611             : 
    1612        3357 :     virtual sal_uLong getCharTableFlags( sal_Unicode c, sal_Unicode cLast ) const SAL_OVERRIDE
    1613             :     {
    1614        3357 :         sal_uLong nFlags = mpCharTable[static_cast<sal_uInt8>(c)];
    1615        3357 :         if (c == '-' && cLast == '[')
    1616             :             // '-' can occur within a reference string only after '[' e.g. R[-1]C.
    1617         197 :             nFlags |= SC_COMPILER_C_IDENT;
    1618        3357 :         return nFlags;
    1619             :     }
    1620             : };
    1621             : 
    1622        3282 : ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos, ScTokenArray& rArr ) :
    1623             :     FormulaCompiler(rArr),
    1624        3282 :     pDoc(rCxt.getDoc()),
    1625             :     aPos(rPos),
    1626        3282 :     mpFormatter(pDoc->GetFormatTable()),
    1627             :     pCharClass(ScGlobal::pCharClass),
    1628             :     mnPredetectedReference(0),
    1629             :     mnRangeOpPosInSymbol(-1),
    1630        3282 :     pConv(GetRefConvention(FormulaGrammar::CONV_OOO)),
    1631             :     meExtendedErrorDetection(EXTENDED_ERROR_DETECTION_NONE),
    1632             :     mbCloseBrackets(true),
    1633             :     mbRewind(false),
    1634       13128 :     maTabNames(rCxt.getTabNames())
    1635             : {
    1636        3282 :     nMaxTab = pDoc->GetTableCount() - 1;
    1637        3282 :     SetGrammar(rCxt.getGrammar());
    1638        3282 : }
    1639             : 
    1640        8688 : ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,ScTokenArray& rArr)
    1641             :         : FormulaCompiler(rArr),
    1642             :         pDoc( pDocument ),
    1643             :         aPos( rPos ),
    1644        8688 :         mpFormatter(pDoc->GetFormatTable()),
    1645             :         nSrcPos(0),
    1646             :         pCharClass( ScGlobal::pCharClass ),
    1647             :         mnPredetectedReference(0),
    1648             :         mnRangeOpPosInSymbol(-1),
    1649        8688 :         pConv( GetRefConvention( FormulaGrammar::CONV_OOO ) ),
    1650             :         meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
    1651             :         mbCloseBrackets( true ),
    1652       26064 :         mbRewind( false )
    1653             : {
    1654        8688 :     nMaxTab = pDoc->GetTableCount() - 1;
    1655        8688 : }
    1656             : 
    1657           5 : ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos ) :
    1658           5 :     pDoc(rCxt.getDoc()),
    1659             :     aPos(rPos),
    1660           5 :     mpFormatter(pDoc ? pDoc->GetFormatTable() : NULL),
    1661             :     pCharClass(ScGlobal::pCharClass),
    1662             :     mnPredetectedReference(0),
    1663             :     mnRangeOpPosInSymbol(-1),
    1664           5 :     pConv(GetRefConvention(FormulaGrammar::CONV_OOO)),
    1665             :     meExtendedErrorDetection(EXTENDED_ERROR_DETECTION_NONE),
    1666             :     mbCloseBrackets(true),
    1667             :     mbRewind(false),
    1668          20 :     maTabNames(rCxt.getTabNames())
    1669             : {
    1670           5 :     nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
    1671           5 :     SetGrammar(rCxt.getGrammar());
    1672           5 : }
    1673             : 
    1674       32801 : ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos)
    1675             :         :
    1676             :         pDoc( pDocument ),
    1677             :         aPos( rPos ),
    1678       32769 :         mpFormatter(pDoc ? pDoc->GetFormatTable() : NULL),
    1679             :         nSrcPos(0),
    1680             :         pCharClass( ScGlobal::pCharClass ),
    1681             :         mnPredetectedReference(0),
    1682             :         mnRangeOpPosInSymbol(-1),
    1683       32801 :         pConv( GetRefConvention( FormulaGrammar::CONV_OOO ) ),
    1684             :         meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
    1685             :         mbCloseBrackets( true ),
    1686       98371 :         mbRewind( false )
    1687             : {
    1688       32801 :     nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
    1689       32801 : }
    1690             : 
    1691       45929 : ScCompiler::~ScCompiler()
    1692             : {
    1693       45929 : }
    1694             : 
    1695       29953 : void ScCompiler::CheckTabQuotes( OUString& rString,
    1696             :                                  const FormulaGrammar::AddressConvention eConv )
    1697             : {
    1698             :     using namespace ::com::sun::star::i18n;
    1699       29953 :     sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | KParseTokens::ASC_UNDERSCORE;
    1700       29953 :     sal_Int32 nContFlags = nStartFlags;
    1701             :     ParseResult aRes = ScGlobal::pCharClass->parsePredefinedToken(
    1702       29953 :         KParseType::IDENTNAME, rString, 0, nStartFlags, EMPTY_OUSTRING, nContFlags, EMPTY_OUSTRING);
    1703       29953 :     bool bNeedsQuote = !((aRes.TokenType & KParseType::IDENTNAME) && aRes.EndPos == rString.getLength());
    1704             : 
    1705       29953 :     switch ( eConv )
    1706             :     {
    1707             :         default :
    1708             :         case FormulaGrammar::CONV_UNSPECIFIED :
    1709           0 :             break;
    1710             :         case FormulaGrammar::CONV_OOO :
    1711             :         case FormulaGrammar::CONV_XL_A1 :
    1712             :         case FormulaGrammar::CONV_XL_R1C1 :
    1713             :         case FormulaGrammar::CONV_XL_OOX :
    1714             :         case FormulaGrammar::CONV_ODF :
    1715       29953 :             if( bNeedsQuote )
    1716             :             {
    1717         937 :                 const OUString one_quote('\'');
    1718        1874 :                 const OUString two_quote("''");
    1719             :                 // escape embedded quotes
    1720        1874 :                 rString = rString.replaceAll( one_quote, two_quote );
    1721             :             }
    1722       29953 :             break;
    1723             :     }
    1724             : 
    1725       29953 :     if ( !bNeedsQuote && CharClass::isAsciiNumeric( rString ) )
    1726             :     {
    1727             :         // Prevent any possible confusion resulting from pure numeric sheet names.
    1728           1 :         bNeedsQuote = true;
    1729             :     }
    1730             : 
    1731       29953 :     if( bNeedsQuote )
    1732             :     {
    1733         938 :         rString = "'" + rString + "'";
    1734       29953 :     }
    1735       29953 : }
    1736             : 
    1737           1 : sal_Int32 ScCompiler::GetDocTabPos( const OUString& rString )
    1738             : {
    1739           1 :     if (rString[0] != '\'')
    1740           1 :         return -1;
    1741           0 :     sal_Int32 nPos = ScGlobal::FindUnquoted( rString, SC_COMPILER_FILE_TAB_SEP);
    1742             :     // it must be 'Doc'#
    1743           0 :     if (nPos != -1 && rString[nPos-1] != '\'')
    1744           0 :         nPos = -1;
    1745           0 :     return nPos;
    1746             : }
    1747             : 
    1748       51961 : void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv )
    1749             : {
    1750       51961 :     const Convention* p = GetRefConvention(eConv);
    1751       51961 :     if (p)
    1752       51482 :         SetRefConvention(p);
    1753       51961 : }
    1754             : 
    1755       96769 : const ScCompiler::Convention* ScCompiler::GetRefConvention( FormulaGrammar::AddressConvention eConv )
    1756             : {
    1757             : 
    1758       96769 :     switch (eConv)
    1759             :     {
    1760             :         case FormulaGrammar::CONV_OOO:
    1761             :         {
    1762       88373 :             static const ConventionOOO_A1 ConvOOO_A1;
    1763       88373 :             return &ConvOOO_A1;
    1764             :         }
    1765             :         case FormulaGrammar::CONV_ODF:
    1766             :         {
    1767        5643 :             static const ConventionOOO_A1_ODF ConvOOO_A1_ODF;
    1768        5643 :             return &ConvOOO_A1_ODF;
    1769             :         }
    1770             :         case FormulaGrammar::CONV_XL_A1:
    1771             :         {
    1772         146 :             static const ConventionXL_A1 ConvXL_A1;
    1773         146 :             return &ConvXL_A1;
    1774             :         }
    1775             :         case FormulaGrammar::CONV_XL_R1C1:
    1776             :         {
    1777         441 :             static const ConventionXL_R1C1 ConvXL_R1C1;
    1778         441 :             return &ConvXL_R1C1;
    1779             :         }
    1780             :         case FormulaGrammar::CONV_XL_OOX:
    1781             :         {
    1782        1687 :             static const ConventionXL_OOX ConvXL_OOX;
    1783        1687 :             return &ConvXL_OOX;
    1784             :         }
    1785             :         case FormulaGrammar::CONV_UNSPECIFIED:
    1786             :         default:
    1787             :             ;
    1788             :     }
    1789             : 
    1790         479 :     return NULL;
    1791             : }
    1792             : 
    1793       51482 : void ScCompiler::SetRefConvention( const ScCompiler::Convention *pConvP )
    1794             : {
    1795       51482 :     pConv = pConvP;
    1796       51482 :     meGrammar = FormulaGrammar::mergeToGrammar( meGrammar, pConv->meConv);
    1797             :     OSL_ENSURE( FormulaGrammar::isSupported( meGrammar),
    1798             :             "ScCompiler::SetRefConvention: unsupported grammar resulting");
    1799       51482 : }
    1800             : 
    1801        3102 : void ScCompiler::SetError(sal_uInt16 nError)
    1802             : {
    1803        3102 :     if( !pArr->GetCodeError() )
    1804        1552 :         pArr->SetCodeError( nError);
    1805        3102 : }
    1806             : 
    1807         186 : static sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, sal_Int32 nMax )
    1808             : {
    1809         186 :     const sal_Unicode* const pStop = pDst + nMax;
    1810        4771 :     while ( *pSrc && pDst < pStop )
    1811             :     {
    1812        4399 :         *pDst++ = *pSrc++;
    1813             :     }
    1814         186 :     *pDst = 0;
    1815         186 :     return pDst;
    1816             : }
    1817             : 
    1818             : // NextSymbol
    1819             : 
    1820             : // Parses the formula into separate symbols for further
    1821             : // processing (Turing-Machine).
    1822             : 
    1823             : // initial state = GetChar
    1824             : 
    1825             : // old state     | read character    | action                | new state
    1826             : //---------------+-------------------+-----------------------+---------------
    1827             : // GetChar       | ;()+-*/^=&        | Symbol=char           | Stop
    1828             : //               | <>                | Symbol=char           | GetBool
    1829             : //               | $ letter          | Symbol=char           | GetWord
    1830             : //               | number            | Symbol=char           | GetValue
    1831             : //               | "                 | none                  | GetString
    1832             : //               | other             | none                  | GetChar
    1833             : //---------------+-------------------+-----------------------+---------------
    1834             : // GetBool       | =>                | Symbol=Symbol+char    | Stop
    1835             : //               | other             | Dec(CharPos)          | Stop
    1836             : //---------------+-------------------+-----------------------+---------------
    1837             : // GetWord       | SepSymbol         | Dec(CharPos)          | Stop
    1838             : //               | ()+-*/^=<>&~      |                       |
    1839             : //               | space             | Dec(CharPos)          | Stop
    1840             : //               | $_:.              |                       |
    1841             : //               | letter, number    | Symbol=Symbol+char    | GetWord
    1842             : //               | other             | error                 | Stop
    1843             : //---------------+-------------------+-----------------------+---------------
    1844             : // GetValue      | ;()*/^=<>&        |                       |
    1845             : //               | space             | Dec(CharPos)          | Stop
    1846             : //               | number E+-%,.     | Symbol=Symbol+char    | GetValue
    1847             : //               | other             | error                 | Stop
    1848             : //---------------+-------------------+-----------------------+---------------
    1849             : // GetString     | "                 | none                  | Stop
    1850             : //               | other             | Symbol=Symbol+char    | GetString
    1851             : //---------------+-------------------+-----------------------+---------------
    1852             : 
    1853       30809 : sal_Int32 ScCompiler::NextSymbol(bool bInArray)
    1854             : {
    1855       30809 :     cSymbol[MAXSTRLEN-1] = 0;       // end
    1856       30809 :     sal_Unicode* pSym = cSymbol;
    1857       30809 :     const sal_Unicode* const pStart = aFormula.getStr();
    1858       30809 :     const sal_Unicode* pSrc = pStart + nSrcPos;
    1859       30809 :     bool bi18n = false;
    1860       30809 :     sal_Unicode c = *pSrc;
    1861       30809 :     sal_Unicode cLast = 0;
    1862       30809 :     bool bQuote = false;
    1863       30809 :     mnRangeOpPosInSymbol = -1;
    1864       30809 :     ScanState eState = ssGetChar;
    1865       30809 :     sal_Int32 nSpaces = 0;
    1866       30809 :     sal_Unicode cSep = mxSymbols->getSymbolChar( ocSep);
    1867       30809 :     sal_Unicode cArrayColSep = mxSymbols->getSymbolChar( ocArrayColSep);
    1868       30809 :     sal_Unicode cArrayRowSep = mxSymbols->getSymbolChar( ocArrayRowSep);
    1869       30809 :     sal_Unicode cDecSep = (mxSymbols->isEnglish() ? '.' :
    1870       30809 :             ScGlobal::pLocaleData->getNumDecimalSep()[0]);
    1871             : 
    1872             :     // special symbols specific to address convention used
    1873       30809 :     sal_Unicode cSheetPrefix = pConv->getSpecialSymbol(ScCompiler::Convention::ABS_SHEET_PREFIX);
    1874       30809 :     sal_Unicode cSheetSep    = pConv->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
    1875             : 
    1876       30809 :     int nDecSeps = 0;
    1877       30809 :     bool bAutoIntersection = false;
    1878       30809 :     int nRefInName = 0;
    1879       30809 :     bool bErrorConstantHadSlash = false;
    1880       30809 :     mnPredetectedReference = 0;
    1881             :     // try to parse simple tokens before calling i18n parser
    1882      187327 :     while ((c != 0) && (eState != ssStop) )
    1883             :     {
    1884      125709 :         pSrc++;
    1885      125709 :         sal_uLong nMask = GetCharTableFlags( c, cLast );
    1886             : 
    1887             :         // The parameter separator and the array column and row separators end
    1888             :         // things unconditionally if not in string or reference.
    1889      125709 :         if (c == cSep || (bInArray && (c == cArrayColSep || c == cArrayRowSep)))
    1890             :         {
    1891        6336 :             switch (eState)
    1892             :             {
    1893             :                 // these are to be continued
    1894             :                 case ssGetString:
    1895             :                 case ssSkipString:
    1896             :                 case ssGetReference:
    1897             :                 case ssSkipReference:
    1898           0 :                     break;
    1899             :                 default:
    1900        6336 :                     if (eState == ssGetChar)
    1901        3578 :                         *pSym++ = c;
    1902             :                     else
    1903        2758 :                         pSrc--;
    1904        6336 :                     eState = ssStop;
    1905             :             }
    1906             :         }
    1907             : Label_MaskStateMachine:
    1908      125710 :         switch (eState)
    1909             :         {
    1910             :             case ssGetChar :
    1911             :             {
    1912             :                 // Order is important!
    1913       20777 :                 if (eLastOp == ocTableRefOpen && c != '[' && c != '#' && c != ']')
    1914             :                 {
    1915           0 :                     *pSym++ = c;
    1916           0 :                     eState = ssGetTableRefColumn;
    1917             :                 }
    1918       20777 :                 else if( nMask & SC_COMPILER_C_ODF_LABEL_OP )
    1919             :                 {
    1920             :                     // '!!' automatic intersection
    1921           0 :                     if (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_ODF_LABEL_OP)
    1922             :                     {
    1923             :                         /* TODO: For now the UI "space operator" is used, this
    1924             :                          * could be enhanced using a specialized OpCode to get
    1925             :                          * rid of the space ambiguity, which would need some
    1926             :                          * places to be adapted though. And we would still need
    1927             :                          * to support the ambiguous space operator for UI
    1928             :                          * purposes anyway. However, we then could check for
    1929             :                          * invalid usage of '!!', which currently isn't
    1930             :                          * possible. */
    1931           0 :                         if (!bAutoIntersection)
    1932             :                         {
    1933           0 :                             ++pSrc;
    1934           0 :                             nSpaces += 2;   // must match the character count
    1935           0 :                             bAutoIntersection = true;
    1936             :                         }
    1937             :                         else
    1938             :                         {
    1939           0 :                             pSrc--;
    1940           0 :                             eState = ssStop;
    1941             :                         }
    1942             :                     }
    1943             :                     else
    1944             :                     {
    1945           0 :                         nMask &= ~SC_COMPILER_C_ODF_LABEL_OP;
    1946           0 :                         goto Label_MaskStateMachine;
    1947             :                     }
    1948             :                 }
    1949       20777 :                 else if( nMask & SC_COMPILER_C_ODF_NAME_MARKER )
    1950             :                 {
    1951             :                     // '$$' defined name marker
    1952           0 :                     if (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_ODF_NAME_MARKER)
    1953             :                     {
    1954             :                         // both eaten, not added to pSym
    1955           0 :                         ++pSrc;
    1956             :                     }
    1957             :                     else
    1958             :                     {
    1959           0 :                         nMask &= ~SC_COMPILER_C_ODF_NAME_MARKER;
    1960           0 :                         goto Label_MaskStateMachine;
    1961             :                     }
    1962             :                 }
    1963       20777 :                 else if( nMask & SC_COMPILER_C_CHAR )
    1964             :                 {
    1965             :                     // '[' is a special case in OOXML, it can start an external
    1966             :                     // reference ID like [1]Sheet1!A1 that needs to be scanned
    1967             :                     // entirely, or can be ocTableRefOpen, of which the first
    1968             :                     // transforms an ocDBArea into an ocTableRef.
    1969        6517 :                     if (c == '[' && FormulaGrammar::isOOXML( meGrammar) && eLastOp != ocDBArea && maTableRefs.empty())
    1970             :                     {
    1971           1 :                         nMask &= ~SC_COMPILER_C_CHAR;
    1972           1 :                         goto Label_MaskStateMachine;
    1973             :                     }
    1974             :                     else
    1975             :                     {
    1976        6516 :                         *pSym++ = c;
    1977        6516 :                         eState = ssStop;
    1978             :                     }
    1979             :                 }
    1980       14260 :                 else if( nMask & SC_COMPILER_C_ODF_LBRACKET )
    1981             :                 {
    1982             :                     // eaten, not added to pSym
    1983         789 :                     eState = ssGetReference;
    1984         789 :                     mnPredetectedReference = 1;
    1985             :                 }
    1986       13471 :                 else if( nMask & SC_COMPILER_C_CHAR_BOOL )
    1987             :                 {
    1988          15 :                     *pSym++ = c;
    1989          15 :                     eState = ssGetBool;
    1990             :                 }
    1991       13456 :                 else if( nMask & SC_COMPILER_C_CHAR_VALUE )
    1992             :                 {
    1993        3308 :                     *pSym++ = c;
    1994        3308 :                     eState = ssGetValue;
    1995             :                 }
    1996       10148 :                 else if( nMask & SC_COMPILER_C_CHAR_STRING )
    1997             :                 {
    1998         776 :                     *pSym++ = c;
    1999         776 :                     eState = ssGetString;
    2000             :                 }
    2001        9372 :                 else if( nMask & SC_COMPILER_C_CHAR_ERRCONST )
    2002             :                 {
    2003          23 :                     *pSym++ = c;
    2004          23 :                     if (!maTableRefs.empty() && maTableRefs.back().mnLevel == 2)
    2005           0 :                         eState = ssGetTableRefItem;
    2006             :                     else
    2007          23 :                         eState = ssGetErrorConstant;
    2008             :                 }
    2009        9349 :                 else if( nMask & SC_COMPILER_C_CHAR_DONTCARE )
    2010             :                 {
    2011         451 :                     nSpaces++;
    2012             :                 }
    2013        8898 :                 else if( nMask & SC_COMPILER_C_CHAR_IDENT )
    2014             :                 {   // try to get a simple ASCII identifier before calling
    2015             :                     // i18n, to gain performance during import
    2016        8854 :                     *pSym++ = c;
    2017        8854 :                     eState = ssGetIdent;
    2018             :                 }
    2019             :                 else
    2020             :                 {
    2021          44 :                     bi18n = true;
    2022          44 :                     eState = ssStop;
    2023             :                 }
    2024             :             }
    2025       20776 :             break;
    2026             :             case ssGetIdent:
    2027             :             {
    2028       77550 :                 if ( nMask & SC_COMPILER_C_IDENT )
    2029             :                 {   // This catches also $Sheet1.A$1, for example.
    2030       71291 :                     if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2031             :                     {
    2032           0 :                         SetError(errStringOverflow);
    2033           0 :                         eState = ssStop;
    2034             :                     }
    2035             :                     else
    2036       71291 :                         *pSym++ = c;
    2037             :                 }
    2038        6259 :                 else if (c == ':' && mnRangeOpPosInSymbol < 0)
    2039             :                 {
    2040             :                     // One range operator may form Sheet1.A:A, which we need to
    2041             :                     // pass as one entity to IsReference().
    2042        2491 :                     mnRangeOpPosInSymbol = pSym - &cSymbol[0];
    2043        4982 :                     if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2044             :                     {
    2045           0 :                         SetError(errStringOverflow);
    2046           0 :                         eState = ssStop;
    2047             :                     }
    2048             :                     else
    2049        2491 :                         *pSym++ = c;
    2050             :                 }
    2051        3768 :                 else if ( 128 <= c || '\'' == c )
    2052             :                 {   // High values need reparsing with i18n,
    2053             :                     // single quoted $'sheet' names too (otherwise we'd had to
    2054             :                     // implement everything twice).
    2055         141 :                     bi18n = true;
    2056         141 :                     eState = ssStop;
    2057             :                 }
    2058             :                 else
    2059             :                 {
    2060        3627 :                     pSrc--;
    2061        3627 :                     eState = ssStop;
    2062             :                 }
    2063             :             }
    2064       77550 :             break;
    2065             :             case ssGetBool :
    2066             :             {
    2067          15 :                 if( nMask & SC_COMPILER_C_BOOL )
    2068             :                 {
    2069          10 :                     *pSym++ = c;
    2070          10 :                     eState = ssStop;
    2071             :                 }
    2072             :                 else
    2073             :                 {
    2074           5 :                     pSrc--;
    2075           5 :                     eState = ssStop;
    2076             :                 }
    2077             :             }
    2078          15 :             break;
    2079             :             case ssGetValue :
    2080             :             {
    2081        4341 :                 if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2082             :                 {
    2083           0 :                     SetError(errStringOverflow);
    2084           0 :                     eState = ssStop;
    2085             :                 }
    2086        4341 :                 else if (c == cDecSep)
    2087             :                 {
    2088         418 :                     if (++nDecSeps > 1)
    2089             :                     {
    2090             :                         // reparse with i18n, may be numeric sheet name as well
    2091           0 :                         bi18n = true;
    2092           0 :                         eState = ssStop;
    2093             :                     }
    2094             :                     else
    2095         418 :                         *pSym++ = c;
    2096             :                 }
    2097        3923 :                 else if( nMask & SC_COMPILER_C_VALUE )
    2098        2288 :                     *pSym++ = c;
    2099        1635 :                 else if( nMask & SC_COMPILER_C_VALUE_SEP )
    2100             :                 {
    2101        1599 :                     pSrc--;
    2102        1599 :                     eState = ssStop;
    2103             :                 }
    2104          36 :                 else if (c == 'E' || c == 'e')
    2105             :                 {
    2106           0 :                     if (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_VALUE_EXP)
    2107           0 :                         *pSym++ = c;
    2108             :                     else
    2109             :                     {
    2110             :                         // reparse with i18n
    2111           0 :                         bi18n = true;
    2112           0 :                         eState = ssStop;
    2113             :                     }
    2114             :                 }
    2115          36 :                 else if( nMask & SC_COMPILER_C_VALUE_SIGN )
    2116             :                 {
    2117          35 :                     if (((cLast == 'E') || (cLast == 'e')) &&
    2118           0 :                             (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_VALUE_VALUE))
    2119             :                     {
    2120           0 :                         *pSym++ = c;
    2121             :                     }
    2122             :                     else
    2123             :                     {
    2124          35 :                         pSrc--;
    2125          35 :                         eState = ssStop;
    2126             :                     }
    2127             :                 }
    2128             :                 else
    2129             :                 {
    2130             :                     // reparse with i18n
    2131           1 :                     bi18n = true;
    2132           1 :                     eState = ssStop;
    2133             :                 }
    2134             :             }
    2135        4341 :             break;
    2136             :             case ssGetString :
    2137             :             {
    2138        4868 :                 if( nMask & SC_COMPILER_C_STRING_SEP )
    2139             :                 {
    2140         776 :                     if ( !bQuote )
    2141             :                     {
    2142         776 :                         if ( *pSrc == '"' )
    2143           0 :                             bQuote = true;      // "" => literal "
    2144             :                         else
    2145         776 :                             eState = ssStop;
    2146             :                     }
    2147             :                     else
    2148           0 :                         bQuote = false;
    2149             :                 }
    2150        4868 :                 if ( !bQuote )
    2151             :                 {
    2152        4868 :                     if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2153             :                     {
    2154           0 :                         SetError(errStringOverflow);
    2155           0 :                         eState = ssSkipString;
    2156             :                     }
    2157             :                     else
    2158        4868 :                         *pSym++ = c;
    2159             :                 }
    2160             :             }
    2161        4868 :             break;
    2162             :             case ssSkipString:
    2163           0 :                 if( nMask & SC_COMPILER_C_STRING_SEP )
    2164           0 :                     eState = ssStop;
    2165           0 :                 break;
    2166             :             case ssGetErrorConstant:
    2167             :                 {
    2168             :                     // ODFF Error ::= '#' [A-Z0-9]+ ([!?] | ('/' ([A-Z] | ([0-9] [!?]))))
    2169             :                     // BUT, in UI these may have been translated! So don't
    2170             :                     // check for ASCII alnum. Note that this construct can't be
    2171             :                     // parsed with i18n.
    2172             :                     /* TODO: be strict when reading ODFF, check for ASCII alnum
    2173             :                      * and proper continuation after '/'. However, even with
    2174             :                      * the lax parsing only the error constants we have defined
    2175             :                      * as opcode symbols will be recognized and others result
    2176             :                      * in ocBad, so the result is actually conformant. */
    2177          92 :                     bool bAdd = true;
    2178          92 :                     if ('!' == c || '?' == c)
    2179          23 :                         eState = ssStop;
    2180          69 :                     else if ('/' == c)
    2181             :                     {
    2182           0 :                         if (!bErrorConstantHadSlash)
    2183           0 :                             bErrorConstantHadSlash = true;
    2184             :                         else
    2185             :                         {
    2186           0 :                             bAdd = false;
    2187           0 :                             eState = ssStop;
    2188             :                         }
    2189             :                     }
    2190          69 :                     else if ((nMask & SC_COMPILER_C_WORD_SEP) ||
    2191          69 :                             (c < 128 && !rtl::isAsciiAlphanumeric( c)))
    2192             :                     {
    2193           0 :                         bAdd = false;
    2194           0 :                         eState = ssStop;
    2195             :                     }
    2196          92 :                     if (!bAdd)
    2197           0 :                         --pSrc;
    2198             :                     else
    2199             :                     {
    2200          92 :                         if (pSym == &cSymbol[ MAXSTRLEN-1 ])
    2201             :                         {
    2202           0 :                             SetError( errStringOverflow);
    2203           0 :                             eState = ssStop;
    2204             :                         }
    2205             :                         else
    2206          92 :                             *pSym++ = c;
    2207             :                     }
    2208             :                 }
    2209          92 :                 break;
    2210             :             case ssGetTableRefItem:
    2211             :                 {
    2212             :                     // Scan whatever up to the next ']' closer.
    2213           0 :                     if (c != ']')
    2214             :                     {
    2215           0 :                         if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2216             :                         {
    2217           0 :                             SetError( errStringOverflow);
    2218           0 :                             eState = ssStop;
    2219             :                         }
    2220             :                         else
    2221           0 :                             *pSym++ = c;
    2222             :                     }
    2223             :                     else
    2224             :                     {
    2225           0 :                         --pSrc;
    2226           0 :                         eState = ssStop;
    2227             :                     }
    2228             :                 }
    2229           0 :                 break;
    2230             :             case ssGetTableRefColumn:
    2231             :                 {
    2232             :                     // Scan whatever up to the next unescaped ']' closer.
    2233           0 :                     if (c != ']' || cLast == '\'')
    2234             :                     {
    2235           0 :                         if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2236             :                         {
    2237           0 :                             SetError( errStringOverflow);
    2238           0 :                             eState = ssStop;
    2239             :                         }
    2240             :                         else
    2241           0 :                             *pSym++ = c;
    2242             :                     }
    2243             :                     else
    2244             :                     {
    2245           0 :                         --pSrc;
    2246           0 :                         eState = ssStop;
    2247             :                     }
    2248             :                 }
    2249           0 :                 break;
    2250             :             case ssGetReference:
    2251       11731 :                 if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2252             :                 {
    2253           0 :                     SetError( errStringOverflow);
    2254           0 :                     eState = ssSkipReference;
    2255             :                 }
    2256             :                 // fall through and follow logic
    2257             :             case ssSkipReference:
    2258             :                 // ODF reference: ['External'#$'Sheet'.A1:.B2] with dots being
    2259             :                 // mandatory also if no sheet name. 'External'# is optional,
    2260             :                 // sheet name is optional, quotes around sheet name are
    2261             :                 // optional if no quote contained. [#REF!] is valid.
    2262             :                 // 2nd usage: ['Sheet'.$$'DefinedName']
    2263             :                 // 3rd usage: ['External'#$$'DefinedName']
    2264             :                 // 4th usage: ['External'#$'Sheet'.$$'DefinedName']
    2265             :                 // Also for all these names quotes are optional if no quote
    2266             :                 // contained.
    2267             :                 {
    2268             : 
    2269             :                     // nRefInName: 0 := not in sheet name yet. 'External'
    2270             :                     // is parsed as if it was a sheet name and nRefInName
    2271             :                     // is reset when # is encountered immediately after closing
    2272             :                     // quote. Same with 'DefinedName', nRefInName is cleared
    2273             :                     // when : is encountered.
    2274             : 
    2275             :                     // Encountered leading $ before sheet name.
    2276             :                     static const int kDollar    = (1 << 1);
    2277             :                     // Encountered ' opening quote, which may be after $ or
    2278             :                     // not.
    2279             :                     static const int kOpen      = (1 << 2);
    2280             :                     // Somewhere in name.
    2281             :                     static const int kName      = (1 << 3);
    2282             :                     // Encountered ' in name, will be cleared if double or
    2283             :                     // transformed to kClose if not, in which case kOpen is
    2284             :                     // cleared.
    2285             :                     static const int kQuote     = (1 << 4);
    2286             :                     // Past ' closing quote.
    2287             :                     static const int kClose     = (1 << 5);
    2288             :                     // Encountered # file/sheet separator.
    2289             :                     static const int kFileSep   = (1 << 6);
    2290             :                     // Past . sheet name separator.
    2291             :                     static const int kPast      = (1 << 7);
    2292             :                     // Marked name $$ follows sheet name separator, detected
    2293             :                     // while we're still on the separator. Will be cleared when
    2294             :                     // entering the name.
    2295             :                     static const int kMarkAhead = (1 << 8);
    2296             :                     // In marked defined name.
    2297             :                     static const int kDefName   = (1 << 9);
    2298             :                     // Encountered # of #REF!
    2299             :                     static const int kRefErr    = (1 << 10);
    2300             : 
    2301       11731 :                     bool bAddToSymbol = true;
    2302       11731 :                     if ((nMask & SC_COMPILER_C_ODF_RBRACKET) && !(nRefInName & kOpen))
    2303             :                     {
    2304             :                         OSL_ENSURE( nRefInName & (kPast | kDefName | kRefErr),
    2305             :                                 "ScCompiler::NextSymbol: reference: "
    2306             :                                 "closing bracket ']' without prior sheet name separator '.' violates ODF spec");
    2307             :                         // eaten, not added to pSym
    2308         789 :                         bAddToSymbol = false;
    2309         789 :                         eState = ssStop;
    2310             :                     }
    2311       10942 :                     else if (cSheetSep == c && nRefInName == 0)
    2312             :                     {
    2313             :                         // eat it, no sheet name [.A1]
    2314        1015 :                         bAddToSymbol = false;
    2315        1015 :                         nRefInName |= kPast;
    2316        2030 :                         if ('$' == pSrc[0] && '$' == pSrc[1])
    2317           0 :                             nRefInName |= kMarkAhead;
    2318             :                     }
    2319        9927 :                     else if (!(nRefInName & kPast) || (nRefInName & (kMarkAhead | kDefName)))
    2320             :                     {
    2321             :                         // Not in col/row yet.
    2322             : 
    2323       13444 :                         if (SC_COMPILER_FILE_TAB_SEP == c && (nRefInName & kFileSep))
    2324          57 :                             nRefInName = 0;
    2325        6665 :                         else if ('$' == c && '$' == pSrc[0] && !(nRefInName & kOpen))
    2326             :                         {
    2327           0 :                             nRefInName &= ~kMarkAhead;
    2328           0 :                             if (!(nRefInName & kDefName))
    2329             :                             {
    2330             :                                 // eaten, not added to pSym (2 chars)
    2331           0 :                                 bAddToSymbol = false;
    2332           0 :                                 ++pSrc;
    2333           0 :                                 nRefInName &= kPast;
    2334           0 :                                 nRefInName |= kDefName;
    2335             :                             }
    2336             :                             else
    2337             :                             {
    2338             :                                 // ScAddress::Parse() will recognize this as
    2339             :                                 // invalid later.
    2340           0 :                                 if (eState != ssSkipReference)
    2341             :                                 {
    2342           0 :                                     *pSym++ = c;
    2343           0 :                                     *pSym++ = *pSrc++;
    2344             :                                 }
    2345           0 :                                 bAddToSymbol = false;
    2346             :                             }
    2347             :                         }
    2348        6665 :                         else if (cSheetPrefix == c && nRefInName == 0)
    2349          64 :                             nRefInName |= kDollar;
    2350        6601 :                         else if ('\'' == c)
    2351             :                         {
    2352             :                             // TODO: The conventions' parseExternalName()
    2353             :                             // should handle quoted names, but as long as they
    2354             :                             // don't remove non-embedded quotes here.
    2355         118 :                             if (!(nRefInName & kName))
    2356             :                             {
    2357          58 :                                 nRefInName |= (kOpen | kName);
    2358          58 :                                 bAddToSymbol = !(nRefInName & kDefName);
    2359             :                             }
    2360          60 :                             else if (!(nRefInName & kOpen))
    2361             :                             {
    2362             :                                 OSL_FAIL("ScCompiler::NextSymbol: reference: "
    2363             :                                         "a ''' without the name being enclosed in '...' violates ODF spec");
    2364             :                             }
    2365          60 :                             else if (nRefInName & kQuote)
    2366             :                             {
    2367             :                                 // escaped embedded quote
    2368           1 :                                 nRefInName &= ~kQuote;
    2369             :                             }
    2370             :                             else
    2371             :                             {
    2372          59 :                                 switch (pSrc[0])
    2373             :                                 {
    2374             :                                     case '\'':
    2375             :                                         // escapes embedded quote
    2376           1 :                                         nRefInName |= kQuote;
    2377           1 :                                         break;
    2378             :                                     case SC_COMPILER_FILE_TAB_SEP:
    2379             :                                         // sheet name should follow
    2380          57 :                                         nRefInName |= kFileSep;
    2381             :                                         // fallthru
    2382             :                                     default:
    2383             :                                         // quote not followed by quote => close
    2384          58 :                                         nRefInName |= kClose;
    2385          58 :                                         nRefInName &= ~kOpen;
    2386             :                                 }
    2387          59 :                                 bAddToSymbol = !(nRefInName & kDefName);
    2388             :                             }
    2389             :                         }
    2390        6483 :                         else if ('#' == c && nRefInName == 0)
    2391           0 :                             nRefInName |= kRefErr;
    2392        6483 :                         else if (cSheetSep == c && !(nRefInName & kOpen))
    2393             :                         {
    2394             :                             // unquoted sheet name separator
    2395         122 :                             nRefInName |= kPast;
    2396         244 :                             if ('$' == pSrc[0] && '$' == pSrc[1])
    2397           0 :                                 nRefInName |= kMarkAhead;
    2398             :                         }
    2399        6361 :                         else if (':' == c && !(nRefInName & kOpen))
    2400             :                         {
    2401             :                             OSL_FAIL("ScCompiler::NextSymbol: reference: "
    2402             :                                     "range operator ':' without prior sheet name separator '.' violates ODF spec");
    2403           0 :                             nRefInName = 0;
    2404           0 :                             ++mnPredetectedReference;
    2405             :                         }
    2406        6361 :                         else if (!(nRefInName & kName))
    2407             :                         {
    2408             :                             // start unquoted name
    2409         132 :                             nRefInName |= kName;
    2410             :                         }
    2411             :                     }
    2412        3205 :                     else if (':' == c)
    2413             :                     {
    2414             :                         // range operator
    2415         359 :                         nRefInName = 0;
    2416         359 :                         ++mnPredetectedReference;
    2417             :                     }
    2418       11731 :                     if (bAddToSymbol && eState != ssSkipReference)
    2419        9927 :                         *pSym++ = c;    // everything is part of reference
    2420             :                 }
    2421       11731 :                 break;
    2422             :             case ssStop:
    2423             :                 ;   // nothing, prevent warning
    2424        6336 :                 break;
    2425             :         }
    2426      125709 :         cLast = c;
    2427      125709 :         c = *pSrc;
    2428             :     }
    2429       30809 :     if ( bi18n )
    2430             :     {
    2431         186 :         nSrcPos = nSrcPos + nSpaces;
    2432         186 :         OUStringBuffer aSymbol;
    2433         186 :         mnRangeOpPosInSymbol = -1;
    2434         186 :         sal_uInt16 nErr = 0;
    2435         463 :         do
    2436             :         {
    2437         463 :             bi18n = false;
    2438             :             // special case  (e.g. $'sheetname' in OOO A1)
    2439         463 :             if ( pStart[nSrcPos] == cSheetPrefix && pStart[nSrcPos+1] == '\'' )
    2440         131 :                 aSymbol.append(pStart[nSrcPos++]);
    2441             : 
    2442         463 :             ParseResult aRes = pConv->parseAnyToken( aFormula, nSrcPos, pCharClass );
    2443             : 
    2444         463 :             if ( !aRes.TokenType )
    2445           0 :                 SetError( nErr = errIllegalChar );      // parsed chars as string
    2446         463 :             if ( aRes.EndPos <= nSrcPos )
    2447             :             {   // ?!?
    2448           0 :                 SetError( nErr = errIllegalChar );
    2449           0 :                 nSrcPos = aFormula.getLength();
    2450           0 :                 aSymbol.truncate(0);
    2451             :             }
    2452             :             else
    2453             :             {
    2454         463 :                 aSymbol.append( pStart + nSrcPos, aRes.EndPos - nSrcPos);
    2455         463 :                 nSrcPos = aRes.EndPos;
    2456         463 :                 c = pStart[nSrcPos];
    2457         463 :                 if ( aRes.TokenType & KParseType::SINGLE_QUOTE_NAME )
    2458             :                 {   // special cases (e.g. 'sheetname'. or 'filename'# in OOO A1)
    2459         173 :                     bi18n = (c == cSheetSep || c == SC_COMPILER_FILE_TAB_SEP);
    2460             :                 }
    2461             :                 // One range operator restarts parsing for second reference.
    2462         463 :                 if (c == ':' && mnRangeOpPosInSymbol < 0)
    2463             :                 {
    2464         104 :                     mnRangeOpPosInSymbol = aSymbol.getLength();
    2465         104 :                     bi18n = true;
    2466             :                 }
    2467         463 :                 if ( bi18n )
    2468         277 :                     aSymbol.append(pStart[nSrcPos++]);
    2469         463 :             }
    2470         277 :         } while ( bi18n && !nErr );
    2471         186 :         sal_Int32 nLen = aSymbol.getLength();
    2472         186 :         if ( nLen >= MAXSTRLEN )
    2473             :         {
    2474           0 :             SetError( errStringOverflow );
    2475           0 :             nLen = MAXSTRLEN-1;
    2476             :         }
    2477         186 :         lcl_UnicodeStrNCpy( cSymbol, aSymbol.getStr(), nLen );
    2478         186 :         pSym = &cSymbol[nLen];
    2479             :     }
    2480             :     else
    2481             :     {
    2482       30623 :         nSrcPos = pSrc - pStart;
    2483       30623 :         *pSym = 0;
    2484             :     }
    2485       30809 :     if (mnRangeOpPosInSymbol >= 0 && mnRangeOpPosInSymbol == (pSym-1) - &cSymbol[0])
    2486             :     {
    2487             :         // This is a trailing range operator, which is nonsense. Will be caught
    2488             :         // in next round.
    2489           0 :         mnRangeOpPosInSymbol = -1;
    2490           0 :         *--pSym = 0;
    2491           0 :         --nSrcPos;
    2492             :     }
    2493       30809 :     if ( bAutoCorrect )
    2494           0 :         aCorrectedSymbol = cSymbol;
    2495       30809 :     if (bAutoIntersection && nSpaces > 1)
    2496           0 :         --nSpaces;  // replace '!!' with only one space
    2497       30809 :     return nSpaces;
    2498             : }
    2499             : 
    2500             : // Convert symbol to token
    2501             : 
    2502       16476 : bool ScCompiler::IsOpCode( const OUString& rName, bool bInArray )
    2503             : {
    2504       16476 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
    2505       16476 :     bool bFound = (iLook != mxSymbols->getHashMap()->end());
    2506       16476 :     if (bFound)
    2507             :     {
    2508       12767 :         OpCode eOp = iLook->second;
    2509       12767 :         if (bInArray)
    2510             :         {
    2511         246 :             if (rName.equals(mxSymbols->getSymbol(ocArrayColSep)))
    2512          42 :                 eOp = ocArrayColSep;
    2513         204 :             else if (rName.equals(mxSymbols->getSymbol(ocArrayRowSep)))
    2514         132 :                 eOp = ocArrayRowSep;
    2515             :         }
    2516       12521 :         else if (eOp == ocCeil && mxSymbols->isOOXML())
    2517             :         {
    2518             :             // Ensure that _xlfn.CEILING.MATH maps to ocCeil_Math. ocCeil is
    2519             :             // unassigned for import.
    2520           0 :             eOp = ocCeil_Math;
    2521             :         }
    2522       12767 :         maRawToken.SetOpCode(eOp);
    2523             :     }
    2524        3709 :     else if (mxSymbols->isODFF())
    2525             :     {
    2526             :         // ODFF names that are not written in the current mapping but to be
    2527             :         // recognized. New names will be written in a future relase, then
    2528             :         // exchange (!) with the names in
    2529             :         // formula/source/core/resource/core_resource.src to be able to still
    2530             :         // read the old names as well.
    2531             :         struct FunctionName
    2532             :         {
    2533             :             const sal_Char* pName;
    2534             :             OpCode          eOp;
    2535             :         };
    2536             :         static const FunctionName aOdffAliases[] = {
    2537             :             // Renamed old names, still accept them:
    2538             :             { "B",              ocB },              // B -> BINOM.DIST.RANGE
    2539             :             { "TDIST",          ocTDist },          // TDIST -> LEGACY.TDIST
    2540             :             { "EASTERSUNDAY",   ocEasterSunday },   // EASTERSUNDAY -> ORG.OPENOFFICE.EASTERSUNDAY
    2541             :             { "ZGZ",            ocRRI },            // ZGZ -> RRI
    2542             :             { "COLOR",          ocColor },          // COLOR -> ORG.LIBREOFFICE.COLOR
    2543             :             { "GOALSEEK",       ocBackSolver },     // GOALSEEK -> ORG.OPENOFFICE.GOALSEEK
    2544             :             { "COM.MICROSOFT.F.DIST", ocFDist_LT }, // fdo#40835, -> FDIST -> COM.MICROSOFT.F.DIST
    2545             :             // Renamed new names, prepare to read future names:
    2546             :             //{ "ORG.OPENOFFICE.XXX", ocXXX }         // XXX -> ORG.OPENOFFICE.XXX
    2547             :         };
    2548             :         static const size_t nOdffAliases = sizeof(aOdffAliases) / sizeof(aOdffAliases[0]);
    2549        1212 :         for (size_t i=0; i<nOdffAliases; ++i)
    2550             :         {
    2551        1064 :             if (rName.equalsIgnoreAsciiCaseAscii( aOdffAliases[i].pName))
    2552             :             {
    2553           4 :                 maRawToken.SetOpCode( aOdffAliases[i].eOp);
    2554           4 :                 bFound = true;
    2555           4 :                 break;  // for
    2556             :             }
    2557             :         }
    2558             :     }
    2559       16476 :     if (!bFound)
    2560             :     {
    2561        3705 :         OUString aIntName;
    2562        3705 :         if (mxSymbols->hasExternals())
    2563             :         {
    2564             :             // If symbols are set by filters get mapping to exact name.
    2565             :             ExternalHashMap::const_iterator iExt(
    2566         643 :                     mxSymbols->getExternalHashMap()->find( rName));
    2567         643 :             if (iExt != mxSymbols->getExternalHashMap()->end())
    2568             :             {
    2569         100 :                 if (ScGlobal::GetAddInCollection()->GetFuncData( (*iExt).second))
    2570         100 :                     aIntName = (*iExt).second;
    2571             :             }
    2572         643 :             if (aIntName.isEmpty())
    2573             :             {
    2574             :                 // If that isn't found we might continue with rName lookup as a
    2575             :                 // last resort by just falling through to FindFunction(), but
    2576             :                 // it shouldn't happen if the map was setup correctly. Don't
    2577             :                 // waste time and bail out.
    2578         543 :                 return false;
    2579             :             }
    2580             :         }
    2581        3162 :         if (aIntName.isEmpty())
    2582             :         {
    2583             :             // Old (deprecated) addins first for legacy.
    2584        3062 :             if (ScGlobal::GetFuncCollection()->findByName(cSymbol))
    2585             :             {
    2586           0 :                 maRawToken.SetExternal( cSymbol );
    2587             :             }
    2588             :             else
    2589             :                 // bLocalFirst=false for (English) upper full original name
    2590             :                 // (service.function)
    2591        6124 :                 aIntName = ScGlobal::GetAddInCollection()->FindFunction(
    2592        6124 :                         rName, !mxSymbols->isEnglish());
    2593             :         }
    2594        3162 :         if (!aIntName.isEmpty())
    2595             :         {
    2596         100 :             maRawToken.SetExternal( aIntName.getStr() );     // international name
    2597         100 :             bFound = true;
    2598        3162 :         }
    2599             :     }
    2600             :     OpCode eOp;
    2601       15933 :     if (bFound && ((eOp = maRawToken.GetOpCode()) == ocSub || eOp == ocNegSub))
    2602             :     {
    2603             :         bool bShouldBeNegSub =
    2604         389 :             (eLastOp == ocOpen || eLastOp == ocSep || eLastOp == ocNegSub ||
    2605         110 :              (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_BIN_OP) ||
    2606         109 :              eLastOp == ocArrayOpen ||
    2607         314 :              eLastOp == ocArrayColSep || eLastOp == ocArrayRowSep);
    2608         206 :         if (bShouldBeNegSub && eOp == ocSub)
    2609         152 :             maRawToken.NewOpCode( ocNegSub );
    2610             :             //TODO: if ocNegSub had ForceArray we'd have to set it here
    2611          54 :         else if (!bShouldBeNegSub && eOp == ocNegSub)
    2612           0 :             maRawToken.NewOpCode( ocSub );
    2613             :     }
    2614       15933 :     return bFound;
    2615             : }
    2616             : 
    2617           0 : bool ScCompiler::IsOpCode2( const OUString& rName )
    2618             : {
    2619           0 :     bool bFound = false;
    2620             :     sal_uInt16 i;
    2621             : 
    2622           0 :     for( i = ocInternalBegin; i <= ocInternalEnd && !bFound; i++ )
    2623           0 :         bFound = rName.equalsAscii( pInternal[ i-ocInternalBegin ] );
    2624             : 
    2625           0 :     if (bFound)
    2626             :     {
    2627           0 :         maRawToken.SetOpCode( (OpCode) --i );
    2628             :     }
    2629           0 :     return bFound;
    2630             : }
    2631             : 
    2632        3438 : bool ScCompiler::IsValue( const OUString& rSym )
    2633             : {
    2634             :     double fVal;
    2635        3438 :     sal_uInt32 nIndex = mxSymbols->isEnglish() ? mpFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US) : 0;
    2636             : 
    2637        3438 :     if (!mpFormatter->IsNumberFormat(rSym, nIndex, fVal))
    2638         131 :         return false;
    2639             : 
    2640        3307 :     sal_uInt16 nType = mpFormatter->GetType(nIndex);
    2641             : 
    2642             :     // Don't accept 3:3 as time, it is a reference to entire row 3 instead.
    2643             :     // Dates should never be entered directly and automatically converted
    2644             :     // to serial, because the serial would be wrong if null-date changed.
    2645             :     // Usually it wouldn't be accepted anyway because the date separator
    2646             :     // clashed with other separators or operators.
    2647        3307 :     if (nType & (css::util::NumberFormat::TIME | css::util::NumberFormat::DATE))
    2648           0 :         return false;
    2649             : 
    2650        3307 :     if (nType == css::util::NumberFormat::LOGICAL)
    2651             :     {
    2652           0 :         const sal_Unicode* p = aFormula.getStr() + nSrcPos;
    2653           0 :         while( *p == ' ' )
    2654           0 :             p++;
    2655           0 :         if (*p == '(')
    2656           0 :             return false;   // Boolean function instead.
    2657             :     }
    2658             : 
    2659        3307 :     if( nType == css::util::NumberFormat::TEXT )
    2660             :         // HACK: number too big!
    2661           0 :         SetError( errIllegalArgument );
    2662        3307 :     maRawToken.SetDouble( fVal );
    2663        3307 :     return true;
    2664             : }
    2665             : 
    2666       23114 : bool ScCompiler::IsString()
    2667             : {
    2668       23114 :     const sal_Unicode* p = cSymbol;
    2669      155013 :     while ( *p )
    2670      108785 :         p++;
    2671       23114 :     sal_Int32 nLen = sal::static_int_cast<sal_Int32>( p - cSymbol - 1 );
    2672       23114 :     bool bQuote = ((cSymbol[0] == '"') && (cSymbol[nLen] == '"'));
    2673       23114 :     if ((bQuote ? nLen-2 : nLen) > MAXSTRLEN-1)
    2674             :     {
    2675           0 :         SetError(errStringOverflow);
    2676           0 :         return false;
    2677             :     }
    2678       23114 :     if ( bQuote )
    2679             :     {
    2680         776 :         cSymbol[nLen] = '\0';
    2681         776 :         const sal_Unicode* pStr = cSymbol+1;
    2682         776 :         svl::SharedString aSS = pDoc->GetSharedStringPool().intern(OUString(pStr));
    2683         776 :         maRawToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    2684         776 :         return true;
    2685             :     }
    2686       22338 :     return false;
    2687             : }
    2688             : 
    2689         789 : bool ScCompiler::IsPredetectedReference(const OUString& rName)
    2690             : {
    2691             :     // Speedup documents with lots of broken references, e.g. sheet deleted.
    2692         789 :     sal_Int32 nPos = rName.indexOf("#REF!");
    2693         789 :     if (nPos != -1)
    2694             :     {
    2695             :         /* TODO: this may be enhanced by reusing scan information from
    2696             :          * NextSymbol(), the positions of quotes and special characters found
    2697             :          * there for $'sheet'.A1:... could be stored in a vector. We don't
    2698             :          * fully rescan here whether found positions are within single quotes
    2699             :          * for performance reasons. This code does not check for possible
    2700             :          * occurrences of insane "valid" sheet names like
    2701             :          * 'haha.#REF!1fooledyou' and will generate an error on such. */
    2702           0 :         if (nPos == 0)
    2703             :         {
    2704             :             // Per ODFF the correct string for a reference error is just #REF!,
    2705             :             // so pass it on.
    2706           0 :             if (rName.getLength() == 5)
    2707           0 :                 return IsErrorConstant( rName);
    2708           0 :             return false;           // #REF!.AB42 or #REF!42 or #REF!#REF!
    2709             :         }
    2710           0 :         sal_Unicode c = rName[nPos-1];      // before #REF!
    2711           0 :         if ('$' == c)
    2712             :         {
    2713           0 :             if (nPos == 1)
    2714           0 :                 return false;       // $#REF!.AB42 or $#REF!42 or $#REF!#REF!
    2715           0 :             c = rName[nPos-2];              // before $#REF!
    2716             :         }
    2717           0 :         sal_Unicode c2 = nPos+5 < rName.getLength() ? rName[nPos+5] : 0;     // after #REF!
    2718           0 :         switch (c)
    2719             :         {
    2720             :             case '.':
    2721           0 :                 if ('$' == c2 || '#' == c2 || ('0' <= c2 && c2 <= '9'))
    2722           0 :                     return false;   // sheet.#REF!42 or sheet.#REF!#REF!
    2723           0 :                 break;
    2724             :             case ':':
    2725           0 :                 if (mnPredetectedReference > 1 &&
    2726           0 :                         ('.' == c2 || '$' == c2 || '#' == c2 ||
    2727           0 :                          ('0' <= c2 && c2 <= '9')))
    2728           0 :                     return false;   // :#REF!.AB42 or :#REF!42 or :#REF!#REF!
    2729           0 :                 break;
    2730             :             default:
    2731           0 :                 if (comphelper::string::isalphaAscii(c) &&
    2732           0 :                         ((mnPredetectedReference > 1 && ':' == c2) || 0 == c2))
    2733           0 :                     return false;   // AB#REF!: or AB#REF!
    2734             :         }
    2735             :     }
    2736         789 :     switch (mnPredetectedReference)
    2737             :     {
    2738             :         case 1:
    2739         430 :             return IsSingleReference( rName);
    2740             :         case 2:
    2741         359 :             return IsDoubleReference( rName);
    2742             :     }
    2743           0 :     return false;
    2744             : }
    2745             : 
    2746        2954 : bool ScCompiler::IsDoubleReference( const OUString& rName )
    2747             : {
    2748        2954 :     ScRange aRange( aPos, aPos );
    2749        2954 :     const ScAddress::Details aDetails( pConv->meConv, aPos );
    2750        2954 :     ScAddress::ExternalInfo aExtInfo;
    2751        2954 :     sal_uInt16 nFlags = aRange.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
    2752        2954 :     if( nFlags & SCA_VALID )
    2753             :     {
    2754             :         ScComplexRefData aRef;
    2755        2954 :         aRef.InitRange( aRange );
    2756        2954 :         aRef.Ref1.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
    2757        2954 :         aRef.Ref1.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
    2758        2954 :         aRef.Ref1.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
    2759        2954 :         if ( !(nFlags & SCA_VALID_TAB) )
    2760           0 :             aRef.Ref1.SetTabDeleted( true );        // #REF!
    2761        2954 :         aRef.Ref1.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
    2762        2954 :         aRef.Ref2.SetColRel( (nFlags & SCA_COL2_ABSOLUTE) == 0 );
    2763        2954 :         aRef.Ref2.SetRowRel( (nFlags & SCA_ROW2_ABSOLUTE) == 0 );
    2764        2954 :         aRef.Ref2.SetTabRel( (nFlags & SCA_TAB2_ABSOLUTE) == 0 );
    2765        2954 :         if ( !(nFlags & SCA_VALID_TAB2) )
    2766          26 :             aRef.Ref2.SetTabDeleted( true );        // #REF!
    2767        2954 :         aRef.Ref2.SetFlag3D( ( nFlags & SCA_TAB2_3D ) != 0 );
    2768        2954 :         aRef.SetRange(aRange, aPos);
    2769        2954 :         if (aExtInfo.mbExternal)
    2770             :         {
    2771          35 :             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    2772          35 :             const OUString* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
    2773             :             maRawToken.SetExternalDoubleRef(
    2774          35 :                 aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
    2775          35 :             maExternalFiles.push_back(aExtInfo.mnFileId);
    2776             :         }
    2777             :         else
    2778             :         {
    2779        2919 :             maRawToken.SetDoubleReference(aRef);
    2780             :         }
    2781             :     }
    2782             : 
    2783        2954 :     return ( nFlags & SCA_VALID ) != 0;
    2784             : }
    2785             : 
    2786        6567 : bool ScCompiler::IsSingleReference( const OUString& rName )
    2787             : {
    2788        6567 :     ScAddress aAddr( aPos );
    2789        6567 :     const ScAddress::Details aDetails( pConv->meConv, aPos );
    2790        6567 :     ScAddress::ExternalInfo aExtInfo;
    2791        6567 :     sal_uInt16 nFlags = aAddr.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
    2792             :     // Something must be valid in order to recognize Sheet1.blah or blah.a1
    2793             :     // as a (wrong) reference.
    2794        6567 :     if( nFlags & ( SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB ) )
    2795             :     {
    2796             :         ScSingleRefData aRef;
    2797        3841 :         aRef.InitAddress( aAddr );
    2798        3841 :         aRef.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
    2799        3841 :         aRef.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
    2800        3841 :         aRef.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
    2801        3841 :         aRef.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
    2802             :         // the reference is really invalid
    2803        3841 :         if( !( nFlags & SCA_VALID ) )
    2804             :         {
    2805           0 :             if( !( nFlags & SCA_VALID_COL ) )
    2806           0 :                 aRef.SetColDeleted(true);
    2807           0 :             if( !( nFlags & SCA_VALID_ROW ) )
    2808           0 :                 aRef.SetRowDeleted(true);
    2809           0 :             if( !( nFlags & SCA_VALID_TAB ) )
    2810           0 :                 aRef.SetTabDeleted(true);
    2811           0 :             nFlags |= SCA_VALID;
    2812             :         }
    2813        3841 :         aRef.SetAddress(aAddr, aPos);
    2814             : 
    2815        3841 :         if (aExtInfo.mbExternal)
    2816             :         {
    2817          59 :             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    2818          59 :             const OUString* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
    2819             :             maRawToken.SetExternalSingleRef(
    2820          59 :                 aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
    2821          59 :             maExternalFiles.push_back(aExtInfo.mnFileId);
    2822             :         }
    2823             :         else
    2824        3782 :             maRawToken.SetSingleReference(aRef);
    2825             :     }
    2826             : 
    2827        6567 :     return ( nFlags & SCA_VALID ) != 0;
    2828             : }
    2829             : 
    2830        9444 : bool ScCompiler::IsReference( const OUString& rName )
    2831             : {
    2832             :     // Has to be called before IsValue
    2833        9444 :     sal_Unicode ch1 = rName[0];
    2834        9444 :     sal_Unicode cDecSep = ( mxSymbols->isEnglish() ? '.' :
    2835        9444 :         ScGlobal::pLocaleData->getNumDecimalSep()[0] );
    2836        9444 :     if ( ch1 == cDecSep )
    2837           0 :         return false;
    2838             :     // Who was that imbecile introducing '.' as the sheet name separator!?!
    2839        9444 :     if ( rtl::isAsciiDigit( ch1 ) )
    2840             :     {
    2841             :         // Numerical sheet name is valid.
    2842             :         // But English 1.E2 or 1.E+2 is value 100, 1.E-2 is 0.01
    2843             :         // Don't create a #REF! of values. But also do not bail out on
    2844             :         // something like 3:3, meaning entire row 3.
    2845             :         do
    2846             :         {
    2847        3307 :             const sal_Int32 nPos = ScGlobal::FindUnquoted( rName, '.');
    2848        3307 :             if ( nPos == -1 )
    2849             :             {
    2850        2889 :                 if (ScGlobal::FindUnquoted( rName, ':') != -1)
    2851           0 :                     break;      // may be 3:3, continue as usual
    2852        2889 :                 return false;
    2853             :             }
    2854         418 :             sal_Unicode const * const pTabSep = rName.getStr() + nPos;
    2855         418 :             sal_Unicode ch2 = pTabSep[1];   // maybe a column identifier
    2856         418 :             if ( !(ch2 == '$' || rtl::isAsciiAlpha( ch2 )) )
    2857         418 :                 return false;
    2858           0 :             if ( cDecSep == '.' && (ch2 == 'E' || ch2 == 'e')   // E + - digit
    2859           0 :                     && (GetCharTableFlags( pTabSep[2], pTabSep[1] ) & SC_COMPILER_C_VALUE_EXP) )
    2860             :             {   // #91053#
    2861             :                 // If it is an 1.E2 expression check if "1" is an existent sheet
    2862             :                 // name. If so, a desired value 1.E2 would have to be entered as
    2863             :                 // 1E2 or 1.0E2 or 1.E+2, sorry. Another possibility would be to
    2864             :                 // require numerical sheet names always being entered quoted, which
    2865             :                 // is not desirable (too many 1999, 2000, 2001 sheets in use).
    2866             :                 // Furthermore, XML files created with versions prior to SRC640e
    2867             :                 // wouldn't contain the quotes added by MakeTabStr()/CheckTabQuotes()
    2868             :                 // and would produce wrong formulas if the conditions here are met.
    2869             :                 // If you can live with these restrictions you may remove the
    2870             :                 // check and return an unconditional FALSE.
    2871           0 :                 OUString aTabName( rName.copy( 0, nPos ) );
    2872             :                 SCTAB nTab;
    2873           0 :                 if ( !pDoc->GetTable( aTabName, nTab ) )
    2874           0 :                     return false;
    2875             :                 // If sheet "1" exists and the expression is 1.E+2 continue as
    2876             :                 // usual, the ScRange/ScAddress parser will take care of it.
    2877             :             }
    2878             :         } while(false);
    2879             :     }
    2880             : 
    2881        6137 :     if (IsSingleReference( rName))
    2882        3411 :         return true;
    2883             : 
    2884             :     // Though the range operator is handled explicitly, when encountering
    2885             :     // something like Sheet1.A:A we will have to treat it as one entity if it
    2886             :     // doesn't pass as single cell reference.
    2887        2726 :     if (mnRangeOpPosInSymbol > 0)   // ":foo" would be nonsense
    2888             :     {
    2889        2595 :         if (IsDoubleReference( rName))
    2890        2595 :             return true;
    2891             :         // Now try with a symbol up to the range operator, rewind source
    2892             :         // position.
    2893           0 :         sal_Int32 nLen = mnRangeOpPosInSymbol;
    2894           0 :         while (cSymbol[++nLen])
    2895             :             ;
    2896           0 :         cSymbol[mnRangeOpPosInSymbol] = 0;
    2897           0 :         nSrcPos -= (nLen - mnRangeOpPosInSymbol);
    2898           0 :         mnRangeOpPosInSymbol = -1;
    2899           0 :         mbRewind = true;
    2900           0 :         return true;    // end all checks
    2901             :     }
    2902             :     else
    2903             :     {
    2904             :         // Special treatment for the 'E:\[doc]Sheet1:Sheet3'!D5 Excel sickness,
    2905             :         // mnRangeOpPosInSymbol did not catch the range operator as it is
    2906             :         // within a quoted name.
    2907         131 :         switch (pConv->meConv)
    2908             :         {
    2909             :             case FormulaGrammar::CONV_XL_A1:
    2910             :             case FormulaGrammar::CONV_XL_R1C1:
    2911             :             case FormulaGrammar::CONV_XL_OOX:
    2912          13 :                 if (rName[0] == '\'' && IsDoubleReference( rName))
    2913           0 :                     return true;
    2914          13 :                 break;
    2915             :             default:
    2916             :                 ;   // nothing
    2917             :         }
    2918             :     }
    2919         131 :     return false;
    2920             : }
    2921             : 
    2922           1 : bool ScCompiler::IsMacro( const OUString& rName )
    2923             : {
    2924             : #if !HAVE_FEATURE_SCRIPTING
    2925             :     (void) rName;
    2926             : 
    2927             :     return false;
    2928             : #else
    2929             : 
    2930             :     // Calling SfxObjectShell::GetBasic() may result in all sort of things
    2931             :     // including obtaining the model and deep down in
    2932             :     // SfxBaseModel::getDocumentStorage() acquiring the SolarMutex, which when
    2933             :     // formulas are compiled from a threaded import may result in a deadlock.
    2934             :     // Check first if we actually could acquire it and if not bail out.
    2935             :     /* FIXME: yes, but how ... */
    2936           1 :     vcl::SolarMutexTryAndBuyGuard g;
    2937           1 :     if (!g.isAcquired())
    2938             :     {
    2939             :         SAL_WARN( "sc.core", "ScCompiler::IsMacro - SolarMutex would deadlock, not obtaining Basic");
    2940           0 :         return false;   // bad luck
    2941             :     }
    2942             : 
    2943           2 :     OUString aName( rName);
    2944           1 :     StarBASIC* pObj = 0;
    2945           1 :     SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
    2946             : 
    2947             :     try
    2948             :     {
    2949           1 :         if( pDocSh )//XXX
    2950           1 :             pObj = pDocSh->GetBasic();
    2951             :         else
    2952           0 :             pObj = SfxApplication::GetBasic();
    2953             :     }
    2954           0 :     catch (...)
    2955             :     {
    2956           0 :         return false;
    2957             :     }
    2958             : 
    2959             :     // ODFF recommends to store user-defined functions prefixed with "USER.",
    2960             :     // use only unprefixed name if encountered. BASIC doesn't allow '.' in a
    2961             :     // function name so a function "USER.FOO" could not exist, and macro check
    2962             :     // is assigned the lowest priority in function name check.
    2963           1 :     if (FormulaGrammar::isODFF( GetGrammar()) && aName.startsWithIgnoreAsciiCase("USER."))
    2964           0 :         aName = aName.copy(5);
    2965             : 
    2966           1 :     SbxMethod* pMeth = static_cast<SbxMethod*>(pObj->Find( aName, SbxCLASS_METHOD ));
    2967           1 :     if( !pMeth )
    2968             :     {
    2969           0 :         return false;
    2970             :     }
    2971             :     // It really should be a BASIC function!
    2972           2 :     if( pMeth->GetType() == SbxVOID
    2973           1 :      || ( pMeth->IsFixed() && pMeth->GetType() == SbxEMPTY )
    2974           2 :      || !pMeth->ISA(SbMethod) )
    2975             :     {
    2976           0 :         return false;
    2977             :     }
    2978           1 :     maRawToken.SetExternal( aName.getStr() );
    2979           1 :     maRawToken.eOp = ocMacro;
    2980           2 :     return true;
    2981             : #endif
    2982             : }
    2983             : 
    2984         131 : bool ScCompiler::IsNamedRange( const OUString& rUpperName )
    2985             : {
    2986             :     // IsNamedRange is called only from NextNewToken, with an upper-case string
    2987             : 
    2988             :     // try local names first
    2989         131 :     bool bGlobal = false;
    2990         131 :     ScRangeName* pRangeName = pDoc->GetRangeName(aPos.Tab());
    2991         131 :     const ScRangeData* pData = NULL;
    2992         131 :     if (pRangeName)
    2993         130 :         pData = pRangeName->findByUpperName(rUpperName);
    2994         131 :     if (!pData)
    2995             :     {
    2996          90 :         pRangeName = pDoc->GetRangeName();
    2997          90 :         if (pRangeName)
    2998          90 :             pData = pRangeName->findByUpperName(rUpperName);
    2999          90 :         if (pData)
    3000          60 :             bGlobal = true;
    3001             :     }
    3002             : 
    3003         131 :     if (pData)
    3004             :     {
    3005         101 :         maRawToken.SetName(bGlobal, pData->GetIndex());
    3006         101 :         return true;
    3007             :     }
    3008             :     else
    3009          30 :         return false;
    3010             : }
    3011             : 
    3012          30 : bool ScCompiler::IsExternalNamedRange( const OUString& rSymbol, bool& rbInvalidExternalNameRange )
    3013             : {
    3014             :     /* FIXME: This code currently (2008-12-02T15:41+0100 in CWS mooxlsc)
    3015             :      * correctly parses external named references in OOo, as required per RFE
    3016             :      * #i3740#, just that we can't store them in ODF yet. We will need an OASIS
    3017             :      * spec first. Until then don't pretend to support external names that
    3018             :      * wouldn't survive a save and reload cycle, return false instead. */
    3019             : 
    3020          30 :     rbInvalidExternalNameRange = false;
    3021             : 
    3022          30 :     if (!pConv)
    3023           0 :         return false;
    3024             : 
    3025          60 :     OUString aFile, aName;
    3026          30 :     if (!pConv->parseExternalName( rSymbol, aFile, aName, pDoc, &maExternalLinks))
    3027          29 :         return false;
    3028             : 
    3029           1 :     if (aFile.getLength() > MAXSTRLEN || aName.getLength() > MAXSTRLEN)
    3030           0 :         return false;
    3031             : 
    3032           1 :     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    3033           2 :     OUString aTmp = aFile;
    3034           1 :     pRefMgr->convertToAbsName(aTmp);
    3035           1 :     aFile = aTmp;
    3036           1 :     sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFile);
    3037           1 :     if (!pRefMgr->isValidRangeName(nFileId, aName))
    3038             :     {
    3039           1 :         rbInvalidExternalNameRange = true;
    3040             :         // range name doesn't exist in the source document.
    3041           1 :         return false;
    3042             :     }
    3043             : 
    3044           0 :     const OUString* pRealName = pRefMgr->getRealRangeName(nFileId, aName);
    3045           0 :     maRawToken.SetExternalName(nFileId, pRealName ? *pRealName : OUString(aTmp));
    3046           0 :     maExternalFiles.push_back(nFileId);
    3047          30 :     return true;
    3048             : }
    3049             : 
    3050          29 : bool ScCompiler::IsDBRange( const OUString& rName )
    3051             : {
    3052          29 :     ScDBCollection::NamedDBs& rDBs = pDoc->GetDBCollection()->getNamedDBs();
    3053          29 :     const ScDBData* p = rDBs.findByUpperName(rName);
    3054          29 :     if (!p)
    3055          17 :         return false;
    3056             : 
    3057          12 :     maRawToken.SetName(true, p->GetIndex()); // DB range is always global.
    3058          12 :     maRawToken.eOp = ocDBArea;
    3059          12 :     return true;
    3060             : }
    3061             : 
    3062          16 : bool ScCompiler::IsColRowName( const OUString& rName )
    3063             : {
    3064          16 :     bool bInList = false;
    3065          16 :     bool bFound = false;
    3066             :     ScSingleRefData aRef;
    3067          16 :     OUString aName( rName );
    3068          16 :     DeQuote( aName );
    3069          16 :     SCTAB nThisTab = aPos.Tab();
    3070          48 :     for ( short jThisTab = 1; jThisTab >= 0 && !bInList; jThisTab-- )
    3071             :     {   // first check ranges on this sheet, in case of duplicated names
    3072          96 :         for ( short jRow=0; jRow<2 && !bInList; jRow++ )
    3073             :         {
    3074             :             ScRangePairList* pRL;
    3075          64 :             if ( !jRow )
    3076          32 :                 pRL = pDoc->GetColNameRanges();
    3077             :             else
    3078          32 :                 pRL = pDoc->GetRowNameRanges();
    3079          64 :             for ( size_t iPair = 0, nPairs = pRL->size(); iPair < nPairs && !bInList; ++iPair )
    3080             :             {
    3081           0 :                 ScRangePair* pR = (*pRL)[iPair];
    3082           0 :                 const ScRange& rNameRange = pR->GetRange(0);
    3083           0 :                 if ( jThisTab && !(rNameRange.aStart.Tab() <= nThisTab &&
    3084           0 :                         nThisTab <= rNameRange.aEnd.Tab()) )
    3085           0 :                     continue;   // for
    3086           0 :                 ScCellIterator aIter( pDoc, rNameRange );
    3087           0 :                 for (bool bHas = aIter.first(); bHas && !bInList; bHas = aIter.next())
    3088             :                 {
    3089             :                     // Don't crash if cell (via CompileNameFormula) encounters
    3090             :                     // a formula cell without code and
    3091             :                     // HasStringData/Interpret/Compile is executed and all that
    3092             :                     // recursive..
    3093             :                     // Furthermore, *this* cell won't be touched, since no RPN exists yet.
    3094           0 :                     CellType eType = aIter.getType();
    3095           0 :                     bool bOk = false;
    3096           0 :                     if (eType == CELLTYPE_FORMULA)
    3097             :                     {
    3098           0 :                         ScFormulaCell* pFC = aIter.getFormulaCell();
    3099           0 :                         bOk = (pFC->GetCode()->GetCodeLen() > 0) && (pFC->aPos != aPos);
    3100             :                     }
    3101             :                     else
    3102           0 :                         bOk = true;
    3103             : 
    3104           0 :                     if (bOk && aIter.hasString())
    3105             :                     {
    3106           0 :                         OUString aStr = aIter.getString();
    3107           0 :                         if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) )
    3108             :                         {
    3109           0 :                             aRef.InitFlags();
    3110           0 :                             if ( !jRow )
    3111           0 :                                 aRef.SetColRel( true );     // ColName
    3112             :                             else
    3113           0 :                                 aRef.SetRowRel( true );     // RowName
    3114           0 :                             aRef.SetAddress(aIter.GetPos(), aPos);
    3115           0 :                             bInList = bFound = true;
    3116           0 :                         }
    3117             :                     }
    3118             :                 }
    3119           0 :             }
    3120             :         }
    3121             :     }
    3122          16 :     if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
    3123             :     {   // search in current sheet
    3124          13 :         long nDistance = 0, nMax = 0;
    3125          13 :         long nMyCol = (long) aPos.Col();
    3126          13 :         long nMyRow = (long) aPos.Row();
    3127          13 :         bool bTwo = false;
    3128          13 :         ScAddress aOne( 0, 0, aPos.Tab() );
    3129          13 :         ScAddress aTwo( MAXCOL, MAXROW, aPos.Tab() );
    3130             : 
    3131          13 :         ScAutoNameCache* pNameCache = pDoc->GetAutoNameCache();
    3132          13 :         if ( pNameCache )
    3133             :         {
    3134             :             //  use GetNameOccurrences to collect all positions of aName on the sheet
    3135             :             //  (only once), similar to the outer part of the loop in the "else" branch.
    3136             : 
    3137           4 :             const ScAutoNameAddresses& rAddresses = pNameCache->GetNameOccurrences( aName, aPos.Tab() );
    3138             : 
    3139             :             //  Loop through the found positions, similar to the inner part of the loop in the "else" branch.
    3140             :             //  The order of addresses in the vector is the same as from ScCellIterator.
    3141             : 
    3142           4 :             ScAutoNameAddresses::const_iterator aEnd(rAddresses.end());
    3143           4 :             for ( ScAutoNameAddresses::const_iterator aAdrIter(rAddresses.begin()); aAdrIter != aEnd; ++aAdrIter )
    3144             :             {
    3145           0 :                 ScAddress aAddress( *aAdrIter );        // cell address with an equal string
    3146             : 
    3147           0 :                 if ( bFound )
    3148             :                 {   // stop if everything else is further away
    3149           0 :                     if ( nMax < (long)aAddress.Col() )
    3150           0 :                         break;      // aIter
    3151             :                 }
    3152           0 :                 if ( aAddress != aPos )
    3153             :                 {
    3154             :                     // same treatment as in isEqual case below
    3155             : 
    3156           0 :                     SCCOL nCol = aAddress.Col();
    3157           0 :                     SCROW nRow = aAddress.Row();
    3158           0 :                     long nC = nMyCol - nCol;
    3159           0 :                     long nR = nMyRow - nRow;
    3160           0 :                     if ( bFound )
    3161             :                     {
    3162           0 :                         long nD = nC * nC + nR * nR;
    3163           0 :                         if ( nD < nDistance )
    3164             :                         {
    3165           0 :                             if ( nC < 0 || nR < 0 )
    3166             :                             {   // right or below
    3167           0 :                                 bTwo = true;
    3168           0 :                                 aTwo.Set( nCol, nRow, aAddress.Tab() );
    3169           0 :                                 nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3170           0 :                                 nDistance = nD;
    3171             :                             }
    3172           0 :                             else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) )
    3173             :                             {
    3174             :                                 // upper left, only if not further up than the
    3175             :                                 // current entry and nMyRow is below (CellIter
    3176             :                                 // runs column-wise)
    3177           0 :                                 bTwo = false;
    3178           0 :                                 aOne.Set( nCol, nRow, aAddress.Tab() );
    3179           0 :                                 nMax = std::max( nMyCol + nC, nMyRow + nR );
    3180           0 :                                 nDistance = nD;
    3181             :                             }
    3182             :                         }
    3183             :                     }
    3184             :                     else
    3185             :                     {
    3186           0 :                         aOne.Set( nCol, nRow, aAddress.Tab() );
    3187           0 :                         nDistance = nC * nC + nR * nR;
    3188           0 :                         nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3189             : 
    3190             :                     }
    3191           0 :                     bFound = true;
    3192             :                 }
    3193             :             }
    3194             :         }
    3195             :         else
    3196             :         {
    3197           9 :             ScCellIterator aIter( pDoc, ScRange( aOne, aTwo ) );
    3198         136 :             for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
    3199             :             {
    3200         127 :                 if ( bFound )
    3201             :                 {   // stop if everything else is further away
    3202           0 :                     if ( nMax < (long)aIter.GetPos().Col() )
    3203           0 :                         break;      // aIter
    3204             :                 }
    3205         127 :                 CellType eType = aIter.getType();
    3206         127 :                 bool bOk = false;
    3207         127 :                 if (eType == CELLTYPE_FORMULA)
    3208             :                 {
    3209         125 :                     ScFormulaCell* pFC = aIter.getFormulaCell();
    3210         125 :                     bOk = (pFC->GetCode()->GetCodeLen() > 0) && (pFC->aPos != aPos);
    3211             :                 }
    3212             :                 else
    3213           2 :                     bOk = true;
    3214             : 
    3215         127 :                 if (bOk && aIter.hasString())
    3216             :                 {
    3217           0 :                     OUString aStr = aIter.getString();
    3218           0 :                     if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) )
    3219             :                     {
    3220           0 :                         SCCOL nCol = aIter.GetPos().Col();
    3221           0 :                         SCROW nRow = aIter.GetPos().Row();
    3222           0 :                         long nC = nMyCol - nCol;
    3223           0 :                         long nR = nMyRow - nRow;
    3224           0 :                         if ( bFound )
    3225             :                         {
    3226           0 :                             long nD = nC * nC + nR * nR;
    3227           0 :                             if ( nD < nDistance )
    3228             :                             {
    3229           0 :                                 if ( nC < 0 || nR < 0 )
    3230             :                                 {   // right or below
    3231           0 :                                     bTwo = true;
    3232           0 :                                     aTwo.Set( nCol, nRow, aIter.GetPos().Tab() );
    3233           0 :                                     nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3234           0 :                                     nDistance = nD;
    3235             :                                 }
    3236           0 :                                 else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) )
    3237             :                                 {
    3238             :                                     // upper left, only if not further up than the
    3239             :                                     // current entry and nMyRow is below (CellIter
    3240             :                                     // runs column-wise)
    3241           0 :                                     bTwo = false;
    3242           0 :                                     aOne.Set( nCol, nRow, aIter.GetPos().Tab() );
    3243           0 :                                     nMax = std::max( nMyCol + nC, nMyRow + nR );
    3244           0 :                                     nDistance = nD;
    3245             :                                 }
    3246             :                             }
    3247             :                         }
    3248             :                         else
    3249             :                         {
    3250           0 :                             aOne.Set( nCol, nRow, aIter.GetPos().Tab() );
    3251           0 :                             nDistance = nC * nC + nR * nR;
    3252           0 :                             nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3253             :                         }
    3254           0 :                         bFound = true;
    3255           0 :                     }
    3256             :                 }
    3257           9 :             }
    3258             :         }
    3259             : 
    3260          13 :         if ( bFound )
    3261             :         {
    3262           0 :             ScAddress aAdr;
    3263           0 :             if ( bTwo )
    3264             :             {
    3265           0 :                 if ( nMyCol >= (long)aOne.Col() && nMyRow >= (long)aOne.Row() )
    3266           0 :                     aAdr = aOne;        // upper left takes precedence
    3267             :                 else
    3268             :                 {
    3269           0 :                     if ( nMyCol < (long)aOne.Col() )
    3270             :                     {   // two to the right
    3271           0 :                         if ( nMyRow >= (long)aTwo.Row() )
    3272           0 :                             aAdr = aTwo;        // directly right
    3273             :                         else
    3274           0 :                             aAdr = aOne;
    3275             :                     }
    3276             :                     else
    3277             :                     {   // two below or below and right, take the nearest
    3278           0 :                         long nC1 = nMyCol - aOne.Col();
    3279           0 :                         long nR1 = nMyRow - aOne.Row();
    3280           0 :                         long nC2 = nMyCol - aTwo.Col();
    3281           0 :                         long nR2 = nMyRow - aTwo.Row();
    3282           0 :                         if ( nC1 * nC1 + nR1 * nR1 <= nC2 * nC2 + nR2 * nR2 )
    3283           0 :                             aAdr = aOne;
    3284             :                         else
    3285           0 :                             aAdr = aTwo;
    3286             :                     }
    3287             :                 }
    3288             :             }
    3289             :             else
    3290           0 :                 aAdr = aOne;
    3291           0 :             aRef.InitAddress( aAdr );
    3292           0 :             if ( (aAdr.Row() != MAXROW && pDoc->HasStringData(
    3293           0 :                     aAdr.Col(), aAdr.Row() + 1, aAdr.Tab()))
    3294           0 :               || (aAdr.Row() != 0 && pDoc->HasStringData(
    3295           0 :                     aAdr.Col(), aAdr.Row() - 1, aAdr.Tab())))
    3296           0 :                 aRef.SetRowRel( true );     // RowName
    3297             :             else
    3298           0 :                 aRef.SetColRel( true );     // ColName
    3299           0 :             aRef.SetAddress(aAdr, aPos);
    3300             :         }
    3301             :     }
    3302          16 :     if ( bFound )
    3303             :     {
    3304           0 :         maRawToken.SetSingleReference( aRef );
    3305           0 :         maRawToken.eOp = ocColRowName;
    3306           0 :         return true;
    3307             :     }
    3308             :     else
    3309          16 :         return false;
    3310             : }
    3311             : 
    3312          71 : bool ScCompiler::IsBoolean( const OUString& rName )
    3313             : {
    3314          71 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName ) );
    3315          71 :     if( iLook != mxSymbols->getHashMap()->end() &&
    3316           0 :         ((*iLook).second == ocTrue ||
    3317           0 :          (*iLook).second == ocFalse) )
    3318             :     {
    3319           0 :         maRawToken.SetOpCode( (*iLook).second );
    3320           0 :         return true;
    3321             :     }
    3322             :     else
    3323          71 :         return false;
    3324             : }
    3325             : 
    3326          23 : bool ScCompiler::IsErrorConstant( const OUString& rName ) const
    3327             : {
    3328          23 :     sal_uInt16 nError = GetErrorConstant( rName);
    3329          23 :     if (nError)
    3330             :     {
    3331          23 :         maRawToken.SetErrorConstant( nError);
    3332          23 :         return true;
    3333             :     }
    3334             :     else
    3335           0 :         return false;
    3336             : }
    3337             : 
    3338           0 : bool ScCompiler::IsTableRefItem( const OUString& rName ) const
    3339             : {
    3340           0 :     bool bItem = false;
    3341           0 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
    3342           0 :     if (iLook != mxSymbols->getHashMap()->end())
    3343             :     {
    3344             :         // Only called when there actually is a current TableRef, hence
    3345             :         // accessing maTableRefs.back() is safe.
    3346           0 :         ScTableRefToken* p = dynamic_cast<ScTableRefToken*>(maTableRefs.back().mxToken.get());
    3347             :         assert(p);  // not a ScTableRefToken can't be
    3348             : 
    3349           0 :         switch ((*iLook).second)
    3350             :         {
    3351             :             case ocTableRefItemAll:
    3352           0 :                 bItem = true;
    3353           0 :                 p->AddItem( ScTableRefToken::ALL);
    3354           0 :                 break;
    3355             :             case ocTableRefItemHeaders:
    3356           0 :                 bItem = true;
    3357           0 :                 p->AddItem( ScTableRefToken::HEADERS);
    3358           0 :                 break;
    3359             :             case ocTableRefItemData:
    3360           0 :                 bItem = true;
    3361           0 :                 p->AddItem( ScTableRefToken::DATA);
    3362           0 :                 break;
    3363             :             case ocTableRefItemTotals:
    3364           0 :                 bItem = true;
    3365           0 :                 p->AddItem( ScTableRefToken::TOTALS);
    3366           0 :                 break;
    3367             :             case ocTableRefItemThisRow:
    3368           0 :                 bItem = true;
    3369           0 :                 p->AddItem( ScTableRefToken::THIS_ROW);
    3370           0 :                 break;
    3371             :             default:
    3372             :                 ;
    3373             :         }
    3374           0 :         if (bItem)
    3375           0 :             maRawToken.SetOpCode( (*iLook).second );
    3376             :     }
    3377           0 :     return bItem;
    3378             : }
    3379             : 
    3380             : namespace {
    3381           0 : OUString unescapeTableRefColumnSpecifier( const OUString& rStr )
    3382             : {
    3383             :     // '#', '[', ']' and '\'' are escaped with '\''
    3384             : 
    3385           0 :     if (rStr.indexOf( '\'' ) < 0)
    3386           0 :         return rStr;
    3387             : 
    3388           0 :     const sal_Int32 n = rStr.getLength();
    3389           0 :     OUStringBuffer aBuf( n );
    3390           0 :     const sal_Unicode* p = rStr.getStr();
    3391           0 :     const sal_Unicode* const pStop = p + n;
    3392           0 :     bool bEscaped = false;
    3393           0 :     for ( ; p < pStop; ++p)
    3394             :     {
    3395           0 :         const sal_Unicode c = *p;
    3396           0 :         if (bEscaped)
    3397             :         {
    3398           0 :             aBuf.append( c );
    3399           0 :             bEscaped = false;
    3400             :         }
    3401           0 :         else if (c == '\'')
    3402           0 :             bEscaped = true;    // unescaped escaping '\''
    3403             :         else
    3404           0 :             aBuf.append( c );
    3405             :     }
    3406           0 :     return aBuf.makeStringAndClear();
    3407             : }
    3408             : }
    3409             : 
    3410           0 : bool ScCompiler::IsTableRefColumn( const OUString& rName ) const
    3411             : {
    3412             :     // Only called when there actually is a current TableRef, hence
    3413             :     // accessing maTableRefs.back() is safe.
    3414           0 :     ScTableRefToken* p = dynamic_cast<ScTableRefToken*>(maTableRefs.back().mxToken.get());
    3415             :     assert(p);  // not a ScTableRefToken can't be
    3416             : 
    3417           0 :     ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex( p->GetIndex());
    3418           0 :     if (!pDBData)
    3419           0 :         return false;
    3420             : 
    3421           0 :     OUString aName( unescapeTableRefColumnSpecifier( rName));
    3422             : 
    3423           0 :     ScRange aRange;
    3424           0 :     pDBData->GetArea( aRange);
    3425           0 :     aRange.aEnd.SetTab( aRange.aStart.Tab());
    3426           0 :     aRange.aEnd.SetRow( aRange.aStart.Row());
    3427             : 
    3428             :     // Quite similar to IsColRowName() but limited to one row of headers.
    3429           0 :     ScCellIterator aIter( pDoc, aRange);
    3430           0 :     for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
    3431             :     {
    3432           0 :         CellType eType = aIter.getType();
    3433           0 :         bool bOk = false;
    3434           0 :         if (eType == CELLTYPE_FORMULA)
    3435             :         {
    3436           0 :             ScFormulaCell* pFC = aIter.getFormulaCell();
    3437           0 :             bOk = (pFC->GetCode()->GetCodeLen() > 0) && (pFC->aPos != aPos);
    3438             :         }
    3439             :         else
    3440           0 :             bOk = true;
    3441             : 
    3442           0 :         if (bOk && aIter.hasString())
    3443             :         {
    3444           0 :             OUString aStr = aIter.getString();
    3445           0 :             if (ScGlobal::GetpTransliteration()->isEqual( aStr, aName))
    3446             :             {
    3447             :                 ScSingleRefData aRef;
    3448           0 :                 aRef.InitFlags();
    3449           0 :                 aRef.SetColRel( true );
    3450           0 :                 aRef.SetAddress( aIter.GetPos(), aPos);
    3451           0 :                 maRawToken.SetSingleReference( aRef );
    3452           0 :                 return true;
    3453           0 :             }
    3454             :         }
    3455             :     }
    3456           0 :     return false;
    3457             : }
    3458             : 
    3459           0 : void ScCompiler::SetAutoCorrection( bool bVal )
    3460             : {
    3461             :     assert(mbJumpCommandReorder);
    3462           0 :     bAutoCorrect = bVal;
    3463           0 :     mbStopOnError = !bVal;
    3464           0 : }
    3465             : 
    3466           0 : void ScCompiler::AutoCorrectParsedSymbol()
    3467             : {
    3468           0 :     sal_Int32 nPos = aCorrectedSymbol.getLength();
    3469           0 :     if ( nPos )
    3470             :     {
    3471           0 :         nPos--;
    3472           0 :         const sal_Unicode cQuote = '\"';
    3473           0 :         const sal_Unicode cx = 'x';
    3474           0 :         const sal_Unicode cX = 'X';
    3475           0 :         sal_Unicode c1 = aCorrectedSymbol[0];
    3476           0 :         sal_Unicode c2 = aCorrectedSymbol[nPos];
    3477           0 :         sal_Unicode c2p = nPos > 0 ? aCorrectedSymbol[nPos-1] : 0;
    3478           0 :         if ( c1 == cQuote && c2 != cQuote  )
    3479             :         {   // "...
    3480             :             // What's not a word doesn't belong to it.
    3481             :             // Don't be pedantic: c < 128 should be sufficient here.
    3482           0 :             while ( nPos && ((aCorrectedSymbol[nPos] < 128) &&
    3483           0 :                     ((GetCharTableFlags(aCorrectedSymbol[nPos], aCorrectedSymbol[nPos-1]) &
    3484             :                     (SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_DONTCARE)) == 0)) )
    3485           0 :                 nPos--;
    3486           0 :             if ( nPos == MAXSTRLEN - 2 )
    3487           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAt( nPos, 1, OUString(cQuote) );   // '"' the 255th character
    3488             :             else
    3489           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAt( nPos + 1, 0, OUString(cQuote) );
    3490           0 :             bCorrected = true;
    3491             :         }
    3492           0 :         else if ( c1 != cQuote && c2 == cQuote )
    3493             :         {   // ..."
    3494           0 :             aCorrectedSymbol = OUStringLiteral1<cQuote>() + aCorrectedSymbol;
    3495           0 :             bCorrected = true;
    3496             :         }
    3497           0 :         else if ( nPos == 0 && (c1 == cx || c1 == cX) )
    3498             :         {   // x => *
    3499           0 :             aCorrectedSymbol = mxSymbols->getSymbol(ocMul);
    3500           0 :             bCorrected = true;
    3501             :         }
    3502           0 :         else if ( (GetCharTableFlags( c1, 0 ) & SC_COMPILER_C_CHAR_VALUE)
    3503           0 :                && (GetCharTableFlags( c2, c2p ) & SC_COMPILER_C_CHAR_VALUE) )
    3504             :         {
    3505           0 :             if ( comphelper::string::getTokenCount(aCorrectedSymbol, cx) > 1 )
    3506             :             {   // x => *
    3507           0 :                 sal_Unicode c = mxSymbols->getSymbolChar(ocMul);
    3508           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAll(OUString(cx), OUString(c));
    3509           0 :                 bCorrected = true;
    3510             :             }
    3511           0 :             if ( comphelper::string::getTokenCount(aCorrectedSymbol, cX) > 1 )
    3512             :             {   // X => *
    3513           0 :                 sal_Unicode c = mxSymbols->getSymbolChar(ocMul);
    3514           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAll(OUString(cX), OUString(c));
    3515           0 :                 bCorrected = true;
    3516             :             }
    3517             :         }
    3518             :         else
    3519             :         {
    3520           0 :             OUString aSymbol( aCorrectedSymbol );
    3521           0 :             OUString aDoc;
    3522             :             sal_Int32 nPosition;
    3523           0 :             if ( aSymbol[0] == '\''
    3524           0 :               && ((nPosition = aSymbol.indexOf( "'#" )) != -1) )
    3525             :             {   // Split off 'Doc'#, may be d:\... or whatever
    3526           0 :                 aDoc = aSymbol.copy(0, nPosition + 2);
    3527           0 :                 aSymbol = aSymbol.copy(nPosition + 2);
    3528             :             }
    3529           0 :             sal_Int32 nRefs = comphelper::string::getTokenCount(aSymbol, ':');
    3530             :             bool bColons;
    3531           0 :             if ( nRefs > 2 )
    3532             :             {   // duplicated or too many ':'? B:2::C10 => B2:C10
    3533           0 :                 bColons = true;
    3534           0 :                 sal_Int32 nIndex = 0;
    3535           0 :                 OUString aTmp1( aSymbol.getToken( 0, ':', nIndex ) );
    3536           0 :                 sal_Int32 nLen1 = aTmp1.getLength();
    3537           0 :                 OUString aSym, aTmp2;
    3538             :                 bool bLastAlp, bNextNum;
    3539           0 :                 bLastAlp = bNextNum = true;
    3540           0 :                 sal_Int32 nStrip = 0;
    3541           0 :                 sal_Int32 nCount = nRefs;
    3542           0 :                 for ( sal_Int32 j=1; j<nCount; j++ )
    3543             :                 {
    3544           0 :                     aTmp2 = aSymbol.getToken( 0, ':', nIndex );
    3545           0 :                     sal_Int32 nLen2 = aTmp2.getLength();
    3546           0 :                     if ( nLen1 || nLen2 )
    3547             :                     {
    3548           0 :                         if ( nLen1 )
    3549             :                         {
    3550           0 :                             aSym += aTmp1;
    3551           0 :                             bLastAlp = CharClass::isAsciiAlpha( aTmp1 );
    3552             :                         }
    3553           0 :                         if ( nLen2 )
    3554             :                         {
    3555           0 :                             bNextNum = CharClass::isAsciiNumeric( aTmp2 );
    3556           0 :                             if ( bLastAlp == bNextNum && nStrip < 1 )
    3557             :                             {
    3558             :                                 // Must be alternating number/string, only
    3559             :                                 // strip within a reference.
    3560           0 :                                 nRefs--;
    3561           0 :                                 nStrip++;
    3562             :                             }
    3563             :                             else
    3564             :                             {
    3565           0 :                                 if ( !aSym.isEmpty() && !aSym.endsWith(":"))
    3566           0 :                                     aSym += ":";
    3567           0 :                                 nStrip = 0;
    3568             :                             }
    3569           0 :                             bLastAlp = !bNextNum;
    3570             :                         }
    3571             :                         else
    3572             :                         {   // ::
    3573           0 :                             nRefs--;
    3574           0 :                             if ( nLen1 )
    3575             :                             {   // B10::C10 ? append ':' on next round
    3576           0 :                                 if ( !bLastAlp && !CharClass::isAsciiNumeric( aTmp1 ) )
    3577           0 :                                     nStrip++;
    3578             :                             }
    3579             :                         }
    3580           0 :                         aTmp1 = aTmp2;
    3581           0 :                         nLen1 = nLen2;
    3582             :                     }
    3583             :                     else
    3584           0 :                         nRefs--;
    3585             :                 }
    3586           0 :                 aSymbol = aSym;
    3587           0 :                 aSymbol += aTmp1;
    3588             :             }
    3589             :             else
    3590           0 :                 bColons = false;
    3591           0 :             if ( nRefs && nRefs <= 2 )
    3592             :             {   // reference twisted? 4A => A4 etc.
    3593           0 :                 OUString aTab[2], aRef[2];
    3594           0 :                 const ScAddress::Details aDetails( pConv->meConv, aPos );
    3595           0 :                 if ( nRefs == 2 )
    3596             :                 {
    3597           0 :                     aRef[0] = aSymbol.getToken( 0, ':' );
    3598           0 :                     aRef[1] = aSymbol.getToken( 1, ':' );
    3599             :                 }
    3600             :                 else
    3601           0 :                     aRef[0] = aSymbol;
    3602             : 
    3603           0 :                 bool bChanged = false;
    3604           0 :                 bool bOk = true;
    3605           0 :                 sal_uInt16 nMask = SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW;
    3606           0 :                 for ( int j=0; j<nRefs; j++ )
    3607             :                 {
    3608           0 :                     sal_Int32 nTmp = 0;
    3609           0 :                     sal_Int32 nDotPos = -1;
    3610           0 :                     while ( (nTmp = aRef[j].indexOf( '.', nTmp )) != -1 )
    3611           0 :                         nDotPos = nTmp++;      // the last one counts
    3612           0 :                     if ( nDotPos != -1 )
    3613             :                     {
    3614           0 :                         aTab[j] = aRef[j].copy( 0, nDotPos + 1 );  // with '.'
    3615           0 :                         aRef[j] = aRef[j].copy( nDotPos + 1 );
    3616             :                     }
    3617           0 :                     OUString aOld( aRef[j] );
    3618           0 :                     OUString aStr2;
    3619           0 :                     const sal_Unicode* p = aRef[j].getStr();
    3620           0 :                     while ( *p && CharClass::isAsciiNumeric( OUString(*p) ) )
    3621           0 :                         aStr2 += OUString(*p++);
    3622           0 :                     aRef[j] = OUString( p );
    3623           0 :                     aRef[j] += aStr2;
    3624           0 :                     if ( bColons || aRef[j] != aOld )
    3625             :                     {
    3626           0 :                         bChanged = true;
    3627           0 :                         ScAddress aAdr;
    3628           0 :                         bOk &= ((aAdr.Parse( aRef[j], pDoc, aDetails ) & nMask) == nMask);
    3629             :                     }
    3630           0 :                 }
    3631           0 :                 if ( bChanged && bOk )
    3632             :                 {
    3633           0 :                     aCorrectedSymbol = aDoc;
    3634           0 :                     aCorrectedSymbol += aTab[0];
    3635           0 :                     aCorrectedSymbol += aRef[0];
    3636           0 :                     if ( nRefs == 2 )
    3637             :                     {
    3638           0 :                         aCorrectedSymbol += ":";
    3639           0 :                         aCorrectedSymbol += aTab[1];
    3640           0 :                         aCorrectedSymbol += aRef[1];
    3641             :                     }
    3642           0 :                     bCorrected = true;
    3643           0 :                 }
    3644           0 :             }
    3645             :         }
    3646             :     }
    3647           0 : }
    3648             : 
    3649        9834 : static inline bool lcl_UpperAsciiOrI18n( OUString& rUpper, const OUString& rOrg, FormulaGrammar::Grammar eGrammar )
    3650             : {
    3651        9834 :     if (FormulaGrammar::isODFF( eGrammar ))
    3652             :     {
    3653             :         // ODFF has a defined set of English function names, avoid i18n
    3654             :         // overhead.
    3655        3809 :         rUpper = rOrg.toAsciiUpperCase();
    3656        3809 :         return true;
    3657             :     }
    3658             :     else
    3659             :     {
    3660        6025 :         rUpper = ScGlobal::pCharClass->uppercase(rOrg);
    3661        6025 :         return false;
    3662             :     }
    3663             : }
    3664             : 
    3665       30809 : bool ScCompiler::NextNewToken( bool bInArray )
    3666             : {
    3667       30809 :     bool bAllowBooleans = bInArray;
    3668       30809 :     sal_Int32 nSpaces = NextSymbol(bInArray);
    3669             : 
    3670       30809 :     if (!cSymbol[0])
    3671        6906 :         return false;
    3672             : 
    3673       23903 :     if( nSpaces )
    3674             :     {
    3675         451 :         ScRawToken aToken;
    3676         451 :         aToken.SetOpCode( ocSpaces );
    3677         451 :         aToken.sbyte.cByte = (sal_uInt8) ( nSpaces > 255 ? 255 : nSpaces );
    3678         451 :         if( !static_cast<ScTokenArray*>(pArr)->AddRawToken( aToken ) )
    3679             :         {
    3680           0 :             SetError(errCodeOverflow);
    3681           0 :             return false;
    3682         451 :         }
    3683             :     }
    3684             : 
    3685             :     // Short cut for references when reading ODF to speedup things.
    3686       23903 :     if (mnPredetectedReference)
    3687             :     {
    3688         789 :         OUString aStr( cSymbol);
    3689             :         bool bInvalidExternalNameRange;
    3690         789 :         if (!IsPredetectedReference( aStr) && !IsExternalNamedRange( aStr, bInvalidExternalNameRange ))
    3691             :         {
    3692             :             /* TODO: it would be nice to generate a #REF! error here, which
    3693             :              * would need an ocBad token with additional error value.
    3694             :              * FormulaErrorToken wouldn't do because we want to preserve the
    3695             :              * original string containing partial valid address
    3696             :              * information if not ODFF (in that case it was already handled).
    3697             :              * */
    3698           0 :             svl::SharedString aSS = pDoc->GetSharedStringPool().intern(aStr);
    3699           0 :             maRawToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    3700           0 :             maRawToken.NewOpCode( ocBad );
    3701             :         }
    3702         789 :         return true;
    3703             :     }
    3704             : 
    3705       23114 :     if ( (cSymbol[0] == '#' || cSymbol[0] == '$') && cSymbol[1] == 0 &&
    3706           0 :             !bAutoCorrect )
    3707             :     {   // special case to speed up broken [$]#REF documents
    3708             :         /* FIXME: ISERROR(#REF!) would be valid and true and the formula to
    3709             :          * be processed as usual. That would need some special treatment,
    3710             :          * also in NextSymbol() because of possible combinations of
    3711             :          * #REF!.#REF!#REF! parts. In case of reading ODF that is all
    3712             :          * handled by IsPredetectedReference(), this case here remains for
    3713             :          * manual/API input. */
    3714           0 :         OUString aBad( aFormula.copy( nSrcPos-1 ) );
    3715           0 :         eLastOp = pArr->AddBad( aBad )->GetOpCode();
    3716           0 :         return false;
    3717             :     }
    3718             : 
    3719       23114 :     if( IsString() )
    3720         776 :         return true;
    3721             : 
    3722             :     bool bMayBeFuncName;
    3723             :     bool bAsciiNonAlnum;    // operators, separators, ...
    3724       22338 :     if ( cSymbol[0] < 128 )
    3725             :     {
    3726       22336 :         bMayBeFuncName = rtl::isAsciiAlpha( cSymbol[0] );
    3727       22336 :         if (!bMayBeFuncName && (cSymbol[0] == '_' && cSymbol[1] == '_') )
    3728             :         {
    3729           0 :             SvtMiscOptions aOpt;
    3730           0 :             bMayBeFuncName = aOpt.IsExperimentalMode();
    3731             :         }
    3732             : 
    3733       22336 :         bAsciiNonAlnum = !bMayBeFuncName && !rtl::isAsciiDigit( cSymbol[0] );
    3734             :     }
    3735             :     else
    3736             :     {
    3737           2 :         OUString aTmpStr( cSymbol[0] );
    3738           2 :         bMayBeFuncName = ScGlobal::pCharClass->isLetter( aTmpStr, 0 );
    3739           2 :         bAsciiNonAlnum = false;
    3740             :     }
    3741       22338 :     if (bAsciiNonAlnum && cSymbol[1] == 0)
    3742             :     {
    3743             :         // Shortcut for operators and separators that need no further checks or upper.
    3744       10100 :         if (IsOpCode( OUString( cSymbol), bInArray ))
    3745       10099 :             return true;
    3746             :     }
    3747       12239 :     if ( bMayBeFuncName )
    3748             :     {
    3749             :         // a function name must be followed by a parenthesis
    3750        4773 :         const sal_Unicode* p = aFormula.getStr() + nSrcPos;
    3751        9560 :         while( *p == ' ' )
    3752          14 :             p++;
    3753        4773 :         bMayBeFuncName = ( *p == '(' );
    3754             :     }
    3755             : 
    3756             :     // Italian ARCTAN.2 resulted in #REF! => IsOpcode() before
    3757             :     // IsReference().
    3758             : 
    3759       12239 :     OUString aUpper;
    3760             : 
    3761          16 :     do
    3762             :     {
    3763       12239 :         const OUString aOrg( cSymbol );
    3764             : 
    3765             :         // Check for TableRef column specifier first, it may be anything.
    3766       12239 :         if (cSymbol[0] != '#' && !maTableRefs.empty() && maTableRefs.back().mnLevel)
    3767             :         {
    3768           0 :             if (IsTableRefColumn( aOrg ))
    3769           0 :                 return true;
    3770             :             // Do not attempt to resolve as any other name.
    3771           0 :             aUpper = aOrg;  // for ocBad
    3772           0 :             break;          // do; create ocBad token or set error.
    3773             :         }
    3774             : 
    3775       12239 :         mbRewind = false;
    3776       12239 :         aUpper.clear();
    3777       12239 :         bool bAsciiUpper = false;
    3778             : 
    3779       12239 :         if (bAsciiNonAlnum)
    3780             :         {
    3781        4159 :             bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
    3782        4159 :             if (cSymbol[0] == '#')
    3783             :             {
    3784             :                 // Check for TableRef item specifiers first.
    3785          23 :                 if (!maTableRefs.empty() && maTableRefs.back().mnLevel == 2)
    3786             :                 {
    3787           0 :                     if (IsTableRefItem( aUpper ))
    3788           0 :                         return true;
    3789             :                 }
    3790             : 
    3791             :                 // This can be only an error constant, if any.
    3792          23 :                 if (IsErrorConstant( aUpper))
    3793          23 :                     return true;
    3794             : 
    3795           0 :                 break;  // do; create ocBad token or set error.
    3796             :             }
    3797        4136 :             if (IsOpCode( aUpper, bInArray ))
    3798         533 :                 return true;
    3799             :         }
    3800             : 
    3801       11683 :         if (bMayBeFuncName)
    3802             :         {
    3803        2240 :             if (aUpper.isEmpty())
    3804        2240 :                 bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
    3805        2240 :             if (IsOpCode( aUpper, bInArray ))
    3806        2239 :                 return true;
    3807             :         }
    3808             : 
    3809             :         // Column 'DM' ("Deutsche Mark", German currency) couldn't be
    3810             :         // referred => IsReference() before IsValue().
    3811             :         // Preserve case of file names in external references.
    3812        9444 :         if (IsReference( aOrg ))
    3813             :         {
    3814        6006 :             if (mbRewind)   // Range operator, but no direct reference.
    3815           0 :                 continue;   // do; up to range operator.
    3816             :             // If a syntactically correct reference was recognized but invalid
    3817             :             // e.g. because of non-existing sheet name => entire reference
    3818             :             // ocBad to preserve input instead of #REF!.A1
    3819        6006 :             if (!maRawToken.IsValidReference())
    3820             :             {
    3821           0 :                 aUpper = aOrg;          // ensure for ocBad
    3822           0 :                 break;                  // do; create ocBad token or set error.
    3823             :             }
    3824        6006 :             return true;
    3825             :         }
    3826             : 
    3827        3438 :         if (aUpper.isEmpty())
    3828        3435 :             bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
    3829             : 
    3830             :         // IsBoolean() before IsValue() to catch inline bools without the kludge
    3831             :         //    for inline arrays.
    3832        3438 :         if (bAllowBooleans && IsBoolean( aUpper ))
    3833           0 :             return true;
    3834             : 
    3835        3438 :         if (IsValue( aUpper ))
    3836        3307 :             return true;
    3837             : 
    3838             :         // User defined names and such do need i18n upper also in ODF.
    3839         131 :         if (bAsciiUpper)
    3840          78 :             aUpper = ScGlobal::pCharClass->uppercase( aOrg );
    3841             : 
    3842         131 :         if (IsNamedRange( aUpper ))
    3843         101 :             return true;
    3844             :         // Preserve case of file names in external references.
    3845             :         bool bInvalidExternalNameRange;
    3846          30 :         if (IsExternalNamedRange( aOrg, bInvalidExternalNameRange ))
    3847           0 :             return true;
    3848             :         // Preserve case of file names in external references even when range
    3849             :         // is not valid and previous check failed tdf#89330
    3850          30 :         if (bInvalidExternalNameRange)
    3851             :         {
    3852             :             // add ocBad but do not lowercase
    3853           1 :             svl::SharedString aSS = pDoc->GetSharedStringPool().intern(aOrg);
    3854           1 :             maRawToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    3855           1 :             maRawToken.NewOpCode( ocBad );
    3856           1 :             return true;
    3857             :         }
    3858          29 :         if (IsDBRange( aUpper ))
    3859          12 :             return true;
    3860             :         // If followed by '(' (with or without space inbetween) it can not be a
    3861             :         // column/row label. Prevent arbitrary content detection.
    3862          17 :         if (!bMayBeFuncName && IsColRowName( aUpper ))
    3863           0 :             return true;
    3864          17 :         if (bMayBeFuncName && IsMacro( aUpper ))
    3865           1 :             return true;
    3866          16 :         if (bMayBeFuncName && IsOpCode2( aUpper ))
    3867           0 :             return true;
    3868             : 
    3869             :     } while (mbRewind);
    3870             : 
    3871          16 :     if ( meExtendedErrorDetection != EXTENDED_ERROR_DETECTION_NONE )
    3872             :     {
    3873             :         // set an error
    3874           1 :         SetError( errNoName );
    3875           1 :         if (meExtendedErrorDetection == EXTENDED_ERROR_DETECTION_NAME_BREAK)
    3876           0 :             return false;   // end compilation
    3877             :     }
    3878             : 
    3879             :     // Provide single token information and continue. Do not set an error, that
    3880             :     // would prematurely end compilation. Simple unknown names are handled by
    3881             :     // the interpreter.
    3882          16 :     aUpper = ScGlobal::pCharClass->lowercase( aUpper );
    3883          32 :     svl::SharedString aSS = pDoc->GetSharedStringPool().intern(aUpper);
    3884          16 :     maRawToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    3885          16 :     maRawToken.NewOpCode( ocBad );
    3886          16 :     if ( bAutoCorrect )
    3887           0 :         AutoCorrectParsedSymbol();
    3888       12255 :     return true;
    3889             : }
    3890             : 
    3891        1550 : void ScCompiler::CreateStringFromXMLTokenArray( OUString& rFormula, OUString& rFormulaNmsp )
    3892             : {
    3893        1550 :     bool bExternal = GetGrammar() == FormulaGrammar::GRAM_EXTERNAL;
    3894        1550 :     sal_uInt16 nExpectedCount = bExternal ? 2 : 1;
    3895             :     OSL_ENSURE( pArr->GetLen() == nExpectedCount, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" );
    3896        1550 :     if( pArr->GetLen() == nExpectedCount )
    3897             :     {
    3898        1550 :         FormulaToken** ppTokens = pArr->GetArray();
    3899             :         // string tokens expected, GetString() will assert if token type is wrong
    3900        1550 :         rFormula = ppTokens[0]->GetString().getString();
    3901        1550 :         if( bExternal )
    3902           0 :             rFormulaNmsp = ppTokens[1]->GetString().getString();
    3903             :     }
    3904        1550 : }
    3905             : 
    3906             : namespace {
    3907             : 
    3908          83 : class ExternalFileInserter : std::unary_function<sal_uInt16, void>
    3909             : {
    3910             :     ScAddress maPos;
    3911             :     ScExternalRefManager& mrRefMgr;
    3912             : public:
    3913          83 :     ExternalFileInserter(const ScAddress& rPos, ScExternalRefManager& rRefMgr) :
    3914          83 :         maPos(rPos), mrRefMgr(rRefMgr) {}
    3915             : 
    3916          83 :     void operator() (sal_uInt16 nFileId) const
    3917             :     {
    3918          83 :         mrRefMgr.insertRefCell(nFileId, maPos);
    3919          83 :     }
    3920             : };
    3921             : 
    3922             : }
    3923             : 
    3924        6906 : ScTokenArray* ScCompiler::CompileString( const OUString& rFormula )
    3925             : {
    3926             :     OSL_ENSURE( meGrammar != FormulaGrammar::GRAM_EXTERNAL, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" );
    3927        6906 :     if( meGrammar == FormulaGrammar::GRAM_EXTERNAL )
    3928           0 :         SetGrammar( FormulaGrammar::GRAM_PODF );
    3929             : 
    3930        6906 :     ScTokenArray aArr;
    3931        6906 :     pArr = &aArr;
    3932        6906 :     aFormula = comphelper::string::strip(rFormula, ' ');
    3933             : 
    3934        6906 :     nSrcPos = 0;
    3935        6906 :     bCorrected = false;
    3936        6906 :     if ( bAutoCorrect )
    3937             :     {
    3938           0 :         aCorrectedFormula.clear();
    3939           0 :         aCorrectedSymbol.clear();
    3940             :     }
    3941        6906 :     sal_uInt8 nForced = 0;   // ==formula forces recalc even if cell is not visible
    3942        6906 :     if( nSrcPos < aFormula.getLength() && aFormula[nSrcPos] == '=' )
    3943             :     {
    3944        2614 :         nSrcPos++;
    3945        2614 :         nForced++;
    3946        2614 :         if ( bAutoCorrect )
    3947           0 :             aCorrectedFormula += "=";
    3948             :     }
    3949        6906 :     if( nSrcPos < aFormula.getLength() && aFormula[nSrcPos] == '=' )
    3950             :     {
    3951           0 :         nSrcPos++;
    3952           0 :         nForced++;
    3953           0 :         if ( bAutoCorrect )
    3954           0 :             aCorrectedFormula += "=";
    3955             :     }
    3956             :     struct FunctionStack
    3957             :     {
    3958             :         OpCode  eOp;
    3959             :         short   nSep;
    3960             :     };
    3961             :     // FunctionStack only used if PODF or OOXML!
    3962        6906 :     bool bPODF = FormulaGrammar::isPODF( meGrammar);
    3963        6906 :     bool bOOXML = FormulaGrammar::isOOXML( meGrammar);
    3964        6906 :     bool bUseFunctionStack = (bPODF || bOOXML);
    3965        6906 :     const size_t nAlloc = 512;
    3966             :     FunctionStack aFuncs[ nAlloc ];
    3967         899 :     FunctionStack* pFunctionStack = (bUseFunctionStack && static_cast<size_t>(rFormula.getLength()) > nAlloc ?
    3968        6906 :          new FunctionStack[rFormula.getLength()] : &aFuncs[0]);
    3969        6906 :     pFunctionStack[0].eOp = ocNone;
    3970        6906 :     pFunctionStack[0].nSep = 0;
    3971        6906 :     size_t nFunction = 0;
    3972        6906 :     short nBrackets = 0;
    3973        6906 :     bool bInArray = false;
    3974        6906 :     eLastOp = ocOpen;
    3975       37715 :     while( NextNewToken( bInArray ) )
    3976             :     {
    3977       23903 :         const OpCode eOp = maRawToken.GetOpCode();
    3978       23903 :         if (eOp == ocSkip)
    3979           0 :             continue;
    3980             : 
    3981       23903 :         switch (eOp)
    3982             :         {
    3983             :             case ocOpen:
    3984             :             {
    3985        2790 :                 ++nBrackets;
    3986        2790 :                 if (bUseFunctionStack)
    3987             :                 {
    3988         759 :                     ++nFunction;
    3989         759 :                     pFunctionStack[ nFunction ].eOp = eLastOp;
    3990         759 :                     pFunctionStack[ nFunction ].nSep = 0;
    3991             :                 }
    3992             :             }
    3993        2790 :             break;
    3994             :             case ocClose:
    3995             :             {
    3996        2774 :                 if( !nBrackets )
    3997             :                 {
    3998           0 :                     SetError( errPairExpected );
    3999           0 :                     if ( bAutoCorrect )
    4000             :                     {
    4001           0 :                         bCorrected = true;
    4002           0 :                         aCorrectedSymbol.clear();
    4003             :                     }
    4004             :                 }
    4005             :                 else
    4006        2774 :                     nBrackets--;
    4007        2774 :                 if (bUseFunctionStack && nFunction)
    4008         751 :                     --nFunction;
    4009             :             }
    4010        2774 :             break;
    4011             :             case ocSep:
    4012             :             {
    4013        3445 :                 if (bUseFunctionStack)
    4014        1364 :                     ++pFunctionStack[ nFunction ].nSep;
    4015             :             }
    4016        3445 :             break;
    4017             :             case ocArrayOpen:
    4018             :             {
    4019          71 :                 if( bInArray )
    4020           0 :                     SetError( errNestedArray );
    4021             :                 else
    4022          71 :                     bInArray = true;
    4023             :                 // Don't count following column separator as parameter separator.
    4024          71 :                 if (bUseFunctionStack)
    4025             :                 {
    4026           1 :                     ++nFunction;
    4027           1 :                     pFunctionStack[ nFunction ].eOp = eOp;
    4028           1 :                     pFunctionStack[ nFunction ].nSep = 0;
    4029             :                 }
    4030             :             }
    4031          71 :             break;
    4032             :             case ocArrayClose:
    4033             :             {
    4034          71 :                 if( bInArray )
    4035             :                 {
    4036          71 :                     bInArray = false;
    4037             :                 }
    4038             :                 else
    4039             :                 {
    4040           0 :                     SetError( errPairExpected );
    4041           0 :                     if ( bAutoCorrect )
    4042             :                     {
    4043           0 :                         bCorrected = true;
    4044           0 :                         aCorrectedSymbol.clear();
    4045             :                     }
    4046             :                 }
    4047          71 :                 if (bUseFunctionStack && nFunction)
    4048           1 :                     --nFunction;
    4049             :             }
    4050          71 :             break;
    4051             :             case ocTableRefOpen:
    4052             :             {
    4053             :                 // Don't count following item separator as parameter separator.
    4054           0 :                 if (bUseFunctionStack)
    4055             :                 {
    4056           0 :                     ++nFunction;
    4057           0 :                     pFunctionStack[ nFunction ].eOp = eOp;
    4058           0 :                     pFunctionStack[ nFunction ].nSep = 0;
    4059             :                 }
    4060             :             }
    4061           0 :             break;
    4062             :             case ocTableRefClose:
    4063             :             {
    4064           0 :                 if (bUseFunctionStack && nFunction)
    4065           0 :                     --nFunction;
    4066             :             }
    4067           0 :             break;
    4068             :             default:
    4069       14752 :             break;
    4070             :         }
    4071       44361 :         if( (eLastOp == ocSep ||
    4072       40784 :              eLastOp == ocArrayRowSep ||
    4073       40610 :              eLastOp == ocArrayColSep ||
    4074       23974 :              eLastOp == ocArrayOpen) &&
    4075        3682 :             (eOp == ocSep ||
    4076        3678 :              eOp == ocClose ||
    4077        3678 :              eOp == ocArrayRowSep ||
    4078        3678 :              eOp == ocArrayColSep ||
    4079             :              eOp == ocArrayClose) )
    4080             :         {
    4081             :             // FIXME: should we check for known functions with optional empty
    4082             :             // args so the correction dialog can do better?
    4083          12 :             if ( !static_cast<ScTokenArray*>(pArr)->Add( new FormulaMissingToken ) )
    4084             :             {
    4085           0 :                 SetError(errCodeOverflow); break;
    4086             :             }
    4087             :         }
    4088       23903 :         if (bOOXML)
    4089             :         {
    4090             :             // Append a parameter for FLOOR and WEEKNUM, all 1.0
    4091             :             // Function is already closed, parameter count is nSep+1
    4092        5733 :             size_t nFunc = nFunction + 1;
    4093        6444 :             if (eOp == ocClose && (
    4094         711 :                     (pFunctionStack[ nFunc ].eOp == ocFloor &&  // 3rd Excel mode
    4095         711 :                      pFunctionStack[ nFunc ].nSep == 1) ||
    4096         711 :                     (pFunctionStack[ nFunc ].eOp == ocWeek &&   // 2nd week start
    4097           0 :                      pFunctionStack[ nFunc ].nSep == 0)))
    4098             :             {
    4099           0 :                 if (    !static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep, ocSep)) ||
    4100           0 :                         !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0)))
    4101             :                 {
    4102           0 :                     SetError(errCodeOverflow); break;
    4103             :                 }
    4104             :             }
    4105             :         }
    4106       18170 :         else if (bPODF)
    4107             :         {
    4108             :             /* TODO: for now this is the only PODF adapter. If there were more,
    4109             :              * factor this out. */
    4110             :             // Insert ADDRESS() new empty parameter 4 if there is a 4th, now to be 5th.
    4111         519 :             if (eOp == ocSep &&
    4112          21 :                     pFunctionStack[ nFunction ].eOp == ocAddress &&
    4113           0 :                     pFunctionStack[ nFunction ].nSep == 3)
    4114             :             {
    4115           0 :                 if (    !static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep, ocSep)) ||
    4116           0 :                         !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0)))
    4117             :                 {
    4118           0 :                     SetError(errCodeOverflow); break;
    4119             :                 }
    4120           0 :                 ++pFunctionStack[ nFunction ].nSep;
    4121             :             }
    4122             :         }
    4123       23903 :         FormulaToken* pNewToken = static_cast<ScTokenArray*>(pArr)->Add( maRawToken.CreateToken());
    4124       23903 :         if (!pNewToken)
    4125             :         {
    4126           0 :             SetError(errCodeOverflow);
    4127           0 :             break;
    4128             :         }
    4129       23903 :         else if (eLastOp == ocRange && pNewToken->GetOpCode() == ocPush && pNewToken->GetType() == svSingleRef)
    4130             :         {
    4131           0 :             static_cast<ScTokenArray*>(pArr)->MergeRangeReference( aPos);
    4132             :         }
    4133       23903 :         else if (eLastOp == ocDBArea && pNewToken->GetOpCode() == ocTableRefOpen)
    4134             :         {
    4135           0 :             sal_uInt16 nIdx = pArr->GetLen() - 1;
    4136           0 :             const FormulaToken* pPrev = pArr->PeekPrev( nIdx);
    4137           0 :             if (pPrev && pPrev->GetOpCode() == ocDBArea)
    4138             :             {
    4139           0 :                 FormulaToken* pTableRefToken = new ScTableRefToken( pPrev->GetIndex(), ScTableRefToken::TABLE);
    4140           0 :                 maTableRefs.push_back( TableRefEntry( pTableRefToken));
    4141             :                 // pPrev may be dead hereafter.
    4142           0 :                 static_cast<ScTokenArray*>(pArr)->ReplaceToken( 1, pTableRefToken);
    4143             :             }
    4144             :         }
    4145       23903 :         switch (eOp)
    4146             :         {
    4147             :             case ocTableRefOpen:
    4148             :                 SAL_WARN_IF( maTableRefs.empty(), "sc.core", "ocTableRefOpen without TableRefEntry");
    4149           0 :                 if (maTableRefs.empty())
    4150           0 :                     SetError(errPair);
    4151             :                 else
    4152           0 :                     ++maTableRefs.back().mnLevel;
    4153           0 :                 break;
    4154             :             case ocTableRefClose:
    4155             :                 SAL_WARN_IF( maTableRefs.empty(), "sc.core", "ocTableRefClose without TableRefEntry");
    4156           0 :                 if (maTableRefs.empty())
    4157           0 :                     SetError(errPair);
    4158             :                 else
    4159             :                 {
    4160           0 :                     if (--maTableRefs.back().mnLevel == 0)
    4161           0 :                         maTableRefs.pop_back();
    4162             :                 }
    4163           0 :                 break;
    4164             :             default:
    4165       23903 :                 break;
    4166             :         }
    4167       23903 :         eLastOp = maRawToken.GetOpCode();
    4168       23903 :         if ( bAutoCorrect )
    4169           0 :             aCorrectedFormula += aCorrectedSymbol;
    4170             :     }
    4171        6906 :     if ( mbCloseBrackets )
    4172             :     {
    4173        6906 :         if( bInArray )
    4174             :         {
    4175           0 :             FormulaByteToken aToken( ocArrayClose );
    4176           0 :             if( !pArr->AddToken( aToken ) )
    4177             :             {
    4178           0 :                 SetError(errCodeOverflow);
    4179             :             }
    4180           0 :             else if ( bAutoCorrect )
    4181           0 :                 aCorrectedFormula += mxSymbols->getSymbol(ocArrayClose);
    4182             :         }
    4183             : 
    4184        6906 :         FormulaByteToken aToken( ocClose );
    4185       13828 :         while( nBrackets-- )
    4186             :         {
    4187          16 :             if( !pArr->AddToken( aToken ) )
    4188             :             {
    4189           0 :                 SetError(errCodeOverflow); break;
    4190             :             }
    4191          16 :             if ( bAutoCorrect )
    4192           0 :                 aCorrectedFormula += mxSymbols->getSymbol(ocClose);
    4193        6906 :         }
    4194             :     }
    4195        6906 :     if ( nForced >= 2 )
    4196           0 :         pArr->SetRecalcModeForced();
    4197             : 
    4198        6906 :     if (pFunctionStack != &aFuncs[0])
    4199           0 :         delete [] pFunctionStack;
    4200             : 
    4201             :     // remember pArr, in case a subsequent CompileTokenArray() is executed.
    4202        6906 :     ScTokenArray* pNew = new ScTokenArray( aArr );
    4203        6906 :     pNew->GenHash();
    4204        6906 :     pArr = pNew;
    4205             : 
    4206        6906 :     if (!maExternalFiles.empty())
    4207             :     {
    4208             :         // Remove duplicates, and register all external files found in this cell.
    4209          83 :         std::sort(maExternalFiles.begin(), maExternalFiles.end());
    4210          83 :         std::vector<sal_uInt16>::iterator itEnd = std::unique(maExternalFiles.begin(), maExternalFiles.end());
    4211          83 :         std::for_each(maExternalFiles.begin(), itEnd, ExternalFileInserter(aPos, *pDoc->GetExternalRefManager()));
    4212          83 :         maExternalFiles.erase(itEnd, maExternalFiles.end());
    4213             :     }
    4214             : 
    4215        6906 :     return pNew;
    4216             : }
    4217             : 
    4218        1679 : ScTokenArray* ScCompiler::CompileString( const OUString& rFormula, const OUString& rFormulaNmsp )
    4219             : {
    4220             :     OSL_ENSURE( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL) || rFormulaNmsp.isEmpty(),
    4221             :         "ScCompiler::CompileString - unexpected formula namespace for internal grammar" );
    4222        1679 :     if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL ) try
    4223             :     {
    4224           0 :         ScFormulaParserPool& rParserPool = pDoc->GetFormulaParserPool();
    4225           0 :         uno::Reference< sheet::XFormulaParser > xParser( rParserPool.getFormulaParser( rFormulaNmsp ), uno::UNO_SET_THROW );
    4226           0 :         table::CellAddress aReferencePos;
    4227           0 :         ScUnoConversion::FillApiAddress( aReferencePos, aPos );
    4228           0 :         uno::Sequence< sheet::FormulaToken > aTokenSeq = xParser->parseFormula( rFormula, aReferencePos );
    4229           0 :         ScTokenArray aTokenArray;
    4230           0 :         if( ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, aTokenSeq ) )
    4231             :         {
    4232             :             // remember pArr, in case a subsequent CompileTokenArray() is executed.
    4233           0 :             ScTokenArray* pNew = new ScTokenArray( aTokenArray );
    4234           0 :             pArr = pNew;
    4235           0 :             return pNew;
    4236           0 :         }
    4237             :     }
    4238           0 :     catch( uno::Exception& )
    4239             :     {
    4240             :     }
    4241             :     // no success - fallback to some internal grammar and hope the best
    4242        1679 :     return CompileString( rFormula );
    4243             : }
    4244             : 
    4245         479 : ScRangeData* ScCompiler::GetRangeData( const FormulaToken& rToken ) const
    4246             : {
    4247         479 :     ScRangeData* pRangeData = NULL;
    4248         479 :     bool bGlobal = rToken.IsGlobal();
    4249         479 :     if (bGlobal)
    4250             :         // global named range.
    4251         388 :         pRangeData = pDoc->GetRangeName()->findByIndex( rToken.GetIndex());
    4252             :     else
    4253             :     {
    4254             :         // sheet local named range.
    4255          91 :         const ScRangeName* pRN = pDoc->GetRangeName( aPos.Tab());
    4256          91 :         if (pRN)
    4257          91 :             pRangeData = pRN->findByIndex( rToken.GetIndex());
    4258             :     }
    4259         479 :     return pRangeData;
    4260             : }
    4261             : 
    4262         431 : bool ScCompiler::HandleRange()
    4263             : {
    4264         431 :     const ScRangeData* pRangeData = GetRangeData( *mpToken);
    4265         431 :     if (pRangeData)
    4266             :     {
    4267         431 :         sal_uInt16 nErr = pRangeData->GetErrCode();
    4268         431 :         if( nErr )
    4269           0 :             SetError( errNoName );
    4270         431 :         else if (mbJumpCommandReorder)
    4271             :         {
    4272             :             ScTokenArray* pNew;
    4273             :             // put named formula into parentheses.
    4274             :             // But only if there aren't any yet, parenthetical
    4275             :             // ocSep doesn't work, e.g. SUM((...;...))
    4276             :             // or if not directly between ocSep/parenthesis,
    4277             :             // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes,
    4278             :             // in short: if it isn't a self-contained expression.
    4279         431 :             FormulaToken* p1 = pArr->PeekPrevNoSpaces();
    4280         431 :             FormulaToken* p2 = pArr->PeekNextNoSpaces();
    4281         431 :             OpCode eOp1 = (p1 ? p1->GetOpCode() : static_cast<OpCode>( ocSep ) );
    4282         431 :             OpCode eOp2 = (p2 ? p2->GetOpCode() : static_cast<OpCode>( ocSep ) );
    4283         431 :             bool bBorder1 = (eOp1 == ocSep || eOp1 == ocOpen);
    4284         431 :             bool bBorder2 = (eOp2 == ocSep || eOp2 == ocClose);
    4285         431 :             bool bAddPair = !(bBorder1 && bBorder2);
    4286         431 :             if ( bAddPair )
    4287             :             {
    4288          28 :                 pNew = new ScTokenArray();
    4289          28 :                 pNew->AddOpCode( ocClose );
    4290          28 :                 PushTokenArray( pNew, true );
    4291          28 :                 pNew->Reset();
    4292             :             }
    4293         431 :             pNew = pRangeData->GetCode()->Clone();
    4294         431 :             PushTokenArray( pNew, true );
    4295         431 :             if( pRangeData->HasReferences() )
    4296             :             {
    4297         425 :                 SetRelNameReference();
    4298         425 :                 MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
    4299             :             }
    4300         431 :             pNew->Reset();
    4301         431 :             if ( bAddPair )
    4302             :             {
    4303          28 :                 pNew = new ScTokenArray();
    4304          28 :                 pNew->AddOpCode( ocOpen );
    4305          28 :                 PushTokenArray( pNew, true );
    4306          28 :                 pNew->Reset();
    4307             :             }
    4308         431 :             return GetToken();
    4309             :         }
    4310             :     }
    4311             :     else
    4312           0 :         SetError(errNoName);
    4313           0 :     return true;
    4314             : }
    4315             : 
    4316         199 : bool ScCompiler::HandleExternalReference(const FormulaToken& _aToken)
    4317             : {
    4318             :     // Handle external range names.
    4319         199 :     switch (_aToken.GetType())
    4320             :     {
    4321             :         case svExternalSingleRef:
    4322             :         case svExternalDoubleRef:
    4323         199 :             break;
    4324             :         case svExternalName:
    4325             :         {
    4326           0 :             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    4327           0 :             const OUString* pFile = pRefMgr->getExternalFileName(_aToken.GetIndex());
    4328           0 :             if (!pFile)
    4329             :             {
    4330           0 :                 SetError(errNoName);
    4331           0 :                 return true;
    4332             :             }
    4333             : 
    4334           0 :             OUString aName = _aToken.GetString().getString();
    4335             :             ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getRangeNameTokens(
    4336           0 :                 _aToken.GetIndex(), aName, &aPos);
    4337             : 
    4338           0 :             if (!xNew)
    4339             :             {
    4340           0 :                 SetError(errNoName);
    4341           0 :                 return true;
    4342             :             }
    4343             : 
    4344           0 :             ScTokenArray* pNew = xNew->Clone();
    4345           0 :             PushTokenArray( pNew, true);
    4346           0 :             if (pNew->GetNextReference() != NULL)
    4347             :             {
    4348           0 :                 SetRelNameReference();
    4349           0 :                 MoveRelWrap(MAXCOL, MAXROW);
    4350             :             }
    4351           0 :             pNew->Reset();
    4352           0 :             return GetToken();
    4353             :         }
    4354             :         default:
    4355             :             OSL_FAIL("Wrong type for external reference!");
    4356           0 :             return false;
    4357             :     }
    4358         199 :     return true;
    4359             : }
    4360             : 
    4361             : // reference of named range with relative references
    4362             : 
    4363         425 : void ScCompiler::SetRelNameReference()
    4364             : {
    4365         425 :     pArr->Reset();
    4366         850 :     for( formula::FormulaToken* t = pArr->GetNextReference(); t;
    4367         425 :                   t = pArr->GetNextReference() )
    4368             :     {
    4369         425 :         ScSingleRefData& rRef1 = *t->GetSingleRef();
    4370         425 :         if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
    4371          19 :             rRef1.SetRelName( true );
    4372         425 :         if ( t->GetType() == svDoubleRef )
    4373             :         {
    4374          80 :             ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
    4375          80 :             if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
    4376          13 :                 rRef2.SetRelName( true );
    4377             :         }
    4378             :     }
    4379         425 : }
    4380             : 
    4381             : // Wrap-adjust relative references of a RangeName to current position,
    4382             : // don't call for other token arrays!
    4383         446 : void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow )
    4384             : {
    4385         446 :     pArr->Reset();
    4386         892 :     for( formula::FormulaToken* t = pArr->GetNextReference(); t;
    4387         446 :                   t = pArr->GetNextReference() )
    4388             :     {
    4389         446 :         if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
    4390         354 :             ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( *t->GetSingleRef() ).Ref() );
    4391             :         else
    4392          92 :             ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, *t->GetDoubleRef() );
    4393             :     }
    4394         446 : }
    4395             : 
    4396             : // Wrap-adjust relative references of a RangeName to current position,
    4397             : // don't call for other token arrays!
    4398         127 : void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos,
    4399             :                               SCCOL nMaxCol, SCROW nMaxRow )
    4400             : {
    4401         127 :     rArr.Reset();
    4402         461 :     for( formula::FormulaToken* t = rArr.GetNextReference(); t;
    4403         334 :                   t = rArr.GetNextReference() )
    4404             :     {
    4405         334 :         if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
    4406         250 :             ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( *t->GetSingleRef() ).Ref() );
    4407             :         else
    4408          84 :             ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, *t->GetDoubleRef() );
    4409             :     }
    4410         127 : }
    4411             : 
    4412        1679 : bool ScCompiler::IsCharFlagAllConventions(
    4413             :     OUString const & rStr, sal_Int32 nPos, sal_uLong nFlags, bool bTestLetterNumeric )
    4414             : {
    4415        1679 :     sal_Unicode c = rStr[ nPos ];
    4416        1679 :     sal_Unicode cLast = nPos > 0 ? rStr[ nPos-1 ] : 0;
    4417        1679 :     if (c < 128)
    4418             :     {
    4419       13432 :         for ( int nConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
    4420             :                 ++nConv < formula::FormulaGrammar::CONV_LAST; )
    4421             :         {
    4422       16939 :             if (pConventions[nConv] &&
    4423        6865 :                     ((pConventions[nConv]->getCharTableFlags(c, cLast) & nFlags) != nFlags))
    4424           0 :                 return false;
    4425             :             // convention not known => assume valid
    4426             :         }
    4427        1679 :         return true;
    4428             :     }
    4429           0 :     else if (bTestLetterNumeric)
    4430           0 :         return ScGlobal::pCharClass->isLetterNumeric( rStr, nPos );
    4431             :     else
    4432           0 :         return false;
    4433             : }
    4434             : 
    4435          56 : void ScCompiler::CreateStringFromExternal( OUStringBuffer& rBuffer, const FormulaToken* pTokenP ) const
    4436             : {
    4437          56 :     const FormulaToken* t = pTokenP;
    4438          56 :     sal_uInt16 nFileId = t->GetIndex();
    4439          56 :     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    4440          56 :     const OUString* pFileName = pRefMgr->getExternalFileName(nFileId);
    4441          56 :     if (!pFileName)
    4442          56 :         return;
    4443             : 
    4444          56 :     switch (t->GetType())
    4445             :     {
    4446             :         case svExternalName:
    4447           0 :             rBuffer.append(pConv->makeExternalNameStr( nFileId, *pFileName, t->GetString().getString()));
    4448           0 :         break;
    4449             :         case svExternalSingleRef:
    4450             :             pConv->makeExternalRefStr(
    4451          72 :                    rBuffer, GetPos(), nFileId, *pFileName, t->GetString().getString(),
    4452         108 :                    *t->GetSingleRef());
    4453          36 :         break;
    4454             :         case svExternalDoubleRef:
    4455             :         {
    4456          20 :             vector<OUString> aTabNames;
    4457          20 :             pRefMgr->getAllCachedTableNames(nFileId, aTabNames);
    4458             :             // No sheet names is a valid case if external sheets were not
    4459             :             // cached in this document and external document is not reachable,
    4460             :             // else not and worth to be investigated.
    4461             :             SAL_WARN_IF( aTabNames.empty(), "sc.core", "wrecked cache of external document? '" <<
    4462             :                     *pFileName << "' '" << t->GetString().getString() << "'");
    4463             : 
    4464             :             pConv->makeExternalRefStr(
    4465          40 :                 rBuffer, GetPos(), nFileId, *pFileName, aTabNames, t->GetString().getString(),
    4466          60 :                 *t->GetDoubleRef());
    4467             :         }
    4468          20 :         break;
    4469             :         default:
    4470             :             // warning, not error, otherwise we may end up with a never
    4471             :             // ending message box loop if this was the cursor cell to be redrawn.
    4472             :             OSL_FAIL("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef");
    4473             :     }
    4474             : }
    4475             : 
    4476           4 : void ScCompiler::CreateStringFromMatrix( OUStringBuffer& rBuffer, const FormulaToken* pTokenP ) const
    4477             : {
    4478           4 :     const ScMatrix* pMatrix = pTokenP->GetMatrix();
    4479             :     SCSIZE nC, nMaxC, nR, nMaxR;
    4480             : 
    4481           4 :     pMatrix->GetDimensions( nMaxC, nMaxR);
    4482             : 
    4483           4 :     rBuffer.append( mxSymbols->getSymbol(ocArrayOpen) );
    4484          12 :     for( nR = 0 ; nR < nMaxR ; nR++)
    4485             :     {
    4486           8 :         if( nR > 0)
    4487             :         {
    4488           4 :             rBuffer.append( mxSymbols->getSymbol(ocArrayRowSep) );
    4489             :         }
    4490             : 
    4491          20 :         for( nC = 0 ; nC < nMaxC ; nC++)
    4492             :         {
    4493          12 :             if( nC > 0)
    4494             :             {
    4495           4 :                 rBuffer.append( mxSymbols->getSymbol(ocArrayColSep) );
    4496             :             }
    4497             : 
    4498          12 :             if( pMatrix->IsValue( nC, nR ) )
    4499             :             {
    4500          12 :                 if (pMatrix->IsBoolean(nC, nR))
    4501           0 :                     AppendBoolean(rBuffer, pMatrix->GetDouble(nC, nR) != 0.0);
    4502             :                 else
    4503             :                 {
    4504          12 :                     sal_uInt16 nErr = pMatrix->GetError(nC, nR);
    4505          12 :                     if (nErr)
    4506           0 :                         rBuffer.append(ScGlobal::GetErrorString(nErr));
    4507             :                     else
    4508          12 :                         AppendDouble(rBuffer, pMatrix->GetDouble(nC, nR));
    4509             :                 }
    4510             :             }
    4511           0 :             else if( pMatrix->IsEmpty( nC, nR ) )
    4512             :                 ;
    4513           0 :             else if( pMatrix->IsString( nC, nR ) )
    4514           0 :                 AppendString( rBuffer, pMatrix->GetString(nC, nR).getString() );
    4515             :         }
    4516             :     }
    4517           4 :     rBuffer.append( mxSymbols->getSymbol(ocArrayClose) );
    4518           4 : }
    4519             : 
    4520             : namespace {
    4521           0 : void escapeTableRefColumnSpecifier( OUString& rStr )
    4522             : {
    4523           0 :     const sal_Int32 n = rStr.getLength();
    4524           0 :     OUStringBuffer aBuf( n * 2 );
    4525           0 :     const sal_Unicode* p = rStr.getStr();
    4526           0 :     const sal_Unicode* const pStop = p + n;
    4527           0 :     for ( ; p < pStop; ++p)
    4528             :     {
    4529           0 :         const sal_Unicode c = *p;
    4530           0 :         switch (c)
    4531             :         {
    4532             :             case '\'':
    4533             :             case '[':
    4534             :             case '#':
    4535             :             case ']':
    4536           0 :                 aBuf.append( '\'' );
    4537           0 :                 break;
    4538             :             default:
    4539             :                 ;   // nothing
    4540             :         }
    4541           0 :         aBuf.append( c );
    4542             :     }
    4543           0 :     rStr = aBuf.makeStringAndClear();
    4544           0 : }
    4545             : }
    4546             : 
    4547       15011 : void ScCompiler::CreateStringFromSingleRef( OUStringBuffer& rBuffer, const FormulaToken* _pTokenP ) const
    4548             : {
    4549             :     const FormulaToken* p;
    4550       15011 :     OUString aErrRef = GetCurrentOpCodeMap()->getSymbol(ocErrRef);
    4551       15011 :     const OpCode eOp = _pTokenP->GetOpCode();
    4552       15011 :     const ScSingleRefData& rRef = *_pTokenP->GetSingleRef();
    4553             :     ScComplexRefData aRef;
    4554       15011 :     aRef.Ref1 = aRef.Ref2 = rRef;
    4555       15011 :     if ( eOp == ocColRowName )
    4556             :     {
    4557           0 :         ScAddress aAbs = rRef.toAbs(aPos);
    4558           0 :         if (pDoc->HasStringData(aAbs.Col(), aAbs.Row(), aAbs.Tab()))
    4559             :         {
    4560           0 :             OUString aStr = pDoc->GetString(aAbs);
    4561           0 :             EnQuote( aStr );
    4562           0 :             rBuffer.append(aStr);
    4563             :         }
    4564             :         else
    4565             :         {
    4566           0 :             rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
    4567             :             pConv->makeRefStr(rBuffer, meGrammar, aPos, aErrRef,
    4568           0 :                               GetSetupTabNames(), aRef, true);
    4569             :         }
    4570             :     }
    4571       15011 :     else if (pArr && (p = pArr->PeekPrevNoSpaces()) && p->GetOpCode() == ocTableRefOpen)
    4572             :     {
    4573           0 :         ScAddress aAbs = rRef.toAbs(aPos);
    4574           0 :         OUString aStr = pDoc->GetString(aAbs);
    4575           0 :         escapeTableRefColumnSpecifier( aStr);
    4576           0 :         rBuffer.append(aStr);
    4577             :     }
    4578             :     else
    4579             :         pConv->makeRefStr(rBuffer, meGrammar, aPos, aErrRef,
    4580       15011 :                           GetSetupTabNames(), aRef, true);
    4581       15011 : }
    4582             : 
    4583       13643 : void ScCompiler::CreateStringFromDoubleRef( OUStringBuffer& rBuffer, const FormulaToken* _pTokenP ) const
    4584             : {
    4585       13643 :     OUString aErrRef = GetCurrentOpCodeMap()->getSymbol(ocErrRef);
    4586       13643 :     pConv->makeRefStr(rBuffer, meGrammar, aPos, aErrRef, GetSetupTabNames(),
    4587       27286 :                       *_pTokenP->GetDoubleRef(), false);
    4588       13643 : }
    4589             : 
    4590          55 : void ScCompiler::CreateStringFromIndex( OUStringBuffer& rBuffer, const FormulaToken* _pTokenP ) const
    4591             : {
    4592          55 :     const OpCode eOp = _pTokenP->GetOpCode();
    4593          55 :     OUStringBuffer aBuffer;
    4594          55 :     switch ( eOp )
    4595             :     {
    4596             :         case ocName:
    4597             :         {
    4598          48 :             const ScRangeData* pData = GetRangeData( *_pTokenP);
    4599          48 :             if (pData)
    4600          48 :                 aBuffer.append(pData->GetName());
    4601             :         }
    4602          48 :         break;
    4603             :         case ocDBArea:
    4604             :         {
    4605           7 :             const ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(_pTokenP->GetIndex());
    4606           7 :             if (pDBData)
    4607           7 :                 aBuffer.append(pDBData->GetName());
    4608             :         }
    4609           7 :         break;
    4610             :         case ocTableRef:
    4611             :         {
    4612           0 :             if (NeedsTableRefTransformation())
    4613             :             {
    4614             :                 // Write the resulting reference if TableRef is not supported.
    4615           0 :                 const ScTableRefToken* pTR = dynamic_cast<const ScTableRefToken*>(_pTokenP);
    4616           0 :                 if (!pTR)
    4617           0 :                     AppendErrorConstant( aBuffer, errNoCode);
    4618             :                 else
    4619             :                 {
    4620           0 :                     const FormulaToken* pRef = pTR->GetAreaRefRPN();
    4621           0 :                     if (!pRef)
    4622           0 :                         AppendErrorConstant( aBuffer, errNoCode);
    4623             :                     else
    4624             :                     {
    4625           0 :                         switch (pRef->GetType())
    4626             :                         {
    4627             :                             case svSingleRef:
    4628           0 :                                 CreateStringFromSingleRef( aBuffer, pRef);
    4629           0 :                                 break;
    4630             :                             case svDoubleRef:
    4631           0 :                                 CreateStringFromDoubleRef( aBuffer, pRef);
    4632           0 :                                 break;
    4633             :                             case svError:
    4634           0 :                                 AppendErrorConstant( aBuffer, pRef->GetError());
    4635           0 :                                 break;
    4636             :                             default:
    4637           0 :                                 AppendErrorConstant( aBuffer, errNoCode);
    4638             :                         }
    4639             :                     }
    4640             :                 }
    4641             :             }
    4642             :             else
    4643             :             {
    4644           0 :                 const ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(_pTokenP->GetIndex());
    4645           0 :                 if (pDBData)
    4646           0 :                     aBuffer.append(pDBData->GetName());
    4647             :             }
    4648             :         }
    4649           0 :         break;
    4650             :         default:
    4651             :             ;   // nothing
    4652             :     }
    4653          55 :     if ( !aBuffer.isEmpty() )
    4654          55 :         rBuffer.append(aBuffer.makeStringAndClear());
    4655             :     else
    4656           0 :         rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
    4657          55 : }
    4658             : 
    4659           1 : void ScCompiler::LocalizeString( OUString& rName ) const
    4660             : {
    4661           1 :     ScGlobal::GetAddInCollection()->LocalizeString( rName );
    4662           1 : }
    4663             : 
    4664             : // Put quotes around string if non-alphanumeric characters are contained,
    4665             : // quote characters contained within are escaped by '\\'.
    4666           0 : bool ScCompiler::EnQuote( OUString& rStr )
    4667             : {
    4668           0 :     sal_Int32 nType = ScGlobal::pCharClass->getStringType( rStr, 0, rStr.getLength() );
    4669           0 :     if ( !CharClass::isNumericType( nType )
    4670           0 :             && CharClass::isAlphaNumericType( nType ) )
    4671           0 :         return false;
    4672             : 
    4673           0 :     sal_Int32 nPos = 0;
    4674           0 :     while ( (nPos = rStr.indexOf( '\'', nPos)) != -1 )
    4675             :     {
    4676           0 :         rStr = rStr.replaceAt( nPos, 0, "\\" );
    4677           0 :         nPos += 2;
    4678             :     }
    4679           0 :     rStr = "'" + rStr + "'";
    4680           0 :     return true;
    4681             : }
    4682             : 
    4683           0 : sal_Unicode ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eType ) const
    4684             : {
    4685           0 :     return pConv->getSpecialSymbol(eType);
    4686             : }
    4687             : 
    4688           0 : FormulaTokenRef ScCompiler::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, bool bReuseDoubleRef )
    4689             : {
    4690           0 :     return extendRangeReference( rTok1, rTok2, aPos,bReuseDoubleRef );
    4691             : }
    4692             : 
    4693           0 : void ScCompiler::fillAddInToken(::std::vector< ::com::sun::star::sheet::FormulaOpCodeMapEntry >& _rVec,bool _bIsEnglish) const
    4694             : {
    4695             :     // All known AddIn functions.
    4696           0 :     sheet::FormulaOpCodeMapEntry aEntry;
    4697           0 :     aEntry.Token.OpCode = ocExternal;
    4698             : 
    4699           0 :     ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
    4700           0 :     const long nCount = pColl->GetFuncCount();
    4701           0 :     for (long i=0; i < nCount; ++i)
    4702             :     {
    4703           0 :         const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
    4704           0 :         if (pFuncData)
    4705             :         {
    4706           0 :             if ( _bIsEnglish )
    4707             :             {
    4708           0 :                 OUString aName;
    4709           0 :                 if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
    4710           0 :                     aEntry.Name = aName;
    4711             :                 else
    4712           0 :                     aEntry.Name = pFuncData->GetUpperName();
    4713             :             }
    4714             :             else
    4715           0 :                 aEntry.Name = pFuncData->GetUpperLocal();
    4716           0 :             aEntry.Token.Data <<= OUString( pFuncData->GetOriginalName());
    4717           0 :             _rVec.push_back( aEntry);
    4718             :         }
    4719           0 :     }
    4720             :     // FIXME: what about those old non-UNO AddIns?
    4721           0 : }
    4722             : 
    4723           0 : bool ScCompiler::HandleColRowName()
    4724             : {
    4725           0 :     ScSingleRefData& rRef = *mpToken.get()->GetSingleRef();
    4726           0 :     ScAddress aAbs = rRef.toAbs(aPos);
    4727           0 :     if (!ValidAddress(aAbs))
    4728             :     {
    4729           0 :         SetError( errNoRef );
    4730           0 :         return true;
    4731             :     }
    4732           0 :     SCCOL nCol = aAbs.Col();
    4733           0 :     SCROW nRow = aAbs.Row();
    4734           0 :     SCTAB nTab = aAbs.Tab();
    4735           0 :     ScAddress aLook = aAbs;
    4736           0 :     bool bColName = rRef.IsColRel();
    4737           0 :     SCCOL nMyCol = aPos.Col();
    4738           0 :     SCROW nMyRow = aPos.Row();
    4739           0 :     bool bInList = false;
    4740           0 :     bool bValidName = false;
    4741             :     ScRangePairList* pRL = (bColName ?
    4742           0 :         pDoc->GetColNameRanges() : pDoc->GetRowNameRanges());
    4743           0 :     ScRange aRange;
    4744           0 :     for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
    4745             :     {
    4746           0 :         ScRangePair* pR = (*pRL)[i];
    4747           0 :         if ( pR->GetRange(0).In( aLook ) )
    4748             :         {
    4749           0 :             bInList = bValidName = true;
    4750           0 :             aRange = pR->GetRange(1);
    4751           0 :             if ( bColName )
    4752             :             {
    4753           0 :                 aRange.aStart.SetCol( nCol );
    4754           0 :                 aRange.aEnd.SetCol( nCol );
    4755             :             }
    4756             :             else
    4757             :             {
    4758           0 :                 aRange.aStart.SetRow( nRow );
    4759           0 :                 aRange.aEnd.SetRow( nRow );
    4760             :             }
    4761           0 :             break;  // for
    4762             :         }
    4763             :     }
    4764           0 :     if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
    4765             :     {   // automagically or created by copying and NamePos isn't in list
    4766           0 :         ScRefCellValue aCell;
    4767           0 :         aCell.assign(*pDoc, aLook);
    4768           0 :         bool bString = aCell.hasString();
    4769           0 :         if (!bString && aCell.isEmpty())
    4770           0 :             bString = true;     // empty cell is ok
    4771           0 :         if ( bString )
    4772             :         {   // coresponds with ScInterpreter::ScColRowNameAuto()
    4773           0 :             bValidName = true;
    4774           0 :             if ( bColName )
    4775             :             {   // ColName
    4776           0 :                 SCROW nStartRow = nRow + 1;
    4777           0 :                 if ( nStartRow > MAXROW )
    4778           0 :                     nStartRow = MAXROW;
    4779           0 :                 SCROW nMaxRow = MAXROW;
    4780           0 :                 if ( nMyCol == nCol )
    4781             :                 {   // formula cell in same column
    4782           0 :                     if ( nMyRow == nStartRow )
    4783             :                     {   // take remainder under name cell
    4784           0 :                         nStartRow++;
    4785           0 :                         if ( nStartRow > MAXROW )
    4786           0 :                             nStartRow = MAXROW;
    4787             :                     }
    4788           0 :                     else if ( nMyRow > nStartRow )
    4789             :                     {   // from name cell down to formula cell
    4790           0 :                         nMaxRow = nMyRow - 1;
    4791             :                     }
    4792             :                 }
    4793           0 :                 for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
    4794             :                 {   // next defined ColNameRange below limits row
    4795           0 :                     ScRangePair* pR = (*pRL)[i];
    4796           0 :                     const ScRange& rRange = pR->GetRange(1);
    4797           0 :                     if ( rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col() )
    4798             :                     {   // identical column range
    4799           0 :                         SCROW nTmp = rRange.aStart.Row();
    4800           0 :                         if ( nStartRow < nTmp && nTmp <= nMaxRow )
    4801           0 :                             nMaxRow = nTmp - 1;
    4802             :                     }
    4803             :                 }
    4804           0 :                 aRange.aStart.Set( nCol, nStartRow, nTab );
    4805           0 :                 aRange.aEnd.Set( nCol, nMaxRow, nTab );
    4806             :             }
    4807             :             else
    4808             :             {   // RowName
    4809           0 :                 SCCOL nStartCol = nCol + 1;
    4810           0 :                 if ( nStartCol > MAXCOL )
    4811           0 :                     nStartCol = MAXCOL;
    4812           0 :                 SCCOL nMaxCol = MAXCOL;
    4813           0 :                 if ( nMyRow == nRow )
    4814             :                 {   // formula cell in same row
    4815           0 :                     if ( nMyCol == nStartCol )
    4816             :                     {   // take remainder right from name cell
    4817           0 :                         nStartCol++;
    4818           0 :                         if ( nStartCol > MAXCOL )
    4819           0 :                             nStartCol = MAXCOL;
    4820             :                     }
    4821           0 :                     else if ( nMyCol > nStartCol )
    4822             :                     {   // from name cell right to formula cell
    4823           0 :                         nMaxCol = nMyCol - 1;
    4824             :                     }
    4825             :                 }
    4826           0 :                 for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
    4827             :                 {   // next defined RowNameRange to the right limits column
    4828           0 :                     ScRangePair* pR = (*pRL)[i];
    4829           0 :                     const ScRange& rRange = pR->GetRange(1);
    4830           0 :                     if ( rRange.aStart.Row() <= nRow && nRow <= rRange.aEnd.Row() )
    4831             :                     {   // identical row range
    4832           0 :                         SCCOL nTmp = rRange.aStart.Col();
    4833           0 :                         if ( nStartCol < nTmp && nTmp <= nMaxCol )
    4834           0 :                             nMaxCol = nTmp - 1;
    4835             :                     }
    4836             :                 }
    4837           0 :                 aRange.aStart.Set( nStartCol, nRow, nTab );
    4838           0 :                 aRange.aEnd.Set( nMaxCol, nRow, nTab );
    4839             :             }
    4840           0 :         }
    4841             :     }
    4842           0 :     if ( bValidName )
    4843             :     {
    4844             :         // And now the magic to distinguish between a range and a single
    4845             :         // cell thereof, which is picked position-dependent of the formula
    4846             :         // cell. If a direct neighbor is a binary operator (ocAdd, ...) a
    4847             :         // SingleRef matching the column/row of the formula cell is
    4848             :         // generated. A ocColRowName or ocIntersect as a neighbor results
    4849             :         // in a range. Special case: if label is valid for a single cell, a
    4850             :         // position independent SingleRef is generated.
    4851           0 :         bool bSingle = (aRange.aStart == aRange.aEnd);
    4852             :         bool bFound;
    4853           0 :         if ( bSingle )
    4854           0 :             bFound = true;
    4855             :         else
    4856             :         {
    4857           0 :             FormulaToken* p1 = pArr->PeekPrevNoSpaces();
    4858           0 :             FormulaToken* p2 = pArr->PeekNextNoSpaces();
    4859             :             // begin/end of a formula => single
    4860           0 :             OpCode eOp1 = p1 ? p1->GetOpCode() : static_cast<OpCode>( ocAdd );
    4861           0 :             OpCode eOp2 = p2 ? p2->GetOpCode() : static_cast<OpCode>( ocAdd );
    4862           0 :             if ( eOp1 != ocColRowName && eOp1 != ocIntersect
    4863           0 :                 && eOp2 != ocColRowName && eOp2 != ocIntersect )
    4864             :             {
    4865           0 :                 if (    (SC_OPCODE_START_BIN_OP <= eOp1 && eOp1 < SC_OPCODE_STOP_BIN_OP) ||
    4866           0 :                         (SC_OPCODE_START_BIN_OP <= eOp2 && eOp2 < SC_OPCODE_STOP_BIN_OP))
    4867           0 :                     bSingle = true;
    4868             :             }
    4869           0 :             if ( bSingle )
    4870             :             {   // column and/or row must match range
    4871           0 :                 if ( bColName )
    4872             :                 {
    4873           0 :                     bFound = (aRange.aStart.Row() <= nMyRow
    4874           0 :                         && nMyRow <= aRange.aEnd.Row());
    4875           0 :                     if ( bFound )
    4876           0 :                         aRange.aStart.SetRow( nMyRow );
    4877             :                 }
    4878             :                 else
    4879             :                 {
    4880           0 :                     bFound = (aRange.aStart.Col() <= nMyCol
    4881           0 :                         && nMyCol <= aRange.aEnd.Col());
    4882           0 :                     if ( bFound )
    4883           0 :                         aRange.aStart.SetCol( nMyCol );
    4884             :                 }
    4885             :             }
    4886             :             else
    4887           0 :                 bFound = true;
    4888             :         }
    4889           0 :         if ( !bFound )
    4890           0 :             SetError(errNoRef);
    4891           0 :         else if (mbJumpCommandReorder)
    4892             :         {
    4893           0 :             ScTokenArray* pNew = new ScTokenArray();
    4894           0 :             if ( bSingle )
    4895             :             {
    4896             :                 ScSingleRefData aRefData;
    4897           0 :                 aRefData.InitAddress( aRange.aStart );
    4898           0 :                 if ( bColName )
    4899           0 :                     aRefData.SetColRel( true );
    4900             :                 else
    4901           0 :                     aRefData.SetRowRel( true );
    4902           0 :                 aRefData.SetAddress(aRange.aStart, aPos);
    4903           0 :                 pNew->AddSingleReference( aRefData );
    4904             :             }
    4905             :             else
    4906             :             {
    4907             :                 ScComplexRefData aRefData;
    4908           0 :                 aRefData.InitRange( aRange );
    4909           0 :                 if ( bColName )
    4910             :                 {
    4911           0 :                     aRefData.Ref1.SetColRel( true );
    4912           0 :                     aRefData.Ref2.SetColRel( true );
    4913             :                 }
    4914             :                 else
    4915             :                 {
    4916           0 :                     aRefData.Ref1.SetRowRel( true );
    4917           0 :                     aRefData.Ref2.SetRowRel( true );
    4918             :                 }
    4919           0 :                 aRefData.SetRange(aRange, aPos);
    4920           0 :                 if ( bInList )
    4921           0 :                     pNew->AddDoubleReference( aRefData );
    4922             :                 else
    4923             :                 {   // automagically
    4924           0 :                     pNew->Add( new ScDoubleRefToken( aRefData, ocColRowNameAuto ) );
    4925             :                 }
    4926             :             }
    4927           0 :             PushTokenArray( pNew, true );
    4928           0 :             pNew->Reset();
    4929           0 :             return GetToken();
    4930             :         }
    4931             :     }
    4932             :     else
    4933           0 :         SetError(errNoName);
    4934           0 :     return true;
    4935             : }
    4936             : 
    4937          12 : bool ScCompiler::HandleDbData()
    4938             : {
    4939          12 :     ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(mpToken->GetIndex());
    4940          12 :     if ( !pDBData )
    4941           0 :         SetError(errNoName);
    4942          12 :     else if (mbJumpCommandReorder)
    4943             :     {
    4944             :         ScComplexRefData aRefData;
    4945          12 :         aRefData.InitFlags();
    4946          12 :         ScRange aRange;
    4947          12 :         pDBData->GetArea(aRange);
    4948          12 :         aRange.aEnd.SetTab(aRange.aStart.Tab());
    4949          12 :         aRefData.SetRange(aRange, aPos);
    4950          12 :         ScTokenArray* pNew = new ScTokenArray();
    4951          12 :         pNew->AddDoubleReference( aRefData );
    4952          12 :         PushTokenArray( pNew, true );
    4953          12 :         pNew->Reset();
    4954          12 :         return GetToken();
    4955             :     }
    4956           0 :     return true;
    4957             : }
    4958             : 
    4959           0 : bool ScCompiler::GetTokenIfOpCode( OpCode eOp )
    4960             : {
    4961           0 :     const formula::FormulaToken* p = pArr->PeekNextNoSpaces();
    4962           0 :     if (p && p->GetOpCode() == eOp)
    4963           0 :         return GetToken();
    4964           0 :     return false;
    4965             : }
    4966             : 
    4967             : 
    4968             : /* Documentation on MS-Excel Table structured references:
    4969             :  * https://support.office.com/en-us/article/Use-structured-references-in-Excel-table-formulas-75fb07d3-826a-449c-b76f-363057e3d16f
    4970             :  * * as of Excel 2013
    4971             :  * [MS-XLSX]: Formulas https://msdn.microsoft.com/en-us/library/dd906358.aspx
    4972             :  * * look for structure-reference
    4973             :  */
    4974             : 
    4975           0 : bool ScCompiler::HandleTableRef()
    4976             : {
    4977           0 :     ScTableRefToken* pTR = dynamic_cast<ScTableRefToken*>(mpToken.get());
    4978           0 :     if (!pTR)
    4979             :     {
    4980           0 :         SetError(errUnknownToken);
    4981           0 :         return true;
    4982             :     }
    4983             : 
    4984           0 :     ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex( pTR->GetIndex());
    4985           0 :     if ( !pDBData )
    4986           0 :         SetError(errNoName);
    4987           0 :     else if (mbJumpCommandReorder)
    4988             :     {
    4989           0 :         ScRange aDBRange;
    4990           0 :         pDBData->GetArea(aDBRange);
    4991           0 :         aDBRange.aEnd.SetTab(aDBRange.aStart.Tab());
    4992           0 :         ScRange aRange( aDBRange);
    4993           0 :         sal_uInt16 nError = 0;
    4994           0 :         bool bForwardToClose = false;
    4995           0 :         ScTableRefToken::Item eItem = pTR->GetItem();
    4996           0 :         switch (eItem)
    4997             :         {
    4998             :             case ScTableRefToken::TABLE:
    4999             :                 {
    5000             :                     // The table name without items references the table data,
    5001             :                     // without headers or totals.
    5002           0 :                     if (pDBData->HasHeader())
    5003           0 :                         aRange.aStart.IncRow();
    5004           0 :                     if (pDBData->HasTotals())
    5005           0 :                         aRange.aEnd.IncRow(-1);
    5006           0 :                     if (aRange.aEnd.Row() < aRange.aStart.Row())
    5007           0 :                         nError = errNoRef;
    5008           0 :                     bForwardToClose = true;
    5009             :                 }
    5010           0 :                 break;
    5011             :             case ScTableRefToken::ALL:
    5012             :                 {
    5013           0 :                     bForwardToClose = true;
    5014             :                 }
    5015           0 :                 break;
    5016             :             case ScTableRefToken::HEADERS:
    5017             :                 {
    5018           0 :                     if (pDBData->HasHeader())
    5019           0 :                         aRange.aEnd.SetRow( aRange.aStart.Row());
    5020             :                     else
    5021           0 :                         nError = errNoRef;
    5022           0 :                     bForwardToClose = true;
    5023             :                 }
    5024           0 :                 break;
    5025             :             case ScTableRefToken::DATA:
    5026             :                 {
    5027           0 :                     if (pDBData->HasHeader())
    5028           0 :                         aRange.aStart.IncRow();
    5029             :                 }
    5030             :                 // fallthru
    5031             :             case ScTableRefToken::HEADERS_DATA:
    5032             :                 {
    5033           0 :                     if (pDBData->HasTotals())
    5034           0 :                         aRange.aEnd.IncRow(-1);
    5035           0 :                     if (aRange.aEnd.Row() < aRange.aStart.Row())
    5036           0 :                         nError = errNoRef;
    5037           0 :                     bForwardToClose = true;
    5038             :                 }
    5039           0 :                 break;
    5040             :             case ScTableRefToken::TOTALS:
    5041             :                 {
    5042           0 :                     if (pDBData->HasTotals())
    5043           0 :                         aRange.aStart.SetRow( aRange.aEnd.Row());
    5044             :                     else
    5045           0 :                         nError = errNoRef;
    5046           0 :                     bForwardToClose = true;
    5047             :                 }
    5048           0 :                 break;
    5049             :             case ScTableRefToken::DATA_TOTALS:
    5050             :                 {
    5051           0 :                     if (pDBData->HasHeader())
    5052           0 :                         aRange.aStart.IncRow();
    5053           0 :                     if (aRange.aEnd.Row() < aRange.aStart.Row())
    5054           0 :                         nError = errNoRef;
    5055           0 :                     bForwardToClose = true;
    5056             :                 }
    5057           0 :                 break;
    5058             :             case ScTableRefToken::THIS_ROW:
    5059             :                 {
    5060           0 :                     if (aRange.aStart.Row() <= aPos.Row() && aPos.Row() <= aRange.aEnd.Row())
    5061             :                     {
    5062           0 :                         aRange.aStart.SetRow( aPos.Row());
    5063           0 :                         aRange.aEnd.SetRow( aPos.Row());
    5064             :                     }
    5065             :                     else
    5066           0 :                         nError = errNoRef;
    5067           0 :                     bForwardToClose = true;
    5068             :                 }
    5069           0 :                 break;
    5070             :         }
    5071           0 :         bool bColumnRange = false;
    5072           0 :         int nLevel = 0;
    5073           0 :         if (bForwardToClose && GetTokenIfOpCode( ocTableRefOpen))
    5074             :         {
    5075           0 :             ++nLevel;
    5076             :             enum
    5077             :             {
    5078             :                 sOpen,
    5079             :                 sItem,
    5080             :                 sClose,
    5081             :                 sSep,
    5082             :                 sLast,
    5083             :                 sStop
    5084           0 :             } eState = sOpen;
    5085           0 :             do
    5086             :             {
    5087           0 :                 const formula::FormulaToken* p = pArr->PeekNextNoSpaces();
    5088           0 :                 if (!p)
    5089           0 :                     eState = sStop;
    5090             :                 else
    5091             :                 {
    5092           0 :                     switch (p->GetOpCode())
    5093             :                     {
    5094             :                         case ocTableRefOpen:
    5095           0 :                             eState = ((eState == sOpen || eState == sSep) ? sOpen : sStop);
    5096           0 :                             if (++nLevel > 2)
    5097             :                             {
    5098           0 :                                 SetError( errPair);
    5099           0 :                                 eState = sStop;
    5100             :                             }
    5101           0 :                             break;
    5102             :                         case ocTableRefItemAll:
    5103             :                         case ocTableRefItemHeaders:
    5104             :                         case ocTableRefItemData:
    5105             :                         case ocTableRefItemTotals:
    5106             :                         case ocTableRefItemThisRow:
    5107           0 :                             eState = ((eState == sOpen) ? sItem : sStop);
    5108           0 :                             break;
    5109             :                         case ocTableRefClose:
    5110           0 :                             eState = ((eState == sItem || eState == sClose) ? sClose : sStop);
    5111           0 :                             if (eState != sStop && --nLevel == 0)
    5112           0 :                                 eState = sLast;
    5113           0 :                             break;
    5114             :                         case ocSep:
    5115           0 :                             eState = ((eState == sClose) ? sSep : sStop);
    5116           0 :                             break;
    5117             :                         case ocPush:
    5118           0 :                             if (eState == sOpen && p->GetType() == svSingleRef)
    5119             :                             {
    5120           0 :                                 bColumnRange = true;
    5121           0 :                                 eState = sLast;
    5122             :                             }
    5123             :                             else
    5124             :                             {
    5125           0 :                                 eState = sStop;
    5126             :                             }
    5127           0 :                             break;
    5128             :                         case ocBad:
    5129           0 :                             eState = sLast;
    5130           0 :                             if (!nError)
    5131           0 :                                 nError = errNoName;
    5132           0 :                             break;
    5133             :                         default:
    5134           0 :                             eState = sStop;
    5135             :                     }
    5136           0 :                     if (eState != sStop)
    5137           0 :                         GetToken();
    5138           0 :                     if (eState == sLast)
    5139           0 :                         eState = sStop;
    5140             :                 }
    5141             :             } while (eState != sStop);
    5142             :         }
    5143           0 :         ScTokenArray* pNew = new ScTokenArray();
    5144           0 :         if (!nError)
    5145             :         {
    5146           0 :             if (bColumnRange)
    5147             :             {
    5148             :                 // Limit range to specified columns.
    5149           0 :                 ScRange aColRange( ScAddress::INITIALIZE_INVALID );
    5150           0 :                 switch (mpToken->GetType())
    5151             :                 {
    5152             :                     case svSingleRef:
    5153             :                         {
    5154           0 :                             aColRange.aStart = aColRange.aEnd = mpToken->GetSingleRef()->toAbs( aPos);
    5155           0 :                             if (    GetTokenIfOpCode( ocTableRefClose) && (nLevel--) &&
    5156           0 :                                     GetTokenIfOpCode( ocRange) &&
    5157           0 :                                     GetTokenIfOpCode( ocTableRefOpen) && (++nLevel) &&
    5158           0 :                                     GetTokenIfOpCode( ocPush))
    5159             :                             {
    5160           0 :                                 if (mpToken->GetType() != svSingleRef)
    5161           0 :                                     aColRange = ScRange( ScAddress::INITIALIZE_INVALID);
    5162             :                                 else
    5163             :                                 {
    5164           0 :                                     aColRange.aEnd = mpToken->GetSingleRef()->toAbs( aPos);
    5165           0 :                                     aColRange.Justify();
    5166             :                                 }
    5167             :                             }
    5168             :                         }
    5169           0 :                         break;
    5170             :                     default:
    5171             :                         ;   // nothing
    5172             :                 }
    5173           0 :                 if (aColRange.aStart.Row() != aDBRange.aStart.Row() || aColRange.aEnd.Row() != aDBRange.aStart.Row())
    5174           0 :                     aRange = ScRange( ScAddress::INITIALIZE_INVALID);
    5175             :                 else
    5176             :                 {
    5177           0 :                     aColRange.aEnd.SetRow( aRange.aEnd.Row());
    5178           0 :                     aRange = aRange.Intersection( aColRange);
    5179             :                 }
    5180             :             }
    5181           0 :             if (aRange.IsValid())
    5182             :             {
    5183           0 :                 if (aRange.aStart == aRange.aEnd)
    5184             :                 {
    5185             :                     ScSingleRefData aRefData;
    5186           0 :                     aRefData.InitFlags();
    5187           0 :                     aRefData.SetColRel( true);
    5188           0 :                     if (eItem == ScTableRefToken::THIS_ROW)
    5189             :                     {
    5190           0 :                         aRefData.SetRowRel( true);
    5191             :                     }
    5192           0 :                     if (aRange.aStart.Tab() != aPos.Tab())
    5193           0 :                         aRefData.SetFlag3D( true);
    5194             :                     else
    5195             :                     {
    5196           0 :                         aRefData.SetTabRel( true);
    5197             :                     }
    5198           0 :                     aRefData.SetAddress( aRange.aStart, aPos);
    5199           0 :                     pTR->SetAreaRefRPN( pNew->AddSingleReference( aRefData ));
    5200             :                 }
    5201             :                 else
    5202             :                 {
    5203             :                     ScComplexRefData aRefData;
    5204           0 :                     aRefData.InitFlags();
    5205           0 :                     aRefData.Ref1.SetColRel( true);
    5206           0 :                     aRefData.Ref2.SetColRel( true);
    5207           0 :                     if (eItem == ScTableRefToken::THIS_ROW)
    5208             :                     {
    5209           0 :                         aRefData.Ref1.SetRowRel( true);
    5210           0 :                         aRefData.Ref2.SetRowRel( true);
    5211             :                     }
    5212           0 :                     if (aRange.aStart.Tab() != aPos.Tab())
    5213           0 :                         aRefData.Ref1.SetFlag3D( true);
    5214             :                     else
    5215             :                     {
    5216           0 :                         aRefData.Ref1.SetTabRel( true);
    5217           0 :                         aRefData.Ref2.SetTabRel( true);
    5218             :                     }
    5219           0 :                     aRefData.SetRange( aRange, aPos);
    5220           0 :                     pTR->SetAreaRefRPN( pNew->AddDoubleReference( aRefData ));
    5221             :                 }
    5222             :             }
    5223             :             else
    5224             :             {
    5225           0 :                 pTR->SetAreaRefRPN( pNew->Add( new FormulaErrorToken( errNoRef)));
    5226             :             }
    5227             :         }
    5228             :         else
    5229             :         {
    5230           0 :             pTR->SetAreaRefRPN( pNew->Add( new FormulaErrorToken( nError)));
    5231             :         }
    5232           0 :         while (nLevel-- > 0)
    5233             :         {
    5234           0 :             if (!GetTokenIfOpCode( ocTableRefClose))
    5235           0 :                 SetError( errPair);
    5236             :         }
    5237           0 :         PushTokenArray( pNew, true );
    5238           0 :         pNew->Reset();
    5239           0 :         return GetToken();
    5240             :     }
    5241           0 :     return true;
    5242         156 : }
    5243             : 
    5244             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11