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