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