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