1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tokenuno.hxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 #include "precompiled_formula.hxx"
31 #include "formula/FormulaCompiler.hxx"
32 #include "formula/errorcodes.hxx"
33 #include "formula/token.hxx"
34 #include "formula/tokenarray.hxx"
35 #include "core_resource.hxx"
36 #include "core_resource.hrc"
38 #include <svtools/zforlist.hxx>
39 #include <tools/rc.hxx>
40 #include <tools/rcid.h>
41 #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
42 #include <com/sun/star/sheet/FormulaMapGroup.hpp>
43 #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
46 // =============================================================================
49 // =============================================================================
50 using namespace ::com::sun::star
;
52 static const sal_Char
* pInternal
[ 5 ] = { "GAME", "SPEW", "TTT", "STARCALCTEAM", "ANTWORT" };
54 // =============================================================================
57 // =============================================================================
58 class FormulaCompilerRecursionGuard
63 FormulaCompilerRecursionGuard( short& rRec
)
64 : rRecursion( rRec
) { ++rRecursion
; }
65 ~FormulaCompilerRecursionGuard() { --rRecursion
; }
68 short lcl_GetRetFormat( OpCode eOpCode
)
96 return NUMBERFORMAT_LOGICAL
;
100 return NUMBERFORMAT_DATE
;
102 return NUMBERFORMAT_DATETIME
;
104 return NUMBERFORMAT_TIME
;
118 return NUMBERFORMAT_CURRENCY
;
126 return NUMBERFORMAT_PERCENT
;
133 return NUMBERFORMAT_NUMBER
;
135 return NUMBERFORMAT_NUMBER
;
138 inline void lclPushOpCodeMapEntry( ::std::vector
< sheet::FormulaOpCodeMapEntry
>& rVec
, const String
* pTable
, USHORT nOpCode
)
140 sheet::FormulaOpCodeMapEntry aEntry
;
141 aEntry
.Token
.OpCode
= nOpCode
;
142 aEntry
.Name
= pTable
[nOpCode
];
143 rVec
.push_back( aEntry
);
146 void lclPushOpCodeMapEntries( ::std::vector
< sheet::FormulaOpCodeMapEntry
>& rVec
, const String
* pTable
, USHORT nOpCodeBeg
, USHORT nOpCodeEnd
)
148 for (USHORT nOpCode
= nOpCodeBeg
; nOpCode
< nOpCodeEnd
; ++nOpCode
)
149 lclPushOpCodeMapEntry( rVec
, pTable
, nOpCode
);
152 void lclPushOpCodeMapEntries( ::std::vector
< sheet::FormulaOpCodeMapEntry
>& rVec
, const String
* pTable
, const USHORT
* pnOpCodes
, size_t nCount
)
154 for (const USHORT
* pnEnd
= pnOpCodes
+ nCount
; pnOpCodes
< pnEnd
; ++pnOpCodes
)
155 lclPushOpCodeMapEntry( rVec
, pTable
, *pnOpCodes
);
158 class OpCodeList
: public Resource
// temp object for resource
162 OpCodeList( USHORT
, FormulaCompiler::NonConstOpCodeMapPtr
);
165 bool getOpCodeString( String
& rStr
, USHORT nOp
);
166 void putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap
, USHORT nOp
);
174 SeparatorType meSepType
;
177 OpCodeList::OpCodeList( USHORT nRID
, FormulaCompiler::NonConstOpCodeMapPtr xMap
) :
178 Resource( ResId(nRID
,*ResourceManager::getResManager()) )
179 ,meSepType(SEMICOLON_BASE
)
181 for (USHORT i
= 0; i
<= SC_OPCODE_LAST_OPCODE_ID
; ++i
)
184 if ( getOpCodeString(aOpStr
, i
) )
185 xMap
->putOpCode(aOpStr
, OpCode(i
));
187 putDefaultOpCode(xMap
, i
);
193 bool OpCodeList::getOpCodeString( String
& rStr
, USHORT nOp
)
199 if (meSepType
== COMMA_BASE
)
201 rStr
= String::CreateFromAscii(",");
204 else if (meSepType
== SEMICOLON_BASE
)
206 rStr
= String::CreateFromAscii(";");
211 case SC_OPCODE_ARRAY_COL_SEP
:
213 if (meSepType
== COMMA_BASE
)
215 rStr
= String::CreateFromAscii(",");
218 else if (meSepType
== SEMICOLON_BASE
)
220 rStr
= String::CreateFromAscii(";");
225 case SC_OPCODE_ARRAY_ROW_SEP
:
227 if (meSepType
== COMMA_BASE
)
229 rStr
= String::CreateFromAscii(";");
232 else if (meSepType
== SEMICOLON_BASE
)
234 rStr
= String::CreateFromAscii("|");
244 void OpCodeList::putDefaultOpCode( FormulaCompiler::NonConstOpCodeMapPtr xMap
, USHORT nOp
)
246 ResId
aRes(nOp
,*ResourceManager::getResManager());
247 aRes
.SetRT(RSC_STRING
);
248 if (IsAvailableRes(aRes
))
249 xMap
->putOpCode(aRes
, OpCode(nOp
));
251 // -----------------------------------------------------------------------------
253 const sal_Unicode
* lcl_UnicodeStrChr( const sal_Unicode
* pStr
,sal_Unicode c
)
265 // =============================================================================
267 // =============================================================================
269 void FormulaCompiler::OpCodeMap::putExternal( const String
& rSymbol
, const String
& rAddIn
)
271 bool bOk
= mpExternalHashMap
->insert( ExternalHashMap::value_type( rSymbol
, rAddIn
)).second
;
273 bOk
= mpReverseExternalHashMap
->insert( ExternalHashMap::value_type( rAddIn
, rSymbol
)).second
;
274 DBG_ASSERT( bOk
, "OpCodeMap::putExternal: symbol not inserted");
277 void FormulaCompiler::OpCodeMap::putExternalSoftly( const String
& rSymbol
, const String
& rAddIn
)
279 bool bOk
= mpReverseExternalHashMap
->insert( ExternalHashMap::value_type( rAddIn
, rSymbol
)).second
;
281 mpExternalHashMap
->insert( ExternalHashMap::value_type( rSymbol
, rAddIn
)).second
;
283 uno::Sequence
< sheet::FormulaToken
> FormulaCompiler::OpCodeMap::createSequenceOfFormulaTokens(const FormulaCompiler
& _rCompiler
,const uno::Sequence
< ::rtl::OUString
>& rNames
) const
285 const sal_Int32 nLen
= rNames
.getLength();
286 uno::Sequence
< sheet::FormulaToken
> aTokens( nLen
);
287 sheet::FormulaToken
* pToken
= aTokens
.getArray();
288 ::rtl::OUString
const * pName
= rNames
.getConstArray();
289 ::rtl::OUString
const * const pStop
= pName
+ nLen
;
290 for ( ; pName
< pStop
; ++pName
, ++pToken
)
292 OpCodeHashMap::const_iterator
iLook( mpHashMap
->find( *pName
));
293 if (iLook
!= mpHashMap
->end())
294 pToken
->OpCode
= (*iLook
).second
;
297 ::rtl::OUString aIntName
;
300 ExternalHashMap::const_iterator
iExt( mpExternalHashMap
->find( *pName
));
301 if (iExt
!= mpExternalHashMap
->end())
302 aIntName
= (*iExt
).second
;
303 // Check for existence not needed here, only name-mapping is of
306 if (!aIntName
.getLength())
307 aIntName
= _rCompiler
.FindAddInFunction(*pName
, !isEnglish()); // bLocalFirst=FALSE for english
308 if (!aIntName
.getLength())
309 pToken
->OpCode
= getOpCodeUnknown();
312 pToken
->OpCode
= ocExternal
;
313 pToken
->Data
<<= aIntName
;
319 uno::Sequence
< sheet::FormulaOpCodeMapEntry
> FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings(const FormulaCompiler
& _rCompiler
,const sal_Int32 nGroups
) const
321 using namespace sheet
;
323 // Unfortunately uno::Sequence can't grow without cumbersome reallocs. As
324 // we don't know in advance how many elements it will have we use a
325 // temporary vector to add elements and then copy to Sequence :-(
326 ::std::vector
< FormulaOpCodeMapEntry
> aVec
;
328 if (nGroups
== FormulaMapGroup::SPECIAL
)
330 // Use specific order, keep in sync with
331 // offapi/com/sun/star/sheet/FormulaMapGroupSpecialOffset.idl
337 { FormulaMapGroupSpecialOffset::PUSH
, ocPush
} ,
338 { FormulaMapGroupSpecialOffset::CALL
, ocCall
} ,
339 { FormulaMapGroupSpecialOffset::STOP
, ocStop
} ,
340 { FormulaMapGroupSpecialOffset::EXTERNAL
, ocExternal
} ,
341 { FormulaMapGroupSpecialOffset::NAME
, ocName
} ,
342 { FormulaMapGroupSpecialOffset::NO_NAME
, ocNoName
} ,
343 { FormulaMapGroupSpecialOffset::MISSING
, ocMissing
} ,
344 { FormulaMapGroupSpecialOffset::BAD
, ocBad
} ,
345 { FormulaMapGroupSpecialOffset::SPACES
, ocSpaces
} ,
346 { FormulaMapGroupSpecialOffset::MAT_REF
, ocMatRef
} ,
347 { FormulaMapGroupSpecialOffset::DB_AREA
, ocDBArea
} ,
348 { FormulaMapGroupSpecialOffset::MACRO
, ocMacro
} ,
349 { FormulaMapGroupSpecialOffset::COL_ROW_NAME
, ocColRowName
}
351 const size_t nCount
= sizeof(aMap
)/sizeof(aMap
[0]);
352 // Preallocate vector elements.
353 if (aVec
.size() < nCount
)
355 FormulaOpCodeMapEntry aEntry
;
356 aEntry
.Token
.OpCode
= getOpCodeUnknown();
357 aVec
.resize( nCount
, aEntry
);
358 } // if (aVec.size() < nCount)
360 FormulaOpCodeMapEntry aEntry
;
361 for (size_t i
=0; i
< nCount
; ++i
)
363 size_t nIndex
= static_cast< size_t >( aMap
[i
].nOff
);
364 if (aVec
.size() <= nIndex
)
366 // The offsets really should be aligned with the size, so if
367 // the vector was preallocated above this code to resize it is
368 // just a measure in case the table isn't in sync with the API,
369 // usually it isn't executed.
370 aEntry
.Token
.OpCode
= getOpCodeUnknown();
371 aVec
.resize( nIndex
+ 1, aEntry
);
373 aEntry
.Token
.OpCode
= aMap
[i
].eOp
;
374 aVec
[nIndex
] = aEntry
;
379 /* FIXME: Once we support error constants in formulas we'll need a map
380 * group for that, e.g. FormulaMapGroup::ERROR_CONSTANTS, and fill
381 * SC_OPCODE_START_ERRORS to SC_OPCODE_STOP_ERRORS. */
383 // Anything else but SPECIAL.
384 if ((nGroups
& FormulaMapGroup::SEPARATORS
) != 0)
386 static const USHORT aOpCodes
[] = {
391 lclPushOpCodeMapEntries( aVec
, mpTable
, aOpCodes
, sizeof(aOpCodes
)/sizeof(aOpCodes
[0]) );
393 if ((nGroups
& FormulaMapGroup::ARRAY_SEPARATORS
) != 0)
395 static const USHORT aOpCodes
[] = {
396 SC_OPCODE_ARRAY_OPEN
,
397 SC_OPCODE_ARRAY_CLOSE
,
398 SC_OPCODE_ARRAY_ROW_SEP
,
399 SC_OPCODE_ARRAY_COL_SEP
401 lclPushOpCodeMapEntries( aVec
, mpTable
, aOpCodes
, sizeof(aOpCodes
)/sizeof(aOpCodes
[0]) );
403 if ((nGroups
& FormulaMapGroup::UNARY_OPERATORS
) != 0)
405 // Due to the nature of the percent operator following its operand
406 // it isn't sorted into unary operators for compiler interna.
407 lclPushOpCodeMapEntry( aVec
, mpTable
, ocPercentSign
);
408 // "+" can be used as unary operator too, push only if binary group is not set
409 if ((nGroups
& FormulaMapGroup::BINARY_OPERATORS
) == 0)
410 lclPushOpCodeMapEntry( aVec
, mpTable
, ocAdd
);
411 // regular unary operators
412 for (USHORT nOp
= SC_OPCODE_START_UN_OP
; nOp
< SC_OPCODE_STOP_UN_OP
&& nOp
< mnSymbols
; ++nOp
)
416 // NOT and NEG in fact are functions but for legacy reasons
417 // are sorted into unary operators for compiler interna.
422 lclPushOpCodeMapEntry( aVec
, mpTable
, nOp
);
426 if ((nGroups
& FormulaMapGroup::BINARY_OPERATORS
) != 0)
428 for (USHORT nOp
= SC_OPCODE_START_BIN_OP
; nOp
< SC_OPCODE_STOP_BIN_OP
&& nOp
< mnSymbols
; ++nOp
)
432 // AND and OR in fact are functions but for legacy reasons
433 // are sorted into binary operators for compiler interna.
438 lclPushOpCodeMapEntry( aVec
, mpTable
, nOp
);
442 if ((nGroups
& FormulaMapGroup::FUNCTIONS
) != 0)
444 // Function names are not consecutive, skip the gaps between
445 // functions with no parameter, functions with 1 parameter
446 lclPushOpCodeMapEntries( aVec
, mpTable
, SC_OPCODE_START_NO_PAR
, ::std::min
< USHORT
>( SC_OPCODE_STOP_NO_PAR
, mnSymbols
) );
447 lclPushOpCodeMapEntries( aVec
, mpTable
, SC_OPCODE_START_1_PAR
, ::std::min
< USHORT
>( SC_OPCODE_STOP_1_PAR
, mnSymbols
) );
448 // Additional functions not within range of functions.
449 static const USHORT aOpCodes
[] = {
457 lclPushOpCodeMapEntries( aVec
, mpTable
, aOpCodes
, sizeof(aOpCodes
)/sizeof(aOpCodes
[0]) );
458 // functions with 2 or more parameters.
459 for (USHORT nOp
= SC_OPCODE_START_2_PAR
; nOp
< SC_OPCODE_STOP_2_PAR
&& nOp
< mnSymbols
; ++nOp
)
463 // NO_NAME is in SPECIAL.
464 case SC_OPCODE_NO_NAME
:
467 lclPushOpCodeMapEntry( aVec
, mpTable
, nOp
);
470 // If AddIn functions are present in this mapping, use them, and only those.
473 for (ExternalHashMap::const_iterator
it( mpExternalHashMap
->begin());it
!= mpExternalHashMap
->end(); ++it
)
475 FormulaOpCodeMapEntry aEntry
;
476 aEntry
.Name
= (*it
).first
;
477 aEntry
.Token
.Data
<<= ::rtl::OUString( (*it
).second
);
478 aEntry
.Token
.OpCode
= ocExternal
;
479 aVec
.push_back( aEntry
);
484 //DBG_ASSERT( isCore(), "FormulaCompiler::OpCodeMap::createSequenceOfAvailableMappings: AddIn mapping from collection only implemented for core languages");
485 _rCompiler
.fillAddInToken(aVec
,isEnglish());
489 const FormulaOpCodeMapEntry
* pRet
= aVec
.empty() ? 0 : &aVec
[0];
490 return uno::Sequence
< FormulaOpCodeMapEntry
>(pRet
, aVec
.size());
492 //-----------------------------------------------------------------------------
494 void FormulaCompiler::OpCodeMap::putOpCode( const String
& rStr
, const OpCode eOp
)
496 DBG_ASSERT( 0 < eOp
&& USHORT(eOp
) < mnSymbols
, "OpCodeMap::putOpCode: OpCode out of range");
497 if (0 < eOp
&& USHORT(eOp
) < mnSymbols
)
499 DBG_ASSERT( (mpTable
[eOp
].Len() == 0) || (mpTable
[eOp
] == rStr
),
500 ByteString( "OpCodeMap::putOpCode: reusing OpCode ").
501 Append( ByteString::CreateFromInt32( sal_Int32( eOp
))).Append( " (").
502 Append( ByteString( rStr
, RTL_TEXTENCODING_ASCII_US
)).Append( ')').GetBuffer());
504 mpHashMap
->insert( OpCodeHashMap::value_type( rStr
, eOp
));
507 // -----------------------------------------------------------------------------
508 // class FormulaCompiler
509 // -----------------------------------------------------------------------------
510 DBG_NAME(FormulaCompiler
)
511 FormulaCompiler::FormulaCompiler(FormulaTokenArray
& _rArr
)
517 nNumFmt( NUMBERFORMAT_UNDEFINED
),
518 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED
),
519 bAutoCorrect( FALSE
),
521 bCompileForFAP( FALSE
),
522 bIgnoreErrors( FALSE
)
525 DBG_CTOR(FormulaCompiler
,NULL
);
527 FormulaCompiler::FormulaCompiler()
533 nNumFmt( NUMBERFORMAT_UNDEFINED
),
534 meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED
),
535 bAutoCorrect( FALSE
),
537 bCompileForFAP( FALSE
),
538 bIgnoreErrors( FALSE
)
541 DBG_CTOR(FormulaCompiler
,NULL
);
543 FormulaCompiler::~FormulaCompiler()
545 DBG_DTOR(FormulaCompiler
,NULL
);
548 FormulaCompiler::OpCodeMapPtr
FormulaCompiler::GetOpCodeMap( const sal_Int32 nLanguage
) const
550 FormulaCompiler::OpCodeMapPtr xMap
;
551 using namespace sheet
;
554 case FormulaLanguage::ODFF
:
557 xMap
= mxSymbolsODFF
;
559 case FormulaLanguage::ODF_11
:
562 xMap
= mxSymbolsPODF
;
564 case FormulaLanguage::ENGLISH
:
565 if (!mxSymbolsEnglish
)
566 InitSymbolsEnglish();
567 xMap
= mxSymbolsEnglish
;
569 case FormulaLanguage::NATIVE
:
570 if (!mxSymbolsNative
)
572 xMap
= mxSymbolsNative
;
574 case FormulaLanguage::XL_ENGLISH
:
575 if (!mxSymbolsEnglishXL
)
576 InitSymbolsEnglishXL();
577 xMap
= mxSymbolsEnglishXL
;
580 ; // nothing, NULL map returned
584 // -----------------------------------------------------------------------------
586 String
FormulaCompiler::FindAddInFunction( const String
& /*rUpperName*/, BOOL
/*bLocalFirst*/ ) const
590 // -----------------------------------------------------------------------------
591 FormulaCompiler::OpCodeMapPtr
FormulaCompiler::CreateOpCodeMap(
593 const sheet::FormulaOpCodeMapEntry
> & rMapping
,
596 using sheet::FormulaOpCodeMapEntry
;
597 // Filter / API maps are never Core
598 NonConstOpCodeMapPtr
xMap( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID
+ 1,false, FormulaGrammar::mergeToGrammar( FormulaGrammar::setEnglishBit(FormulaGrammar::GRAM_EXTERNAL
, bEnglish
),FormulaGrammar::CONV_UNSPECIFIED
)));
599 FormulaOpCodeMapEntry
const * pArr2
= rMapping
.getConstArray();
600 FormulaOpCodeMapEntry
const * const pStop
= pArr2
+ rMapping
.getLength();
601 for ( ; pArr2
< pStop
; ++pArr2
)
603 OpCode eOp
= OpCode(pArr2
->Token
.OpCode
);
604 if (eOp
!= ocExternal
)
605 xMap
->putOpCode( pArr2
->Name
, eOp
);
608 ::rtl::OUString aExternalName
;
609 if (pArr2
->Token
.Data
>>= aExternalName
)
610 xMap
->putExternal( pArr2
->Name
, aExternalName
);
613 DBG_ERRORFILE( "FormulaCompiler::CreateOpCodeMap: no Token.Data external name");
620 // -----------------------------------------------------------------------------
621 void lcl_fillNativeSymbols(FormulaCompiler::NonConstOpCodeMapPtr
& _xMap
,bool _destroy
= false)
623 static FormulaCompiler::NonConstOpCodeMapPtr s_SymbolMap
;
628 else if ( !s_SymbolMap
.get() )
631 s_SymbolMap
.reset( new FormulaCompiler::OpCodeMap( SC_OPCODE_LAST_OPCODE_ID
+ 1, true, FormulaGrammar::GRAM_NATIVE_UI
));
632 OModuleClient aModuleClient
;
633 OpCodeList
aOpCodeListNative( RID_STRLIST_FUNCTION_NAMES
, s_SymbolMap
);
634 // No AddInMap for native core mapping.
635 } // if ( !s_SymbolMap.get() )
638 // -----------------------------------------------------------------------------
639 const String
& FormulaCompiler::GetNativeSymbol( OpCode eOp
)
641 NonConstOpCodeMapPtr xSymbolsNative
;
642 lcl_fillNativeSymbols(xSymbolsNative
);
643 return xSymbolsNative
->getSymbol( eOp
);
645 // -----------------------------------------------------------------------------
646 void FormulaCompiler::InitSymbolsNative() const
648 if (mxSymbolsNative
.get())
651 // Use English function names and separators instead of native in UI.
652 static const sal_Char aEnvVarName
[] = "OOO_CALC_USE_ENGLISH_FORMULAS";
653 const char* pEnv
= getenv( aEnvVarName
);
654 if (pEnv
&& (*pEnv
== 'Y' || *pEnv
== 'y' || *pEnv
== '1') )
656 fprintf( stderr
, "%s=%s => UI uses English function names and separators in formulas.\n",
658 InitSymbolsEnglish();
659 mxSymbolsNative
= mxSymbolsEnglish
;
662 static NonConstOpCodeMapPtr s_sSymbol
;
663 if ( !s_sSymbol
.get() )
664 lcl_fillNativeSymbols(s_sSymbol
);
665 mxSymbolsNative
= s_sSymbol
;
667 // -----------------------------------------------------------------------------
668 void FormulaCompiler::InitSymbolsEnglish() const
670 static NonConstOpCodeMapPtr s_sSymbol
;
671 if ( !s_sSymbol
.get() )
672 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH
,FormulaGrammar::GRAM_ENGLISH
,s_sSymbol
);
673 mxSymbolsEnglish
= s_sSymbol
;
675 // -----------------------------------------------------------------------------
676 void FormulaCompiler::InitSymbolsPODF() const
678 static NonConstOpCodeMapPtr s_sSymbol
;
679 if ( !s_sSymbol
.get() )
680 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH
,FormulaGrammar::GRAM_PODF
,s_sSymbol
);
681 mxSymbolsPODF
= s_sSymbol
;
683 // -----------------------------------------------------------------------------
684 void FormulaCompiler::InitSymbolsODFF() const
686 static NonConstOpCodeMapPtr s_sSymbol
;
687 if ( !s_sSymbol
.get() )
688 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF
,FormulaGrammar::GRAM_ODFF
,s_sSymbol
);
689 mxSymbolsODFF
= s_sSymbol
;
691 // -----------------------------------------------------------------------------
692 void FormulaCompiler::InitSymbolsEnglishXL() const
694 static NonConstOpCodeMapPtr s_sSymbol
;
695 if ( !s_sSymbol
.get() )
696 loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH
,FormulaGrammar::GRAM_ENGLISH
,s_sSymbol
);
697 mxSymbolsEnglishXL
= s_sSymbol
;
699 // TODO: For now, just replace the separators to the Excel English
700 // variants. Later, if we want to properly map Excel functions with Calc
701 // functions, we'll need to do a little more work here.
702 mxSymbolsEnglishXL
->putOpCode(sal_Unicode(','), ocSep
);
703 mxSymbolsEnglishXL
->putOpCode(sal_Unicode(','), ocArrayColSep
);
704 mxSymbolsEnglishXL
->putOpCode(sal_Unicode(';'), ocArrayRowSep
);
707 // -----------------------------------------------------------------------------
708 void FormulaCompiler::loadSymbols(USHORT _nSymbols
,FormulaGrammar::Grammar _eGrammar
,NonConstOpCodeMapPtr
& _xMap
) const
713 _xMap
.reset( new OpCodeMap( SC_OPCODE_LAST_OPCODE_ID
+ 1, _eGrammar
!= FormulaGrammar::GRAM_ODFF
, _eGrammar
));
714 OModuleClient aModuleClient
;
715 OpCodeList
aOpCodeList( _nSymbols
, _xMap
);
717 fillFromAddInMap( _xMap
, _eGrammar
);
718 // Fill from collection for AddIns not already present.
719 if ( FormulaGrammar::GRAM_ENGLISH
!= _eGrammar
)
720 fillFromAddInCollectionUpperName( _xMap
);
722 fillFromAddInCollectionEnglishName( _xMap
);
725 // -----------------------------------------------------------------------------
726 void FormulaCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr
/*xMap */) const
729 // -----------------------------------------------------------------------------
730 void FormulaCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr
/*xMap */) const
733 // -----------------------------------------------------------------------------
734 void FormulaCompiler::fillFromAddInMap( NonConstOpCodeMapPtr
/*xMap*/, FormulaGrammar::Grammar
/*_eGrammar */) const
737 // -----------------------------------------------------------------------------
738 OpCode
FormulaCompiler::GetEnglishOpCode( const String
& rName
) const
740 FormulaCompiler::OpCodeMapPtr xMap
= GetOpCodeMap(sheet::FormulaLanguage::ENGLISH
);
742 formula::OpCodeHashMap::const_iterator
iLook( xMap
->getHashMap()->find( rName
) );
743 bool bFound
= (iLook
!= xMap
->getHashMap()->end());
744 return bFound
? (*iLook
).second
: OpCode(ocNone
);
747 bool FormulaCompiler::IsOpCodeVolatile( OpCode eOp
)
758 // more than one parameters:
759 // ocIndirect/ocIndirectXL otherwise would have to do
760 // StopListening and StartListening on a reference for every
761 // interpreted value.
764 // ocOffset results in indirect references.
771 // Remove quotes, escaped quotes are unescaped.
772 BOOL
FormulaCompiler::DeQuote( String
& rStr
)
774 xub_StrLen nLen
= rStr
.Len();
775 if ( nLen
> 1 && rStr
.GetChar(0) == '\'' && rStr
.GetChar( nLen
-1 ) == '\'' )
777 rStr
.Erase( nLen
-1, 1 );
780 while ( (nPos
= rStr
.SearchAscii( "\\\'", nPos
)) != STRING_NOTFOUND
)
782 rStr
.Erase( nPos
, 1 );
789 // -----------------------------------------------------------------------------
790 void FormulaCompiler::fillAddInToken(::std::vector
< sheet::FormulaOpCodeMapEntry
>& /*_rVec*/,bool /*_bIsEnglish*/) const
793 // -----------------------------------------------------------------------------
794 BOOL
FormulaCompiler::IsMatrixFunction(OpCode _eOpCode
)
811 // added to avoid warnings
817 // -----------------------------------------------------------------------------
818 FormulaCompiler::OpCodeMap::~OpCodeMap()
820 delete mpReverseExternalHashMap
;
821 delete mpExternalHashMap
;
825 // -----------------------------------------------------------------------------
826 sal_Int32
FormulaCompiler::OpCodeMap::getOpCodeUnknown()
828 static const sal_Int32 kOpCodeUnknown
= -1;
829 return kOpCodeUnknown
;
831 // -----------------------------------------------------------------------------
832 BOOL
FormulaCompiler::GetToken()
834 static const short nRecursionMax
= 42;
835 FormulaCompilerRecursionGuard
aRecursionGuard( nRecursion
);
836 if ( nRecursion
> nRecursionMax
)
838 SetError( errStackOverflow
);
839 pToken
= new FormulaByteToken( ocStop
);
842 if ( bAutoCorrect
&& !pStack
)
843 { // #61426# don't merge stacked subroutine code into entered formula
844 aCorrectedFormula
+= aCorrectedSymbol
;
845 aCorrectedSymbol
.Erase();
848 if( pArr
->GetCodeError() && !bIgnoreErrors
)
852 short nWasColRowName
;
854 && pArr
->pCode
[ pArr
->nIndex
-1 ]->GetOpCode() == ocColRowName
)
858 pToken
= pArr
->Next();
859 while( pToken
&& pToken
->GetOpCode() == ocSpaces
)
861 if ( nWasColRowName
)
863 if ( bAutoCorrect
&& !pStack
)
864 CreateStringFromToken( aCorrectedFormula
, pToken
, FALSE
);
865 pToken
= pArr
->Next();
867 if ( bAutoCorrect
&& !pStack
&& pToken
)
868 CreateStringFromToken( aCorrectedSymbol
, pToken
, FALSE
);
881 if ( nWasColRowName
>= 2 && pToken
->GetOpCode() == ocColRowName
)
882 { // convert an ocSpaces to ocIntersect in RPN
883 pToken
= new FormulaByteToken( ocIntersect
);
884 pArr
->nIndex
--; // we advanced to the second ocColRowName, step back
890 pToken
= new FormulaByteToken( ocStop
);
893 if( pToken
->GetOpCode() == ocSubTotal
)
895 else if ( pToken
->GetOpCode() == ocExternalRef
)
897 return HandleExternalReference(*pToken
);
899 else if( pToken
->GetOpCode() == ocName
)
901 return HandleRange();
903 else if( pToken
->GetOpCode() == ocColRowName
)
905 return HandleSingleRef();
907 else if( pToken
->GetOpCode() == ocDBArea
)
909 return HandleDbData();
911 else if( pToken
->GetType() == svSingleRef
)
915 else if( pToken
->GetType() == svDoubleRef
)
921 //---------------------------------------------------------------------------
922 // RPN creation by recursion
923 //---------------------------------------------------------------------------
925 void FormulaCompiler::Factor()
927 if ( pArr
->GetCodeError() && !bIgnoreErrors
)
930 CurrentFactor
pFacToken( this );
932 OpCode eOp
= pToken
->GetOpCode();
933 if( eOp
== ocPush
|| eOp
== ocColRowNameAuto
|| eOp
== ocMatRef
||
935 || (bCompileForFAP
&& ((eOp
== ocName
) || (eOp
== ocDBArea
)
936 || (eOp
== ocColRowName
) || (eOp
== ocBad
)))
943 // PUSH( is an error that may be caused by an unknown function.
945 ( pToken
->GetType() == svString
946 || pToken
->GetType() == svSingleRef
)
947 ? errNoName
: errOperatorExpected
);
948 if ( bAutoCorrect
&& !pStack
)
949 { // assume multiplication
950 aCorrectedFormula
+= mxSymbols
->getSymbol(ocMul
);
955 SetError(errPairExpected
);
961 else if( eOp
== ocOpen
)
965 while ((eOp
== ocSep
) && (!pArr
->GetCodeError() || bIgnoreErrors
))
966 { // range list (A1;A2) converted to (A1~A2)
970 // Do not ignore error here, regardless of bIgnoreErrors, otherwise
971 // errors like =(1;) would also result in display of =(1~)
972 if (!pArr
->GetCodeError())
974 pFacToken
->NewOpCode( ocUnion
,FormulaToken::PrivateAccess());
979 SetError(errPairExpected
);
985 if( nNumFmt
== NUMBERFORMAT_UNDEFINED
)
986 nNumFmt
= lcl_GetRetFormat( eOp
);
988 if ( IsOpCodeVolatile(eOp
) )
989 pArr
->SetRecalcModeAlways();
994 // Functions recalculated on every document load.
995 // Don't use SetRecalcModeOnLoad() which would override
998 pArr
->AddRecalcMode( RECALCMODE_ONLOAD
);
1000 // If the referred cell is moved the value changes.
1003 // ocCell needs recalc on move for some possible type values.
1005 pArr
->SetRecalcModeOnRefMove();
1008 pArr
->SetHyperLink(TRUE
);
1014 if (SC_OPCODE_START_NO_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_NO_PAR
)
1020 SetError(errPairExpected
);
1021 PutCode( pFacToken
);
1027 SetError(errPairExpected
);
1032 // special cases NOT() and NEG()
1033 else if( eOp
== ocNot
|| eOp
== ocNeg
1034 || (SC_OPCODE_START_1_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_1_PAR
) )
1038 if( nNumFmt
== NUMBERFORMAT_UNDEFINED
&& eOp
== ocNot
)
1039 nNumFmt
= NUMBERFORMAT_LOGICAL
;
1046 SetError(errPairExpected
);
1048 SetError(errPairExpected
);
1049 else if ( !pArr
->GetCodeError() )
1050 pFacToken
->SetByte( 1 );
1051 PutCode( pFacToken
);
1054 else if ((SC_OPCODE_START_2_PAR
<= eOp
&& eOp
< SC_OPCODE_STOP_2_PAR
)
1055 || eOp
== ocExternal
1060 || ( eOp
>= ocInternalBegin
&& eOp
<= ocInternalEnd
)
1061 || (bCompileForFAP
&& ((eOp
== ocIf
) || (eOp
== ocChose
)))
1065 OpCode eMyLastOp
= eOp
;
1067 bool bNoParam
= false;
1068 bool bBadName
= false;
1077 else if (eMyLastOp
== ocBad
)
1079 // Just a bad name, not an unknown function, no parameters, no
1080 // closing expected.
1085 SetError(errPairExpected
);
1090 while ( (eOp
== ocSep
) && (!pArr
->GetCodeError() || bIgnoreErrors
) )
1098 ; // nothing, keep current token for return
1099 else if (eOp
!= ocClose
)
1100 SetError(errPairExpected
);
1103 // Jumps are just normal functions for the FunctionAutoPilot tree view
1104 if ( bCompileForFAP
&& pFacToken
->GetType() == svJump
)
1105 pFacToken
= new FormulaFAPToken( pFacToken
->GetOpCode(), nSepCount
, pFacToken
);
1107 pFacToken
->SetByte( nSepCount
);
1108 PutCode( pFacToken
);
1110 else if (eOp
== ocIf
|| eOp
== ocChose
)
1112 // the PC counters are -1
1115 pFacToken
->GetJump()[ 0 ] = 3; // if, else, behind
1117 pFacToken
->GetJump()[ 0 ] = MAXJUMPCOUNT
+1;
1125 SetError(errPairExpected
);
1126 short nJumpCount
= 0;
1127 PutCode( pFacToken
);
1128 // #36253# during AutoCorrect (since pArr->GetCodeError() is
1129 // ignored) an unlimited ocIf would crash because
1130 // ScRawToken::Clone() allocates the JumpBuffer according to
1131 // nJump[0]*2+2, which is 3*2+2 on ocIf.
1132 const short nJumpMax
=
1133 (pFacToken
->GetOpCode() == ocIf
? 3 : MAXJUMPCOUNT
);
1134 while ( (nJumpCount
< (MAXJUMPCOUNT
- 1)) && (eOp
== ocSep
)
1135 && (!pArr
->GetCodeError() || bIgnoreErrors
) )
1137 if ( ++nJumpCount
<= nJumpMax
)
1138 pFacToken
->GetJump()[nJumpCount
] = pc
-1;
1141 // ocSep or ocClose terminate the subexpression
1145 SetError(errPairExpected
);
1149 // always limit to nJumpMax, no arbitrary overwrites
1150 if ( ++nJumpCount
<= nJumpMax
)
1151 pFacToken
->GetJump()[ nJumpCount
] = pc
-1;
1152 if ((pFacToken
->GetOpCode() == ocIf
&& (nJumpCount
> 3)) ||
1153 (nJumpCount
>= MAXJUMPCOUNT
))
1154 SetError(errIllegalParameter
);
1156 pFacToken
->GetJump()[ 0 ] = nJumpCount
;
1159 else if ( eOp
== ocMissing
)
1164 else if ( eOp
== ocClose
)
1166 SetError( errParameterExpected
);
1168 else if ( eOp
== ocSep
)
1169 { // Subsequent ocSep
1170 SetError( errParameterExpected
);
1171 if ( bAutoCorrect
&& !pStack
)
1173 aCorrectedSymbol
.Erase();
1177 else if ( eOp
== ocExternalRef
)
1184 SetError( errUnknownToken
);
1185 if ( bAutoCorrect
&& !pStack
)
1187 if ( eOp
== ocStop
)
1188 { // trailing operator w/o operand
1189 xub_StrLen nLen
= aCorrectedFormula
.Len();
1191 aCorrectedFormula
.Erase( nLen
- 1 );
1192 aCorrectedSymbol
.Erase();
1200 //---------------------------------------------------------------------------
1202 void FormulaCompiler::RangeLine()
1205 while (pToken
->GetOpCode() == ocRange
)
1207 FormulaToken
** pCode1
= pCode
- 1;
1208 FormulaTokenRef p
= pToken
;
1211 FormulaToken
** pCode2
= pCode
- 1;
1212 if (!MergeRangeReference( pCode1
, pCode2
))
1217 //---------------------------------------------------------------------------
1219 void FormulaCompiler::UnionLine()
1222 while (pToken
->GetOpCode() == ocUnion
)
1224 FormulaTokenRef p
= pToken
;
1231 //---------------------------------------------------------------------------
1233 void FormulaCompiler::IntersectionLine()
1236 while (pToken
->GetOpCode() == ocIntersect
)
1238 FormulaTokenRef p
= pToken
;
1245 //---------------------------------------------------------------------------
1247 void FormulaCompiler::UnaryLine()
1249 if( pToken
->GetOpCode() == ocAdd
)
1251 else if (SC_OPCODE_START_UN_OP
<= pToken
->GetOpCode() &&
1252 pToken
->GetOpCode() < SC_OPCODE_STOP_UN_OP
)
1254 FormulaTokenRef p
= pToken
;
1263 //---------------------------------------------------------------------------
1265 void FormulaCompiler::PostOpLine()
1268 while ( pToken
->GetOpCode() == ocPercentSign
)
1269 { // this operator _follows_ its operand
1275 //---------------------------------------------------------------------------
1277 void FormulaCompiler::PowLine()
1280 while (pToken
->GetOpCode() == ocPow
)
1282 FormulaTokenRef p
= pToken
;
1289 //---------------------------------------------------------------------------
1291 void FormulaCompiler::MulDivLine()
1294 while (pToken
->GetOpCode() == ocMul
|| pToken
->GetOpCode() == ocDiv
)
1296 FormulaTokenRef p
= pToken
;
1303 //---------------------------------------------------------------------------
1305 void FormulaCompiler::AddSubLine()
1308 while (pToken
->GetOpCode() == ocAdd
|| pToken
->GetOpCode() == ocSub
)
1310 FormulaTokenRef p
= pToken
;
1317 //---------------------------------------------------------------------------
1319 void FormulaCompiler::ConcatLine()
1322 while (pToken
->GetOpCode() == ocAmpersand
)
1324 FormulaTokenRef p
= pToken
;
1331 //---------------------------------------------------------------------------
1333 void FormulaCompiler::CompareLine()
1336 while (pToken
->GetOpCode() >= ocEqual
&& pToken
->GetOpCode() <= ocGreaterEqual
)
1338 FormulaTokenRef p
= pToken
;
1345 //---------------------------------------------------------------------------
1347 void FormulaCompiler::NotLine()
1350 while (pToken
->GetOpCode() == ocNot
)
1352 FormulaTokenRef p
= pToken
;
1359 //---------------------------------------------------------------------------
1361 OpCode
FormulaCompiler::Expression()
1363 static const short nRecursionMax
= 42;
1364 FormulaCompilerRecursionGuard
aRecursionGuard( nRecursion
);
1365 if ( nRecursion
> nRecursionMax
)
1367 SetError( errStackOverflow
);
1368 return ocStop
; //! generate token instead?
1371 while (pToken
->GetOpCode() == ocAnd
|| pToken
->GetOpCode() == ocOr
)
1373 FormulaTokenRef p
= pToken
;
1374 pToken
->SetByte( 2 ); // 2 parameters!
1379 return pToken
->GetOpCode();
1381 // -----------------------------------------------------------------------------
1382 void FormulaCompiler::SetError(USHORT
/*nError*/)
1385 // -----------------------------------------------------------------------------
1386 FormulaTokenRef
FormulaCompiler::ExtendRangeReference( FormulaToken
& /*rTok1*/, FormulaToken
& /*rTok2*/, bool /*bReuseDoubleRef*/ )
1388 return FormulaTokenRef();
1390 // -----------------------------------------------------------------------------
1391 bool FormulaCompiler::MergeRangeReference(FormulaToken
* * const pCode1
, FormulaToken
* const * const pCode2
)
1393 FormulaToken
*p1
, *p2
;
1394 if (pc
< 2 || !pCode1
|| !pCode2
||
1395 (pCode2
- pCode1
!= 1) || (pCode
- pCode2
!= 1) ||
1396 ((p1
= *pCode1
) == 0) || ((p2
= *pCode2
) == 0) )
1399 FormulaTokenRef p
= ExtendRangeReference( *p1
, *p2
, true);
1412 // -----------------------------------------------------------------------------
1413 BOOL
FormulaCompiler::CompileTokenArray()
1417 if( !pArr
->GetCodeError() || bIgnoreErrors
)
1421 aCorrectedFormula
.Erase();
1422 aCorrectedSymbol
.Erase();
1424 pArr
->nRefs
= 0; // count from start
1427 FormulaToken
* pData
[ MAXCODE
];
1429 BOOL bWasForced
= pArr
->IsRecalcModeForced();
1433 aCorrectedFormula
= '=';
1435 pArr
->ClearRecalcMode();
1440 OpCode eOp
= Expression();
1441 // Some trailing garbage that doesn't form an expression?
1443 SetError( errOperatorExpected
);
1445 USHORT nErrorBeforePop
= pArr
->GetCodeError();
1451 pArr
->pRPN
= new FormulaToken
*[ pc
];
1453 memcpy( pArr
->pRPN
, pData
, pc
* sizeof( FormulaToken
* ) );
1456 // once an error, always an error
1457 if( !pArr
->GetCodeError() && nErrorBeforePop
)
1458 pArr
->SetCodeError( nErrorBeforePop
);
1460 if( pArr
->GetCodeError() && !bIgnoreErrors
)
1463 pArr
->SetHyperLink(FALSE
);
1467 pArr
->SetRecalcModeForced();
1469 if( nNumFmt
== NUMBERFORMAT_UNDEFINED
)
1470 nNumFmt
= NUMBERFORMAT_NUMBER
;
1473 // -----------------------------------------------------------------------------
1474 void FormulaCompiler::PopTokenArray()
1478 FormulaArrayStack
* p
= pStack
;
1480 p
->pArr
->nRefs
= sal::static_int_cast
<short>( p
->pArr
->nRefs
+ pArr
->nRefs
);
1481 // obtain special RecalcMode from SharedFormula
1482 if ( pArr
->IsRecalcModeAlways() )
1483 p
->pArr
->SetRecalcModeAlways();
1484 else if ( !pArr
->IsRecalcModeNormal() && p
->pArr
->IsRecalcModeNormal() )
1485 p
->pArr
->SetMaskedRecalcMode( pArr
->GetRecalcMode() );
1486 p
->pArr
->SetCombinedBitsRecalcMode( pArr
->GetRecalcMode() );
1493 // -----------------------------------------------------------------------------
1494 void FormulaCompiler::CreateStringFromTokenArray( String
& rFormula
)
1496 rtl::OUStringBuffer
aBuffer( pArr
->GetLen() * 5 );
1497 CreateStringFromTokenArray( aBuffer
);
1501 void FormulaCompiler::CreateStringFromTokenArray( rtl::OUStringBuffer
& rBuffer
)
1503 rBuffer
.setLength(0);
1504 if( !pArr
->GetLen() )
1507 FormulaTokenArray
* pSaveArr
= pArr
;
1508 bool bODFF
= FormulaGrammar::isODFF( meGrammar
);
1509 if (bODFF
|| FormulaGrammar::isPODF( meGrammar
) )
1511 // Scan token array for missing args and re-write if present.
1512 MissingConvention
aConv( bODFF
);
1513 if (pArr
->NeedsPofRewrite( aConv
))
1514 pArr
= pArr
->RewriteMissingToPof( aConv
);
1517 // At least one character per token, plus some are references, some are
1518 // function names, some are numbers, ...
1519 rBuffer
.ensureCapacity( pArr
->GetLen() * 5 );
1521 if ( pArr
->IsRecalcModeForced() )
1522 rBuffer
.append(sal_Unicode('='));
1523 FormulaToken
* t
= pArr
->First();
1525 t
= CreateStringFromToken( rBuffer
, t
, TRUE
);
1527 if (pSaveArr
!= pArr
)
1533 // -----------------------------------------------------------------------------
1534 FormulaToken
* FormulaCompiler::CreateStringFromToken( String
& rFormula
, FormulaToken
* pTokenP
,BOOL bAllowArrAdvance
)
1536 rtl::OUStringBuffer aBuffer
;
1537 FormulaToken
* p
= CreateStringFromToken( aBuffer
, pTokenP
, bAllowArrAdvance
);
1538 rFormula
+= aBuffer
;
1542 FormulaToken
* FormulaCompiler::CreateStringFromToken( rtl::OUStringBuffer
& rBuffer
, FormulaToken
* pTokenP
,BOOL bAllowArrAdvance
)
1545 BOOL bSpaces
= FALSE
;
1546 FormulaToken
* t
= pTokenP
;
1547 OpCode eOp
= t
->GetOpCode();
1548 if( eOp
>= ocAnd
&& eOp
<= ocOr
)
1551 if ( bAllowArrAdvance
)
1554 t
= pArr
->PeekNext();
1556 bSpaces
= ( !t
|| t
->GetOpCode() != ocOpen
);
1559 rBuffer
.append(sal_Unicode(' '));
1561 if( eOp
== ocSpaces
)
1563 bool bIntersectionOp
= mxSymbols
->isODFF();
1564 if (bIntersectionOp
)
1566 const FormulaToken
* p
= pArr
->PeekPrevNoSpaces();
1567 bIntersectionOp
= (p
&& p
->GetOpCode() == ocColRowName
);
1568 if (bIntersectionOp
)
1570 p
= pArr
->PeekNextNoSpaces();
1571 bIntersectionOp
= (p
&& p
->GetOpCode() == ocColRowName
);
1574 if (bIntersectionOp
)
1575 rBuffer
.appendAscii( "!!");
1578 // most times it's just one blank
1579 BYTE n
= t
->GetByte();
1580 for ( BYTE j
=0; j
<n
; ++j
)
1582 rBuffer
.append(sal_Unicode(' '));
1586 else if( eOp
>= ocInternalBegin
&& eOp
<= ocInternalEnd
)
1587 rBuffer
.appendAscii( pInternal
[ eOp
- ocInternalBegin
] );
1588 else if( (USHORT
) eOp
< mxSymbols
->getSymbolCount()) // Keyword:
1589 rBuffer
.append(mxSymbols
->getSymbol(eOp
));
1592 DBG_ERRORFILE("unknown OpCode");
1593 rBuffer
.append(GetNativeSymbol( ocErrName
));
1597 if (eOp
== ocExternalRef
)
1599 CreateStringFromExternal(rBuffer
, pTokenP
);
1603 switch( t
->GetType() )
1606 AppendDouble( rBuffer
, t
->GetDouble() );
1611 rBuffer
.append(t
->GetString());
1613 AppendString( rBuffer
, t
->GetString() );
1616 CreateStringFromSingleRef(rBuffer
,t
);
1619 CreateStringFromDoubleRef(rBuffer
,t
);
1622 CreateStringFromMatrix( rBuffer
, t
);
1626 CreateStringFromIndex( rBuffer
, t
);
1630 // mapped or translated name of AddIns
1631 String
aAddIn( t
->GetExternal() );
1632 bool bMapped
= mxSymbols
->isPODF(); // ODF 1.1 directly uses programmatical name
1633 if (!bMapped
&& mxSymbols
->hasExternals())
1635 ExternalHashMap::const_iterator iLook
= mxSymbols
->getReverseExternalHashMap()->find( aAddIn
);
1636 if (iLook
!= mxSymbols
->getReverseExternalHashMap()->end())
1638 aAddIn
= (*iLook
).second
;
1642 if (!bMapped
&& !mxSymbols
->isEnglish())
1643 LocalizeString( aAddIn
);
1644 rBuffer
.append(aAddIn
);
1654 DBG_ERROR("FormulaCompiler:: GetStringFromToken errUnknownVariable");
1659 rBuffer
.append(sal_Unicode(' '));
1660 if ( bAllowArrAdvance
)
1668 // -----------------------------------------------------------------------------
1670 void FormulaCompiler::AppendDouble( rtl::OUStringBuffer
& rBuffer
, double fVal
)
1672 if ( mxSymbols
->isEnglish() )
1674 ::rtl::math::doubleToUStringBuffer( rBuffer
, fVal
,
1675 rtl_math_StringFormat_Automatic
,
1676 rtl_math_DecimalPlaces_Max
, '.', TRUE
);
1680 SvtSysLocale aSysLocale
;
1681 ::rtl::math::doubleToUStringBuffer( rBuffer
, fVal
,
1682 rtl_math_StringFormat_Automatic
,
1683 rtl_math_DecimalPlaces_Max
,
1684 aSysLocale
.GetLocaleDataPtr()->getNumDecimalSep().GetChar(0),
1688 // -----------------------------------------------------------------------------
1689 void FormulaCompiler::AppendBoolean( rtl::OUStringBuffer
& rBuffer
, bool bVal
)
1691 rBuffer
.append( mxSymbols
->getSymbol(static_cast<OpCode
>(bVal
? ocTrue
: ocFalse
)) );
1693 // -----------------------------------------------------------------------------
1694 BOOL
FormulaCompiler::IsImportingXML() const
1698 // -----------------------------------------------------------------------------
1699 void FormulaCompiler::AppendString( rtl::OUStringBuffer
& rBuffer
, const String
& rStr
)
1701 if (IsImportingXML())
1702 rBuffer
.append( rStr
);
1705 rBuffer
.append(sal_Unicode('"'));
1706 if ( lcl_UnicodeStrChr( rStr
.GetBuffer(), '"' ) == NULL
)
1707 rBuffer
.append( rStr
);
1710 String
aStr( rStr
);
1711 aStr
.SearchAndReplaceAll( '"', String( RTL_CONSTASCII_USTRINGPARAM( "\"\"")));
1712 rBuffer
.append(aStr
);
1714 rBuffer
.append(sal_Unicode('"'));
1718 void FormulaCompiler::UpdateSeparatorsNative(
1719 const rtl::OUString
& rSep
, const rtl::OUString
& rArrayColSep
, const rtl::OUString
& rArrayRowSep
)
1721 NonConstOpCodeMapPtr xSymbolsNative
;
1722 lcl_fillNativeSymbols(xSymbolsNative
);
1723 xSymbolsNative
->putOpCode(rSep
, ocSep
);
1724 xSymbolsNative
->putOpCode(rArrayColSep
, ocArrayColSep
);
1725 xSymbolsNative
->putOpCode(rArrayRowSep
, ocArrayRowSep
);
1728 // -----------------------------------------------------------------------------
1729 OpCode
FormulaCompiler::NextToken()
1733 OpCode eOp
= pToken
->GetOpCode();
1734 // There must be an operator before a push
1735 if ( (eOp
== ocPush
|| eOp
== ocColRowNameAuto
) &&
1736 !( (eLastOp
== ocOpen
) || (eLastOp
== ocSep
) ||
1737 (SC_OPCODE_START_BIN_OP
<= eLastOp
&& eLastOp
< SC_OPCODE_STOP_UN_OP
)) )
1738 SetError(errOperatorExpected
);
1739 // Operator and Plus => operator
1740 if (eOp
== ocAdd
&& (eLastOp
== ocOpen
|| eLastOp
== ocSep
||
1741 (SC_OPCODE_START_BIN_OP
<= eLastOp
&& eLastOp
< SC_OPCODE_STOP_UN_OP
)))
1745 // Before an operator there must not be another operator, with the
1746 // exception of AND and OR.
1747 if ( eOp
!= ocAnd
&& eOp
!= ocOr
&&
1748 (SC_OPCODE_START_BIN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_BIN_OP
)
1749 && (eLastOp
== ocOpen
|| eLastOp
== ocSep
||
1750 (SC_OPCODE_START_BIN_OP
<= eLastOp
&& eLastOp
< SC_OPCODE_STOP_UN_OP
)))
1752 SetError(errVariableExpected
);
1753 if ( bAutoCorrect
&& !pStack
)
1755 if ( eOp
== eLastOp
|| eLastOp
== ocOpen
)
1756 { // throw away duplicated operator
1757 aCorrectedSymbol
.Erase();
1762 xub_StrLen nPos
= aCorrectedFormula
.Len();
1766 sal_Unicode c
= aCorrectedFormula
.GetChar( nPos
);
1770 if ( c
== mxSymbols
->getSymbol(ocEqual
).GetChar(0) )
1771 { // >= instead of =>
1772 aCorrectedFormula
.SetChar( nPos
,
1773 mxSymbols
->getSymbol(ocGreater
).GetChar(0) );
1774 aCorrectedSymbol
= c
;
1779 if ( c
== mxSymbols
->getSymbol(ocEqual
).GetChar(0) )
1780 { // <= instead of =<
1781 aCorrectedFormula
.SetChar( nPos
,
1782 mxSymbols
->getSymbol(ocLess
).GetChar(0) );
1783 aCorrectedSymbol
= c
;
1786 else if ( c
== mxSymbols
->getSymbol(ocGreater
).GetChar(0) )
1787 { // <> instead of ><
1788 aCorrectedFormula
.SetChar( nPos
,
1789 mxSymbols
->getSymbol(ocLess
).GetChar(0) );
1790 aCorrectedSymbol
= c
;
1795 if ( c
== mxSymbols
->getSymbol(ocSub
).GetChar(0) )
1796 { // *- instead of -*
1797 aCorrectedFormula
.SetChar( nPos
,
1798 mxSymbols
->getSymbol(ocMul
).GetChar(0) );
1799 aCorrectedSymbol
= c
;
1804 if ( c
== mxSymbols
->getSymbol(ocSub
).GetChar(0) )
1805 { // /- instead of -/
1806 aCorrectedFormula
.SetChar( nPos
,
1807 mxSymbols
->getSymbol(ocDiv
).GetChar(0) );
1808 aCorrectedSymbol
= c
;
1823 void FormulaCompiler::PutCode( FormulaTokenRef
& p
)
1825 if( pc
>= MAXCODE
-1 )
1827 if ( pc
== MAXCODE
-1 )
1829 p
= new FormulaByteToken( ocStop
);
1834 SetError(errCodeOverflow
);
1837 if( pArr
->GetCodeError() && !bCompileForFAP
)
1839 ForceArrayOperator( p
, pCurrentFactorToken
);
1845 // -----------------------------------------------------------------------------
1846 BOOL
FormulaCompiler::HandleExternalReference(const FormulaToken
& /*_aToken*/)
1850 // -----------------------------------------------------------------------------
1851 BOOL
FormulaCompiler::HandleRange()
1855 // -----------------------------------------------------------------------------
1856 BOOL
FormulaCompiler::HandleSingleRef()
1860 // -----------------------------------------------------------------------------
1861 BOOL
FormulaCompiler::HandleDbData()
1865 // -----------------------------------------------------------------------------
1866 void FormulaCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1869 // -----------------------------------------------------------------------------
1870 void FormulaCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1873 // -----------------------------------------------------------------------------
1874 void FormulaCompiler::CreateStringFromIndex(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1877 // -----------------------------------------------------------------------------
1878 void FormulaCompiler::CreateStringFromMatrix(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1881 // -----------------------------------------------------------------------------
1882 void FormulaCompiler::CreateStringFromExternal(rtl::OUStringBuffer
& /*rBuffer*/,FormulaToken
* /*pTokenP*/)
1885 // -----------------------------------------------------------------------------
1886 void FormulaCompiler::LocalizeString( String
& /*rName*/ )
1889 void FormulaCompiler::PushTokenArray( FormulaTokenArray
* pa
, BOOL bTemp
)
1891 if ( bAutoCorrect
&& !pStack
)
1892 { // #61426# don't merge stacked subroutine code into entered formula
1893 aCorrectedFormula
+= aCorrectedSymbol
;
1894 aCorrectedSymbol
.Erase();
1896 FormulaArrayStack
* p
= new FormulaArrayStack
;
1904 // =============================================================================
1906 // =============================================================================