1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <sal/macros.h>
20 #include "formula/FormulaCompiler.hxx"
21 #include "formula/errorcodes.hxx"
22 #include "formula/token.hxx"
23 #include "formula/tokenarray.hxx"
24 #include "core_resource.hxx"
25 #include "core_resource.hrc"
27 #include <svl/zforlist.hxx>
28 #include <tools/rc.hxx>
29 #include <tools/rcid.h>
30 #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
31 #include <com/sun/star/sheet/FormulaMapGroup.hpp>
32 #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
33 #include <rtl/strbuf.hxx>
36 // =============================================================================
39 // =============================================================================
40 using namespace ::com::sun::star
;
42 static const sal_Char
* pInternal
[ 1 ] = { "TTT" };
44 // =============================================================================
47 // =============================================================================
48 class FormulaCompilerRecursionGuard
53 FormulaCompilerRecursionGuard( short& rRec
)
54 : rRecursion( rRec
) { ++rRecursion
; }
55 ~FormulaCompilerRecursionGuard() { --rRecursion
; }
58 short lcl_GetRetFormat( OpCode eOpCode
)
87 return NUMBERFORMAT_LOGICAL
;
91 return NUMBERFORMAT_DATE
;
93 return NUMBERFORMAT_DATETIME
;
95 return NUMBERFORMAT_TIME
;
109 return NUMBERFORMAT_CURRENCY
;
117 return NUMBERFORMAT_PERCENT
;
119 return NUMBERFORMAT_NUMBER
;
123 inline void lclPushOpCodeMapEntry( ::std::vector
< sheet::FormulaOpCodeMapEntry
>& rVec
, const String
* pTable
, sal_uInt16 nOpCode
)
125 sheet::FormulaOpCodeMapEntry aEntry
;
126 aEntry
.Token
.OpCode
= nOpCode
;
127 aEntry
.Name
= pTable
[nOpCode
];
128 rVec
.push_back( aEntry
);
131 void lclPushOpCodeMapEntries( ::std::vector
< sheet::FormulaOpCodeMapEntry
>& rVec
, const String
* pTable
, sal_uInt16 nOpCodeBeg
, sal_uInt16 nOpCodeEnd
)
133 for (sal_uInt16 nOpCode
= nOpCodeBeg
; nOpCode
< nOpCodeEnd
; ++nOpCode
)
134 lclPushOpCodeMapEntry( rVec
, pTable
, nOpCode
);
137 void lclPushOpCodeMapEntries( ::std::vector
< sheet::FormulaOpCodeMapEntry
>& rVec
, const String
* pTable
, const sal_uInt16
* pnOpCodes
, size_t nCount
)
139 for (const sal_uInt16
* pnEnd
= pnOpCodes
+ nCount
; pnOpCodes
< pnEnd
; ++pnOpCodes
)
140 lclPushOpCodeMapEntry( rVec
, pTable
, *pnOpCodes
);
143 class OpCodeList
: public Resource
// temp object for resource
147 OpCodeList( sal_uInt16
, FormulaCompiler::NonConstOpCodeMapPtr
);
150 bool getOpCodeString( String
& rStr
, sal_uInt16 nOp
);
151 void putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap
, sal_uInt16 nOp
);
159 SeparatorType meSepType
;
162 OpCodeList::OpCodeList( sal_uInt16 nRID
, FormulaCompiler::NonConstOpCodeMapPtr xMap
) :
163 Resource( ResId(nRID
,*ResourceManager::getResManager()) )
164 ,meSepType(SEMICOLON_BASE
)
166 for (sal_uInt16 i
= 0; i
<= SC_OPCODE_LAST_OPCODE_ID
; ++i
)
169 if ( getOpCodeString(aOpStr
, i
) )
170 xMap
->putOpCode(aOpStr
, OpCode(i
));
172 putDefaultOpCode(xMap
, i
);
178 bool OpCodeList::getOpCodeString( String
& rStr
, sal_uInt16 nOp
)
184 if (meSepType
== COMMA_BASE
)
186 rStr
= rtl::OUString(",");
189 else if (meSepType
== SEMICOLON_BASE
)
191 rStr
= rtl::OUString(";");
196 case SC_OPCODE_ARRAY_COL_SEP
:
198 if (meSepType
== COMMA_BASE
)
200 rStr
= rtl::OUString(",");
203 else if (meSepType
== SEMICOLON_BASE
)
205 rStr
= rtl::OUString(";");
210 case SC_OPCODE_ARRAY_ROW_SEP
:
212 if (meSepType
== COMMA_BASE
)
214 rStr
= rtl::OUString(";");
217 else if (meSepType
== SEMICOLON_BASE
)
219 rStr
= rtl::OUString("|");
229 void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap
, sal_uInt16 nOp
)
231 ResId
aRes(nOp
,*ResourceManager::getResManager());
232 aRes
.SetRT(RSC_STRING
);
233 if (IsAvailableRes(aRes
))
234 xMap
->putOpCode(aRes
, OpCode(nOp
));
236 // -----------------------------------------------------------------------------
238 const sal_Unicode
* lcl_UnicodeStrChr( const sal_Unicode
* pStr
,sal_Unicode c
)
250 // =============================================================================
252 // =============================================================================
254 void FormulaCompiler::OpCodeMap::putExternal( const String
& rSymbol
, const String
& rAddIn
)
256 bool bOk
= mpExternalHashMap
->insert( ExternalHashMap::value_type( rSymbol
, rAddIn
)).second
;
258 bOk
= mpReverseExternalHashMap
->insert( ExternalHashMap::value_type( rAddIn
, rSymbol
)).second
;
259 DBG_ASSERT( bOk
, "OpCodeMap::putExternal: symbol not inserted");
262 void FormulaCompiler::OpCodeMap::putExternalSoftly( const String
& rSymbol
, const String
& rAddIn
)
264 bool bOk
= mpReverseExternalHashMap
->insert( ExternalHashMap::value_type( rAddIn
, rSymbol
)).second
;
266 mpExternalHashMap
->insert( ExternalHashMap::value_type( rSymbol
, rAddIn
));
268 uno::Sequence
< sheet::FormulaToken
> FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(const FormulaCompiler
& _rCompiler
,const uno::Sequence
< ::rtl::OUString
>& rNames
) const
270 const sal_Int32 nLen
= rNames
.getLength();
271 uno::Sequence
< sheet::FormulaToken
> aTokens( nLen
);
272 sheet::FormulaToken
* pToken
= aTokens
.getArray();
273 ::rtl::OUString
const * pName
= rNames
.getConstArray();
274 ::rtl::OUString
const * const pStop
= pName
+ nLen
;
275 for ( ; pName
< pStop
; ++pName
, ++pToken
)
277 OpCodeHashMap::const_iterator
iLook( mpHashMap
->find( *pName
));
278 if (iLook
!= mpHashMap
->end())
279 pToken
->OpCode
= (*iLook
).second
;
282 ::rtl::OUString aIntName
;
285 ExternalHashMap::const_iterator
iExt( mpExternalHashMap
->find( *pName
));
286 if (iExt
!= mpExternalHashMap
->end())
287 aIntName
= (*iExt
).second
;
288 // Check for existence not needed here, only name-mapping is of
291 if (aIntName
.isEmpty())
292 aIntName
= _rCompiler
.FindAddInFunction(*pName
, !isEnglish()); // bLocalFirst=false for english
293 if (aIntName
.isEmpty())
294 pToken
->OpCode
= getOpCodeUnknown();
297 pToken
->OpCode
= ocExternal
;
298 pToken
->Data
<<= aIntName
;
304 uno::Sequence
< sheet::FormulaOpCodeMapEntry
> FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(const FormulaCompiler
& _rCompiler
,const sal_Int32 nGroups
) const
306 using namespace sheet
;
308 // Unfortunately uno::Sequence can't grow without cumbersome reallocs. As
309 // we don't know in advance how many elements it will have we use a
310 // temporary vector to add elements and then copy to Sequence :-(
311 ::std::vector
< FormulaOpCodeMapEntry
> aVec
;
313 if (nGroups
== FormulaMapGroup::SPECIAL
)
315 // Use specific order, keep in sync with
316 // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl
322 { FormulaMapGroupSpecialOffset::PUSH
, ocPush
} ,
323 { FormulaMapGroupSpecialOffset::CALL
, ocCall
} ,
324 { FormulaMapGroupSpecialOffset::STOP
, ocStop
} ,
325 { FormulaMapGroupSpecialOffset::EXTERNAL
, ocExternal
} ,
326 { FormulaMapGroupSpecialOffset::NAME
, ocName
} ,
327 { FormulaMapGroupSpecialOffset::NO_NAME
, ocNoName
} ,
328 { FormulaMapGroupSpecialOffset::MISSING
, ocMissing
} ,
329 { FormulaMapGroupSpecialOffset::BAD
, ocBad
} ,
330 { FormulaMapGroupSpecialOffset::SPACES
, ocSpaces
} ,
331 { FormulaMapGroupSpecialOffset::MAT_REF
, ocMatRef
} ,
332 { FormulaMapGroupSpecialOffset::DB_AREA
, ocDBArea
} ,
333 { FormulaMapGroupSpecialOffset::MACRO
, ocMacro
} ,
334 { FormulaMapGroupSpecialOffset::COL_ROW_NAME
, ocColRowName
}
336 const size_t nCount
= sizeof(aMap
)/sizeof(aMap
[0]);
337 // Preallocate vector elements.
338 if (aVec
.size() < nCount
)
340 FormulaOpCodeMapEntry aEntry
;
341 aEntry
.Token
.OpCode
= getOpCodeUnknown();
342 aVec
.resize( nCount
, aEntry
);
343 } // if (aVec.size() < nCount)
345 FormulaOpCodeMapEntry aEntry
;
346 for (size_t i
=0; i
< nCount
; ++i
)
348 size_t nIndex
= static_cast< size_t >( aMap
[i
].nOff
);
349 if (aVec
.size() <= nIndex
)
351 // The offsets really should be aligned with the size, so if
352 // the vector was preallocated above this code to resize it is
353 // just a measure in case the table isn't in sync with the API,
354 // usually it isn't executed.
355 aEntry
.Token
.OpCode
= getOpCodeUnknown();
356 aVec
.resize( nIndex
+ 1, aEntry
);
358 aEntry
.Token
.OpCode
= aMap
[i
].eOp
;
359 aVec
[nIndex
] = aEntry
;
364 /* FIXME: Once we support error constants in formulas we'll need a map
365 * group for that, e.g. FormulaMapGroup::ERROR_CONSTANTS, and fill
366 * SC_OPCODE_START_ERRORS to SC_OPCODE_STOP_ERRORS. */
368 // Anything else but SPECIAL.
369 if ((nGroups
& FormulaMapGroup::SEPARATORS
) != 0)
371 static const sal_uInt16 aOpCodes
[] = {
376 lclPushOpCodeMapEntries( aVec
, mpTable
, aOpCodes
, sizeof(aOpCodes
)/sizeof(aOpCodes
[0]) );
378 if ((nGroups
& FormulaMapGroup::ARRAY_SEPARATORS
) != 0)
380 static const sal_uInt16 aOpCodes
[] = {
381 SC_OPCODE_ARRAY_OPEN
,
382 SC_OPCODE_ARRAY_CLOSE
,
383 SC_OPCODE_ARRAY_ROW_SEP
,
384 SC_OPCODE_ARRAY_COL_SEP
386 lclPushOpCodeMapEntries( aVec
, mpTable
, aOpCodes
, sizeof(aOpCodes
)/sizeof(aOpCodes
[0]) );
388 if ((nGroups
& FormulaMapGroup::UNARY_OPERATORS
) != 0)
390 // Due to the nature of the percent operator following its operand
391 // it isn't sorted into unary operators for compiler interna.
392 lclPushOpCodeMapEntry( aVec
, mpTable
, ocPercentSign
);
393 // "+" can be used as unary operator too, push only if binary group is not set
394 if ((nGroups
& FormulaMapGroup::BINARY_OPERATORS
) == 0)
395 lclPushOpCodeMapEntry( aVec
, mpTable
, ocAdd
);
396 // regular unary operators
397 for (sal_uInt16 nOp
= SC_OPCODE_START_UN_OP
; nOp
< SC_OPCODE_STOP_UN_OP
&& nOp
< mnSymbols
; ++nOp
)
401 // NOT and NEG in fact are functions but for legacy reasons
402 // are sorted into unary operators for compiler interna.
407 lclPushOpCodeMapEntry( aVec
, mpTable
, nOp
);
411 if ((nGroups
& FormulaMapGroup::BINARY_OPERATORS
) != 0)
413 for (sal_uInt16 nOp
= SC_OPCODE_START_BIN_OP
; nOp
< SC_OPCODE_STOP_BIN_OP
&& nOp
< mnSymbols
; ++nOp
)
417 // AND and OR in fact are functions but for legacy reasons
418 // are sorted into binary operators for compiler interna.
423 lclPushOpCodeMapEntry( aVec
, mpTable
, nOp
);
427 if ((nGroups
& FormulaMapGroup::FUNCTIONS
) != 0)
429 // Function names are not consecutive, skip the gaps between
430 // functions with no parameter, functions with 1 parameter
431 lclPushOpCodeMapEntries( aVec
, mpTable
, SC_OPCODE_START_NO_PAR
, ::std::min
< sal_uInt16
>( SC_OPCODE_STOP_NO_PAR
, mnSymbols
) );
432 lclPushOpCodeMapEntries( aVec
, mpTable
, SC_OPCODE_START_1_PAR
, ::std::min
< sal_uInt16
>( SC_OPCODE_STOP_1_PAR
, mnSymbols
) );
433 // Additional functions not within range of functions.
434 static const sal_uInt16 aOpCodes
[] = {
442 lclPushOpCodeMapEntries( aVec
, mpTable
, aOpCodes
, sizeof(aOpCodes
)/sizeof(aOpCodes
[0]) );
443 // functions with 2 or more parameters.
444 for (sal_uInt16 nOp
= SC_OPCODE_START_2_PAR
; nOp
< SC_OPCODE_STOP_2_PAR
&& nOp
< mnSymbols
; ++nOp
)
448 // NO_NAME is in SPECIAL.
449 case SC_OPCODE_NO_NAME
:
452 lclPushOpCodeMapEntry( aVec
, mpTable
, nOp
);
455 // If AddIn functions are present in this mapping, use them, and only those.
458 for (ExternalHashMap::const_iterator
it( mpExternalHashMap
->begin());it
!= mpExternalHashMap
->end(); ++it
)
460 FormulaOpCodeMapEntry aEntry
;
461 aEntry
.Name
= (*it
).first
;
462 aEntry
.Token
.Data
<<= ::rtl::OUString( (*it
).second
);
463 aEntry
.Token
.OpCode
= ocExternal
;
464 aVec
.push_back( aEntry
);
469 _rCompiler
.fillAddInToken(aVec
,isEnglish());
473 const FormulaOpCodeMapEntry
* pRet
= aVec
.empty() ? 0 : &aVec
[0];
474 return uno::Sequence
< FormulaOpCodeMapEntry
>(pRet
, aVec
.size());
476 //-----------------------------------------------------------------------------
478 void FormulaCompiler::OpCodeMap::putOpCode( const String
& rStr
, const OpCode eOp
)
480 DBG_ASSERT( 0 < eOp
&& sal_uInt16(eOp
) < mnSymbols
, "OpCodeMap::putOpCode: OpCode out of range");
481 if (0 < eOp
&& sal_uInt16(eOp
) < mnSymbols
)
483 DBG_ASSERT( (mpTable
[eOp
].Len() == 0) || (mpTable
[eOp
] == rStr
) ||
484 (eOp
== ocCurrency
) || (eOp
== ocSep
) || (eOp
== ocArrayColSep
) ||
485 (eOp
== ocArrayRowSep
),
487 RTL_CONSTASCII_STRINGPARAM("OpCodeMap::putOpCode: reusing OpCode ")).
488 append(sal_Int32(eOp
)).append(RTL_CONSTASCII_STRINGPARAM(" (")).
489 append(rtl::OUStringToOString(rStr
, RTL_TEXTENCODING_ASCII_US
)).
490 append(')').getStr());
492 mpHashMap
->insert( OpCodeHashMap::value_type( rStr
, eOp
));
495 // -----------------------------------------------------------------------------
496 // class FormulaCompiler
497 // -----------------------------------------------------------------------------
498 DBG_NAME(FormulaCompiler
)
499 FormulaCompiler::FormulaCompiler(FormulaTokenArray
& _rArr
)
505 nNumFmt( NUMBERFORMAT_UNDEFINED
),
506 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED
),
507 bAutoCorrect( false ),
509 bCompileForFAP( false ),
510 bIgnoreErrors( false )
513 DBG_CTOR(FormulaCompiler
,NULL
);
515 FormulaCompiler::FormulaCompiler()
521 nNumFmt( NUMBERFORMAT_UNDEFINED
),
522 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED
),
523 bAutoCorrect( false ),
525 bCompileForFAP( false ),
526 bIgnoreErrors( false )
529 DBG_CTOR(FormulaCompiler
,NULL
);
531 FormulaCompiler::~FormulaCompiler()
533 DBG_DTOR(FormulaCompiler
,NULL
);
536 FormulaCompiler::OpCodeMapPtr
FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage
) const
538 FormulaCompiler::OpCodeMapPtr xMap
;
539 using namespace sheet
;
542 case FormulaLanguage::ODFF
:
545 xMap
= mxSymbolsODFF
;
547 case FormulaLanguage::ODF_11
:
550 xMap
= mxSymbolsPODF
;
552 case FormulaLanguage::ENGLISH
:
553 if (!mxSymbolsEnglish
)
554 InitSymbolsEnglish();
555 xMap
= mxSymbolsEnglish
;
557 case FormulaLanguage::NATIVE
:
558 if (!mxSymbolsNative
)
560 xMap
= mxSymbolsNative
;
562 case FormulaLanguage::XL_ENGLISH
:
563 if (!mxSymbolsEnglishXL
)
564 InitSymbolsEnglishXL();
565 xMap
= mxSymbolsEnglishXL
;
568 ; // nothing, NULL map returned
572 // -----------------------------------------------------------------------------
574 String
FormulaCompiler::FindAddInFunction( const String
& /*rUpperName*/, bool /*bLocalFirst*/ ) const
578 // -----------------------------------------------------------------------------
579 FormulaCompiler::OpCodeMapPtr
FormulaCompiler::CreateOpCodeMap(
581 const sheet::FormulaOpCodeMapEntry
> & rMapping
,
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
)
591 OpCode eOp
= OpCode(pArr2
->Token
.OpCode
);
592 if (eOp
!= ocExternal
)
593 xMap
->putOpCode( pArr2
->Name
, eOp
);
596 ::rtl::OUString aExternalName
;
597 if (pArr2
->Token
.Data
>>= aExternalName
)
598 xMap
->putExternal( pArr2
->Name
, aExternalName
);
601 SAL_WARN( "formula.core", "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
608 // -----------------------------------------------------------------------------
609 void lcl_fillNativeSymbols(FormulaCompiler::NonConstOpCodeMapPtr
& _xMap
,bool _destroy
= false)
611 static FormulaCompiler::NonConstOpCodeMapPtr s_SymbolMap
;
616 else if ( !s_SymbolMap
.get() )
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() )
626 // -----------------------------------------------------------------------------
627 const String
& FormulaCompiler::GetNativeSymbol( OpCode eOp
)
629 NonConstOpCodeMapPtr xSymbolsNative
;
630 lcl_fillNativeSymbols(xSymbolsNative
);
631 return xSymbolsNative
->getSymbol( eOp
);
633 // -----------------------------------------------------------------------------
634 void FormulaCompiler::InitSymbolsNative() const
636 lcl_fillNativeSymbols(mxSymbolsNative
);
638 // -----------------------------------------------------------------------------
639 void FormulaCompiler::InitSymbolsEnglish() const
641 static NonConstOpCodeMapPtr s_sSymbol
;
642 if ( !s_sSymbol
.get() )
643 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH
,FormulaGrammar::GRAM_ENGLISH
,s_sSymbol
);
644 mxSymbolsEnglish
= s_sSymbol
;
646 // -----------------------------------------------------------------------------
647 void FormulaCompiler::InitSymbolsPODF() const
649 static NonConstOpCodeMapPtr s_sSymbol
;
650 if ( !s_sSymbol
.get() )
651 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH
,FormulaGrammar::GRAM_PODF
,s_sSymbol
);
652 mxSymbolsPODF
= s_sSymbol
;
654 // -----------------------------------------------------------------------------
655 void FormulaCompiler::InitSymbolsODFF() const
657 static NonConstOpCodeMapPtr s_sSymbol
;
658 if ( !s_sSymbol
.get() )
659 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF
,FormulaGrammar::GRAM_ODFF
,s_sSymbol
);
660 mxSymbolsODFF
= s_sSymbol
;
662 // -----------------------------------------------------------------------------
663 void FormulaCompiler::InitSymbolsEnglishXL() const
665 static NonConstOpCodeMapPtr s_sSymbol
;
666 if ( !s_sSymbol
.get() )
667 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH
,FormulaGrammar::GRAM_ENGLISH
,s_sSymbol
);
668 mxSymbolsEnglishXL
= s_sSymbol
;
670 // TODO: For now, just replace the separators to the Excel English
671 // variants. Later, if we want to properly map Excel functions with Calc
672 // functions, we'll need to do a little more work here.
673 mxSymbolsEnglishXL
->putOpCode(rtl::OUString(','), ocSep
);
674 mxSymbolsEnglishXL
->putOpCode(rtl::OUString(','), ocArrayColSep
);
675 mxSymbolsEnglishXL
->putOpCode(rtl::OUString(';'), ocArrayRowSep
);
678 // -----------------------------------------------------------------------------
679 void FormulaCompiler::loadSymbols(sal_uInt16 _nSymbols
,FormulaGrammar::Grammar _eGrammar
,NonConstOpCodeMapPtr
& _xMap
) const
684 _xMap
.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID
+ 1, _eGrammar
!= FormulaGrammar::GRAM_ODFF
, _eGrammar
));
685 OModuleClient aModuleClient
;
686 OpCodeList
aOpCodeList( _nSymbols
, _xMap
);
688 fillFromAddInMap( _xMap
, _eGrammar
);
689 // Fill from collection for AddIns not already present.
690 if ( FormulaGrammar::GRAM_ENGLISH
!= _eGrammar
)
691 fillFromAddInCollectionUpperName( _xMap
);
693 fillFromAddInCollectionEnglishName( _xMap
);
696 // -----------------------------------------------------------------------------
697 void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr
/*xMap */) const
700 // -----------------------------------------------------------------------------
701 void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr
/*xMap */) const
704 // -----------------------------------------------------------------------------
705 void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr
/*xMap*/, FormulaGrammar::Grammar
/*_eGrammar */) const
708 // -----------------------------------------------------------------------------
709 OpCode
FormulaCompiler::GetEnglishOpCode( const String
& rName
) const
711 FormulaCompiler::OpCodeMapPtr xMap
= GetOpCodeMap(sheet::FormulaLanguage::ENGLISH
);
713 formula::OpCodeHashMap::const_iterator
iLook( xMap
->getHashMap()->find( rName
) );
714 bool bFound
= (iLook
!= xMap
->getHashMap()->end());
715 return bFound
? (*iLook
).second
: OpCode(ocNone
);
718 bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp
)
730 // more than one parameters:
731 // ocIndirect/ocIndirectXL otherwise would have to do
732 // StopListening and StartListening on a reference for every
733 // interpreted value.
736 // ocOffset results in indirect references.
747 // Remove quotes, escaped quotes are unescaped.
748 bool FormulaCompiler::DeQuote( String
& rStr
)
750 xub_StrLen nLen
= rStr
.Len();
751 if ( nLen
> 1 && rStr
.GetChar(0) == '\'' && rStr
.GetChar( nLen
-1 ) == '\'' )
753 rStr
.Erase( nLen
-1, 1 );
756 while ( (nPos
= rStr
.SearchAscii( "\\\'", nPos
)) != STRING_NOTFOUND
)
758 rStr
.Erase( nPos
, 1 );
765 // -----------------------------------------------------------------------------
766 void FormulaCompiler::fillAddInToken(::std::vector
< sheet::FormulaOpCodeMapEntry
>& /*_rVec*/,bool /*_bIsEnglish*/) const
769 // -----------------------------------------------------------------------------
770 bool FormulaCompiler::IsMatrixFunction(OpCode _eOpCode
)
787 // added to avoid warnings
793 // -----------------------------------------------------------------------------
794 FormulaCompiler::OpCodeMap::~OpCodeMap()
796 delete mpReverseExternalHashMap
;
797 delete mpExternalHashMap
;
801 // -----------------------------------------------------------------------------
802 void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap
& r
)
805 mpHashMap
= new OpCodeHashMap(mnSymbols
);
807 sal_uInt16 n
= r
.getSymbolCount();
808 for (sal_uInt16 i
= 0; i
< n
; ++i
)
810 OpCode eOp
= OpCode(i
);
811 const String
& rSymbol
= r
.getSymbol(eOp
);
812 putOpCode(rSymbol
, eOp
);
815 // TODO: maybe copy the external maps too?
817 // -----------------------------------------------------------------------------
819 sal_uInt16
FormulaCompiler::GetErrorConstant( const String
& rName
)
821 sal_uInt16 nError
= 0;
822 OpCodeHashMap::const_iterator
iLook( mxSymbols
->getHashMap()->find( rName
));
823 if (iLook
!= mxSymbols
->getHashMap()->end())
825 switch ((*iLook
).second
)
827 // Not all may make sense in a formula, but these we know as
833 nError
= errDivisionByZero
;
845 nError
= errIllegalFPOperation
;
848 nError
= NOTAVAILABLE
;
858 void FormulaCompiler::AppendErrorConstant( rtl::OUStringBuffer
& rBuffer
, sal_uInt16 nError
)
867 case errDivisionByZero
:
879 case errIllegalFPOperation
:
886 rBuffer
.append( mxSymbols
->getSymbol( eOp
));
889 // -----------------------------------------------------------------------------
890 sal_Int32
FormulaCompiler::OpCodeMap::getOpCodeUnknown()
892 static const sal_Int32 kOpCodeUnknown
= -1;
893 return kOpCodeUnknown
;
895 // -----------------------------------------------------------------------------
896 bool FormulaCompiler::GetToken()
898 static const short nRecursionMax
= 42;
899 FormulaCompilerRecursionGuard
aRecursionGuard( nRecursion
);
900 if ( nRecursion
> nRecursionMax
)
902 SetError( errStackOverflow
);
903 mpToken
= new FormulaByteToken( ocStop
);
906 if ( bAutoCorrect
&& !pStack
)
907 { // don't merge stacked subroutine code into entered formula
908 aCorrectedFormula
+= aCorrectedSymbol
;
909 aCorrectedSymbol
.Erase();
912 if( pArr
->GetCodeError() && !bIgnoreErrors
)
916 short nWasColRowName
;
918 && pArr
->pCode
[ pArr
->nIndex
-1 ]->GetOpCode() == ocColRowName
)
922 mpToken
= pArr
->Next();
923 while( mpToken
&& mpToken
->GetOpCode() == ocSpaces
)
925 if ( nWasColRowName
)
927 if ( bAutoCorrect
&& !pStack
)
928 CreateStringFromToken( aCorrectedFormula
, mpToken
.get(), false );
929 mpToken
= pArr
->Next();
931 if ( bAutoCorrect
&& !pStack
&& mpToken
)
932 CreateStringFromToken( aCorrectedSymbol
, mpToken
.get(), false );
945 if ( nWasColRowName
>= 2 && mpToken
->GetOpCode() == ocColRowName
)
946 { // convert an ocSpaces to ocIntersect in RPN
947 mpToken
= new FormulaByteToken( ocIntersect
);
948 pArr
->nIndex
--; // we advanced to the second ocColRowName, step back
954 mpToken
= new FormulaByteToken( ocStop
);
957 if( mpToken
->GetOpCode() == ocSubTotal
)
959 else if ( mpToken
->IsExternalRef() )
961 return HandleExternalReference(*mpToken
);
963 else if( mpToken
->GetOpCode() == ocName
)
965 return HandleRange();
967 else if( mpToken
->GetOpCode() == ocColRowName
)
969 return HandleSingleRef();
971 else if( mpToken
->GetOpCode() == ocDBArea
)
973 return HandleDbData();
975 else if( mpToken
->GetType() == svSingleRef
)
979 else if( mpToken
->GetType() == svDoubleRef
)
985 //---------------------------------------------------------------------------
986 // RPN creation by recursion
987 //---------------------------------------------------------------------------
989 void FormulaCompiler::Factor()
991 if ( pArr
->GetCodeError() && !bIgnoreErrors
)
994 CurrentFactor
pFacToken( this );
996 OpCode eOp
= mpToken
->GetOpCode();
997 if( eOp
== ocPush
|| eOp
== ocColRowNameAuto
|| eOp
== ocMatRef
||
999 || (bCompileForFAP
&& ((eOp
== ocName
) || (eOp
== ocDBArea
)
1000 || (eOp
== ocColRowName
) || (eOp
== ocBad
)))
1007 // PUSH( is an error that may be caused by an unknown function.
1009 ( mpToken
->GetType() == svString
1010 || mpToken
->GetType() == svSingleRef
)
1011 ? errNoName
: errOperatorExpected
);
1012 if ( bAutoCorrect
&& !pStack
)
1013 { // assume multiplication
1014 aCorrectedFormula
+= mxSymbols
->getSymbol(ocMul
);
1018 if( eOp
!= ocClose
)
1019 SetError(errPairExpected
);
1025 else if( eOp
== ocOpen
)
1029 while ((eOp
== ocSep
) && (!pArr
->GetCodeError() || bIgnoreErrors
))
1030 { // range list (A1;A2) converted to (A1~A2)
1031 pFacToken
= mpToken
;
1034 // Do not ignore error here, regardless of bIgnoreErrors, otherwise
1035 // errors like =(1;) would also result in display of =(1~)
1036 if (!pArr
->GetCodeError())
1038 pFacToken
->NewOpCode( ocUnion
,FormulaToken::PrivateAccess());
1039 PutCode( pFacToken
);
1043 SetError(errPairExpected
);
1049 if( nNumFmt
== NUMBERFORMAT_UNDEFINED
)
1050 nNumFmt
= lcl_GetRetFormat( eOp
);
1052 if ( IsOpCodeVolatile(eOp
) )
1053 pArr
->SetRecalcModeAlways();
1058 // Functions recalculated on every document load.
1059 // Don't use SetRecalcModeOnLoad() which would override
1062 pArr
->AddRecalcMode( RECALCMODE_ONLOAD
);
1064 // If the referred cell is moved the value changes.
1067 // ocCell needs recalc on move for some possible type values.
1069 pArr
->SetRecalcModeOnRefMove();
1072 // cell with hyperlink needs to be calculated on load to
1073 // get its matrix result generated.
1074 pArr
->SetRecalcModeOnLoad();
1075 pArr
->SetHyperLink(true);
1081 if (SC_OPCODE_START_NO_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_NO_PAR
)
1083 pFacToken
= mpToken
;
1087 SetError(errPairExpected
);
1088 PutCode( pFacToken
);
1094 SetError(errPairExpected
);
1099 // special cases NOT() and NEG()
1100 else if( eOp
== ocNot
|| eOp
== ocNeg
1101 || (SC_OPCODE_START_1_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_1_PAR
) )
1103 pFacToken
= mpToken
;
1105 if( nNumFmt
== NUMBERFORMAT_UNDEFINED
&& eOp
== ocNot
)
1106 nNumFmt
= NUMBERFORMAT_LOGICAL
;
1113 SetError(errPairExpected
);
1115 SetError(errPairExpected
);
1116 else if ( !pArr
->GetCodeError() )
1117 pFacToken
->SetByte( 1 );
1118 PutCode( pFacToken
);
1121 else if ((SC_OPCODE_START_2_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_2_PAR
)
1122 || eOp
== ocExternal
1127 || ( eOp
>= ocInternalBegin
&& eOp
<= ocInternalEnd
)
1128 || (bCompileForFAP
&& ((eOp
== ocIf
) || (eOp
== ocChose
)))
1131 pFacToken
= mpToken
;
1132 OpCode eMyLastOp
= eOp
;
1134 bool bNoParam
= false;
1135 bool bBadName
= false;
1144 else if (eMyLastOp
== ocBad
)
1146 // Just a bad name, not an unknown function, no parameters, no
1147 // closing expected.
1152 SetError(errPairExpected
);
1153 sal_uInt8 nSepCount
= 0;
1157 while ( (eOp
== ocSep
) && (!pArr
->GetCodeError() || bIgnoreErrors
) )
1165 ; // nothing, keep current token for return
1166 else if (eOp
!= ocClose
)
1167 SetError(errPairExpected
);
1170 // Jumps are just normal functions for the FunctionAutoPilot tree view
1171 if ( bCompileForFAP
&& pFacToken
->GetType() == svJump
)
1172 pFacToken
= new FormulaFAPToken( pFacToken
->GetOpCode(), nSepCount
, pFacToken
);
1174 pFacToken
->SetByte( nSepCount
);
1175 PutCode( pFacToken
);
1177 else if (eOp
== ocIf
|| eOp
== ocChose
)
1179 // the PC counters are -1
1180 pFacToken
= mpToken
;
1182 pFacToken
->GetJump()[ 0 ] = 3; // if, else, behind
1184 pFacToken
->GetJump()[ 0 ] = MAXJUMPCOUNT
+1;
1192 SetError(errPairExpected
);
1193 short nJumpCount
= 0;
1194 PutCode( pFacToken
);
1195 // during AutoCorrect (since pArr->GetCodeError() is
1196 // ignored) an unlimited ocIf would crash because
1197 // ScRawToken::Clone() allocates the JumpBuffer according to
1198 // nJump[0]*2+2, which is 3*2+2 on ocIf.
1199 const short nJumpMax
=
1200 (pFacToken
->GetOpCode() == ocIf
? 3 : MAXJUMPCOUNT
);
1201 while ( (nJumpCount
< (MAXJUMPCOUNT
- 1)) && (eOp
== ocSep
)
1202 && (!pArr
->GetCodeError() || bIgnoreErrors
) )
1204 if ( ++nJumpCount
<= nJumpMax
)
1205 pFacToken
->GetJump()[nJumpCount
] = pc
-1;
1208 // ocSep or ocClose terminate the subexpression
1212 SetError(errPairExpected
);
1216 // always limit to nJumpMax, no arbitrary overwrites
1217 if ( ++nJumpCount
<= nJumpMax
)
1218 pFacToken
->GetJump()[ nJumpCount
] = pc
-1;
1219 if ((pFacToken
->GetOpCode() == ocIf
&& (nJumpCount
> 3)) ||
1220 (nJumpCount
>= MAXJUMPCOUNT
))
1221 SetError(errIllegalParameter
);
1223 pFacToken
->GetJump()[ 0 ] = nJumpCount
;
1226 else if ( eOp
== ocMissing
)
1231 else if ( eOp
== ocClose
)
1233 SetError( errParameterExpected
);
1235 else if ( eOp
== ocSep
)
1236 { // Subsequent ocSep
1237 SetError( errParameterExpected
);
1238 if ( bAutoCorrect
&& !pStack
)
1240 aCorrectedSymbol
.Erase();
1244 else if ( mpToken
->IsExternalRef() )
1251 SetError( errUnknownToken
);
1252 if ( bAutoCorrect
&& !pStack
)
1254 if ( eOp
== ocStop
)
1255 { // trailing operator w/o operand
1256 xub_StrLen nLen
= aCorrectedFormula
.Len();
1258 aCorrectedFormula
.Erase( nLen
- 1 );
1259 aCorrectedSymbol
.Erase();
1267 //---------------------------------------------------------------------------
1269 void FormulaCompiler::RangeLine()
1272 while (mpToken
->GetOpCode() == ocRange
)
1274 FormulaToken
** pCode1
= pCode
- 1;
1275 FormulaTokenRef p
= mpToken
;
1278 FormulaToken
** pCode2
= pCode
- 1;
1279 if (!MergeRangeReference( pCode1
, pCode2
))
1284 //---------------------------------------------------------------------------
1286 void FormulaCompiler::IntersectionLine()
1289 while (mpToken
->GetOpCode() == ocIntersect
)
1291 FormulaTokenRef p
= mpToken
;
1298 //---------------------------------------------------------------------------
1300 void FormulaCompiler::UnionLine()
1303 while (mpToken
->GetOpCode() == ocUnion
)
1305 FormulaTokenRef p
= mpToken
;
1312 //---------------------------------------------------------------------------
1314 void FormulaCompiler::UnaryLine()
1316 if( mpToken
->GetOpCode() == ocAdd
)
1318 else if (SC_OPCODE_START_UN_OP
<= mpToken
->GetOpCode() &&
1319 mpToken
->GetOpCode() < SC_OPCODE_STOP_UN_OP
)
1321 FormulaTokenRef p
= mpToken
;
1330 //---------------------------------------------------------------------------
1332 void FormulaCompiler::PostOpLine()
1335 while ( mpToken
->GetOpCode() == ocPercentSign
)
1336 { // this operator _follows_ its operand
1342 //---------------------------------------------------------------------------
1344 void FormulaCompiler::PowLine()
1347 while (mpToken
->GetOpCode() == ocPow
)
1349 FormulaTokenRef p
= mpToken
;
1356 //---------------------------------------------------------------------------
1358 void FormulaCompiler::MulDivLine()
1361 while (mpToken
->GetOpCode() == ocMul
|| mpToken
->GetOpCode() == ocDiv
)
1363 FormulaTokenRef p
= mpToken
;
1370 //---------------------------------------------------------------------------
1372 void FormulaCompiler::AddSubLine()
1375 while (mpToken
->GetOpCode() == ocAdd
|| mpToken
->GetOpCode() == ocSub
)
1377 FormulaTokenRef p
= mpToken
;
1384 //---------------------------------------------------------------------------
1386 void FormulaCompiler::ConcatLine()
1389 while (mpToken
->GetOpCode() == ocAmpersand
)
1391 FormulaTokenRef p
= mpToken
;
1398 //---------------------------------------------------------------------------
1400 void FormulaCompiler::CompareLine()
1403 while (mpToken
->GetOpCode() >= ocEqual
&& mpToken
->GetOpCode() <= ocGreaterEqual
)
1405 FormulaTokenRef p
= mpToken
;
1412 //---------------------------------------------------------------------------
1414 void FormulaCompiler::NotLine()
1417 while (mpToken
->GetOpCode() == ocNot
)
1419 FormulaTokenRef p
= mpToken
;
1426 //---------------------------------------------------------------------------
1428 OpCode
FormulaCompiler::Expression()
1430 static const short nRecursionMax
= 42;
1431 FormulaCompilerRecursionGuard
aRecursionGuard( nRecursion
);
1432 if ( nRecursion
> nRecursionMax
)
1434 SetError( errStackOverflow
);
1435 return ocStop
; //! generate token instead?
1438 while (mpToken
->GetOpCode() == ocAnd
|| mpToken
->GetOpCode() == ocOr
)
1440 FormulaTokenRef p
= mpToken
;
1441 mpToken
->SetByte( 2 ); // 2 parameters!
1446 return mpToken
->GetOpCode();
1448 // -----------------------------------------------------------------------------
1449 void FormulaCompiler::SetError(sal_uInt16
/*nError*/)
1452 // -----------------------------------------------------------------------------
1453 FormulaTokenRef
FormulaCompiler::ExtendRangeReference( FormulaToken
& /*rTok1*/, FormulaToken
& /*rTok2*/, bool /*bReuseDoubleRef*/ )
1455 return FormulaTokenRef();
1457 // -----------------------------------------------------------------------------
1458 bool FormulaCompiler::MergeRangeReference(FormulaToken
* * const pCode1
, FormulaToken
* const * const pCode2
)
1460 FormulaToken
*p1
, *p2
;
1461 if (pc
< 2 || !pCode1
|| !pCode2
||
1462 (pCode2
- pCode1
!= 1) || (pCode
- pCode2
!= 1) ||
1463 ((p1
= *pCode1
) == 0) || ((p2
= *pCode2
) == 0) )
1466 FormulaTokenRef p
= ExtendRangeReference( *p1
, *p2
, true);
1479 // -----------------------------------------------------------------------------
1480 bool FormulaCompiler::CompileTokenArray()
1484 if( !pArr
->GetCodeError() || bIgnoreErrors
)
1488 aCorrectedFormula
.Erase();
1489 aCorrectedSymbol
.Erase();
1491 pArr
->nRefs
= 0; // count from start
1494 FormulaToken
* pData
[ MAXCODE
];
1496 bool bWasForced
= pArr
->IsRecalcModeForced();
1500 aCorrectedFormula
= '=';
1502 pArr
->ClearRecalcMode();
1507 OpCode eOp
= Expression();
1508 // Some trailing garbage that doesn't form an expression?
1510 SetError( errOperatorExpected
);
1512 sal_uInt16 nErrorBeforePop
= pArr
->GetCodeError();
1518 pArr
->pRPN
= new FormulaToken
*[ pc
];
1520 memcpy( pArr
->pRPN
, pData
, pc
* sizeof( FormulaToken
* ) );
1523 // once an error, always an error
1524 if( !pArr
->GetCodeError() && nErrorBeforePop
)
1525 pArr
->SetCodeError( nErrorBeforePop
);
1527 if( pArr
->GetCodeError() && !bIgnoreErrors
)
1530 pArr
->SetHyperLink(false);
1534 pArr
->SetRecalcModeForced();
1536 if( nNumFmt
== NUMBERFORMAT_UNDEFINED
)
1537 nNumFmt
= NUMBERFORMAT_NUMBER
;
1540 // -----------------------------------------------------------------------------
1541 void FormulaCompiler::PopTokenArray()
1545 FormulaArrayStack
* p
= pStack
;
1547 p
->pArr
->nRefs
= sal::static_int_cast
<short>( p
->pArr
->nRefs
+ pArr
->nRefs
);
1548 // obtain special RecalcMode from SharedFormula
1549 if ( pArr
->IsRecalcModeAlways() )
1550 p
->pArr
->SetRecalcModeAlways();
1551 else if ( !pArr
->IsRecalcModeNormal() && p
->pArr
->IsRecalcModeNormal() )
1552 p
->pArr
->SetMaskedRecalcMode( pArr
->GetRecalcMode() );
1553 p
->pArr
->SetCombinedBitsRecalcMode( pArr
->GetRecalcMode() );
1560 // -----------------------------------------------------------------------------
1561 void FormulaCompiler::CreateStringFromTokenArray( String
& rFormula
)
1563 rtl::OUStringBuffer
aBuffer( pArr
->GetLen() * 5 );
1564 CreateStringFromTokenArray( aBuffer
);
1565 rFormula
= aBuffer
.makeStringAndClear();
1568 void FormulaCompiler::CreateStringFromTokenArray( rtl::OUStringBuffer
& rBuffer
)
1570 rBuffer
.setLength(0);
1571 if( !pArr
->GetLen() )
1574 FormulaTokenArray
* pSaveArr
= pArr
;
1575 bool bODFF
= FormulaGrammar::isODFF( meGrammar
);
1576 if (bODFF
|| FormulaGrammar::isPODF( meGrammar
) )
1578 // Scan token array for missing args and re-write if present.
1579 MissingConvention
aConv( bODFF
);
1580 if (pArr
->NeedsPofRewrite( aConv
))
1581 pArr
= pArr
->RewriteMissingToPof( aConv
);
1584 // At least one character per token, plus some are references, some are
1585 // function names, some are numbers, ...
1586 rBuffer
.ensureCapacity( pArr
->GetLen() * 5 );
1588 if ( pArr
->IsRecalcModeForced() )
1589 rBuffer
.append(sal_Unicode('='));
1590 FormulaToken
* t
= pArr
->First();
1592 t
= CreateStringFromToken( rBuffer
, t
, true );
1594 if (pSaveArr
!= pArr
)
1600 // -----------------------------------------------------------------------------
1601 FormulaToken
* FormulaCompiler::CreateStringFromToken( String
& rFormula
, FormulaToken
* pTokenP
,bool bAllowArrAdvance
)
1603 rtl::OUStringBuffer aBuffer
;
1604 FormulaToken
* p
= CreateStringFromToken( aBuffer
, pTokenP
, bAllowArrAdvance
);
1605 rFormula
+= aBuffer
.makeStringAndClear();
1609 FormulaToken
* FormulaCompiler::CreateStringFromToken( rtl::OUStringBuffer
& rBuffer
, FormulaToken
* pTokenP
,bool bAllowArrAdvance
)
1612 bool bSpaces
= false;
1613 FormulaToken
* t
= pTokenP
;
1614 OpCode eOp
= t
->GetOpCode();
1615 if( eOp
>= ocAnd
&& eOp
<= ocOr
)
1618 if ( bAllowArrAdvance
)
1621 t
= pArr
->PeekNext();
1623 bSpaces
= ( !t
|| t
->GetOpCode() != ocOpen
);
1626 rBuffer
.append(sal_Unicode(' '));
1628 if( eOp
== ocSpaces
)
1630 bool bIntersectionOp
= mxSymbols
->isODFF();
1631 if (bIntersectionOp
)
1633 const FormulaToken
* p
= pArr
->PeekPrevNoSpaces();
1634 bIntersectionOp
= (p
&& p
->GetOpCode() == ocColRowName
);
1635 if (bIntersectionOp
)
1637 p
= pArr
->PeekNextNoSpaces();
1638 bIntersectionOp
= (p
&& p
->GetOpCode() == ocColRowName
);
1641 if (bIntersectionOp
)
1642 rBuffer
.appendAscii( "!!");
1645 // most times it's just one blank
1646 sal_uInt8 n
= t
->GetByte();
1647 for ( sal_uInt8 j
=0; j
<n
; ++j
)
1649 rBuffer
.append(sal_Unicode(' '));
1653 else if( eOp
>= ocInternalBegin
&& eOp
<= ocInternalEnd
)
1654 rBuffer
.appendAscii( pInternal
[ eOp
- ocInternalBegin
] );
1655 else if( (sal_uInt16
) eOp
< mxSymbols
->getSymbolCount()) // Keyword:
1656 rBuffer
.append(mxSymbols
->getSymbol(eOp
));
1659 SAL_WARN( "formula.core","unknown OpCode");
1660 rBuffer
.append(GetNativeSymbol( ocErrName
));
1664 if (t
->IsExternalRef())
1666 CreateStringFromExternal(rBuffer
, pTokenP
);
1670 switch( t
->GetType() )
1673 AppendDouble( rBuffer
, t
->GetDouble() );
1677 if( eOp
== ocBad
|| eOp
== ocStringXML
)
1678 rBuffer
.append(t
->GetString());
1680 AppendString( rBuffer
, t
->GetString() );
1683 CreateStringFromSingleRef(rBuffer
,t
);
1686 CreateStringFromDoubleRef(rBuffer
,t
);
1689 CreateStringFromMatrix( rBuffer
, t
);
1693 CreateStringFromIndex( rBuffer
, t
);
1697 // mapped or translated name of AddIns
1698 String
aAddIn( t
->GetExternal() );
1699 bool bMapped
= mxSymbols
->isPODF(); // ODF 1.1 directly uses programmatical name
1700 if (!bMapped
&& mxSymbols
->hasExternals())
1702 ExternalHashMap::const_iterator iLook
= mxSymbols
->getReverseExternalHashMap()->find( aAddIn
);
1703 if (iLook
!= mxSymbols
->getReverseExternalHashMap()->end())
1705 aAddIn
= (*iLook
).second
;
1709 if (!bMapped
&& !mxSymbols
->isEnglish())
1710 LocalizeString( aAddIn
);
1711 rBuffer
.append(aAddIn
);
1715 AppendErrorConstant( rBuffer
, t
->GetError());
1724 OSL_FAIL("FormulaCompiler:: GetStringFromToken errUnknownVariable");
1729 rBuffer
.append(sal_Unicode(' '));
1730 if ( bAllowArrAdvance
)
1738 // -----------------------------------------------------------------------------
1740 void FormulaCompiler::AppendDouble( rtl::OUStringBuffer
& rBuffer
, double fVal
)
1742 if ( mxSymbols
->isEnglish() )
1744 ::rtl::math::doubleToUStringBuffer( rBuffer
, fVal
,
1745 rtl_math_StringFormat_Automatic
,
1746 rtl_math_DecimalPlaces_Max
, '.', true );
1750 SvtSysLocale aSysLocale
;
1751 ::rtl::math::doubleToUStringBuffer( rBuffer
, fVal
,
1752 rtl_math_StringFormat_Automatic
,
1753 rtl_math_DecimalPlaces_Max
,
1754 aSysLocale
.GetLocaleDataPtr()->getNumDecimalSep()[0],
1758 // -----------------------------------------------------------------------------
1759 void FormulaCompiler::AppendBoolean( rtl::OUStringBuffer
& rBuffer
, bool bVal
)
1761 rBuffer
.append( mxSymbols
->getSymbol(static_cast<OpCode
>(bVal
? ocTrue
: ocFalse
)) );
1763 // -----------------------------------------------------------------------------
1764 void FormulaCompiler::AppendString( rtl::OUStringBuffer
& rBuffer
, const String
& rStr
)
1766 rBuffer
.append(sal_Unicode('"'));
1767 if ( lcl_UnicodeStrChr( rStr
.GetBuffer(), '"' ) == NULL
)
1768 rBuffer
.append( rStr
);
1771 String
aStr( rStr
);
1772 aStr
.SearchAndReplaceAll( rtl::OUString('"'), rtl::OUString("\"\"") );
1773 rBuffer
.append(aStr
);
1775 rBuffer
.append(sal_Unicode('"'));
1778 void FormulaCompiler::UpdateSeparatorsNative(
1779 const rtl::OUString
& rSep
, const rtl::OUString
& rArrayColSep
, const rtl::OUString
& rArrayRowSep
)
1781 NonConstOpCodeMapPtr xSymbolsNative
;
1782 lcl_fillNativeSymbols(xSymbolsNative
);
1783 xSymbolsNative
->putOpCode(rSep
, ocSep
);
1784 xSymbolsNative
->putOpCode(rArrayColSep
, ocArrayColSep
);
1785 xSymbolsNative
->putOpCode(rArrayRowSep
, ocArrayRowSep
);
1788 void FormulaCompiler::ResetNativeSymbols()
1790 NonConstOpCodeMapPtr xSymbolsNative
;
1791 lcl_fillNativeSymbols(xSymbolsNative
, true);
1792 lcl_fillNativeSymbols(xSymbolsNative
);
1795 void FormulaCompiler::SetNativeSymbols( const OpCodeMapPtr
& xMap
)
1797 NonConstOpCodeMapPtr xSymbolsNative
;
1798 lcl_fillNativeSymbols(xSymbolsNative
);
1799 xSymbolsNative
->copyFrom(*xMap
);
1802 // -----------------------------------------------------------------------------
1803 OpCode
FormulaCompiler::NextToken()
1807 OpCode eOp
= mpToken
->GetOpCode();
1808 // There must be an operator before a push
1809 if ( (eOp
== ocPush
|| eOp
== ocColRowNameAuto
) &&
1810 !( (eLastOp
== ocOpen
) || (eLastOp
== ocSep
) ||
1811 (SC_OPCODE_START_BIN_OP
<= eLastOp
&& eLastOp
< SC_OPCODE_STOP_UN_OP
)) )
1812 SetError(errOperatorExpected
);
1813 // Operator and Plus => operator
1814 if (eOp
== ocAdd
&& (eLastOp
== ocOpen
|| eLastOp
== ocSep
||
1815 (SC_OPCODE_START_BIN_OP
<= eLastOp
&& eLastOp
< SC_OPCODE_STOP_UN_OP
)))
1819 // Before an operator there must not be another operator, with the
1820 // exception of AND and OR.
1821 if ( eOp
!= ocAnd
&& eOp
!= ocOr
&&
1822 (SC_OPCODE_START_BIN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_BIN_OP
)
1823 && (eLastOp
== ocOpen
|| eLastOp
== ocSep
||
1824 (SC_OPCODE_START_BIN_OP
<= eLastOp
&& eLastOp
< SC_OPCODE_STOP_UN_OP
)))
1826 SetError(errVariableExpected
);
1827 if ( bAutoCorrect
&& !pStack
)
1829 if ( eOp
== eLastOp
|| eLastOp
== ocOpen
)
1830 { // throw away duplicated operator
1831 aCorrectedSymbol
.Erase();
1836 xub_StrLen nPos
= aCorrectedFormula
.Len();
1840 sal_Unicode c
= aCorrectedFormula
.GetChar( nPos
);
1844 if ( c
== mxSymbols
->getSymbol(ocEqual
).GetChar(0) )
1845 { // >= instead of =>
1846 aCorrectedFormula
.SetChar( nPos
,
1847 mxSymbols
->getSymbol(ocGreater
).GetChar(0) );
1848 aCorrectedSymbol
= c
;
1853 if ( c
== mxSymbols
->getSymbol(ocEqual
).GetChar(0) )
1854 { // <= instead of =<
1855 aCorrectedFormula
.SetChar( nPos
,
1856 mxSymbols
->getSymbol(ocLess
).GetChar(0) );
1857 aCorrectedSymbol
= c
;
1860 else if ( c
== mxSymbols
->getSymbol(ocGreater
).GetChar(0) )
1861 { // <> instead of ><
1862 aCorrectedFormula
.SetChar( nPos
,
1863 mxSymbols
->getSymbol(ocLess
).GetChar(0) );
1864 aCorrectedSymbol
= c
;
1869 if ( c
== mxSymbols
->getSymbol(ocSub
).GetChar(0) )
1870 { // *- instead of -*
1871 aCorrectedFormula
.SetChar( nPos
,
1872 mxSymbols
->getSymbol(ocMul
).GetChar(0) );
1873 aCorrectedSymbol
= c
;
1878 if ( c
== mxSymbols
->getSymbol(ocSub
).GetChar(0) )
1879 { // /- instead of -/
1880 aCorrectedFormula
.SetChar( nPos
,
1881 mxSymbols
->getSymbol(ocDiv
).GetChar(0) );
1882 aCorrectedSymbol
= c
;
1897 void FormulaCompiler::PutCode( FormulaTokenRef
& p
)
1899 if( pc
>= MAXCODE
-1 )
1901 if ( pc
== MAXCODE
-1 )
1903 p
= new FormulaByteToken( ocStop
);
1908 SetError(errCodeOverflow
);
1911 if( pArr
->GetCodeError() && !bCompileForFAP
)
1913 ForceArrayOperator( p
, pCurrentFactorToken
);
1919 // -----------------------------------------------------------------------------
1920 bool FormulaCompiler::HandleExternalReference(const FormulaToken
& /*_aToken*/)
1924 // -----------------------------------------------------------------------------
1925 bool FormulaCompiler::HandleRange()
1929 // -----------------------------------------------------------------------------
1930 bool FormulaCompiler::HandleSingleRef()
1934 // -----------------------------------------------------------------------------
1935 bool FormulaCompiler::HandleDbData()
1939 // -----------------------------------------------------------------------------
1940 void FormulaCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1943 // -----------------------------------------------------------------------------
1944 void FormulaCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1947 // -----------------------------------------------------------------------------
1948 void FormulaCompiler::CreateStringFromIndex(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1951 // -----------------------------------------------------------------------------
1952 void FormulaCompiler::CreateStringFromMatrix(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1955 // -----------------------------------------------------------------------------
1956 void FormulaCompiler::CreateStringFromExternal(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1959 // -----------------------------------------------------------------------------
1960 void FormulaCompiler::LocalizeString( String
& /*rName*/ )
1963 void FormulaCompiler::PushTokenArray( FormulaTokenArray
* pa
, bool bTemp
)
1965 if ( bAutoCorrect
&& !pStack
)
1966 { // don't merge stacked subroutine code into entered formula
1967 aCorrectedFormula
+= aCorrectedSymbol
;
1968 aCorrectedSymbol
.Erase();
1970 FormulaArrayStack
* p
= new FormulaArrayStack
;
1978 // =============================================================================
1980 // =============================================================================
1982 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */