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: compiler.cxx,v $
10 * $Revision: 1.82.18.2 $
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 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include <sfx2/app.hxx>
37 #include <sfx2/objsh.hxx>
38 #include <basic/sbmeth.hxx>
39 #include <basic/sbstar.hxx>
40 #include <svtools/zforlist.hxx>
41 #include <tools/rcid.h>
42 #include <tools/rc.hxx>
43 #include <tools/solar.h>
44 #include <unotools/charclass.hxx>
45 #include <com/sun/star/lang/Locale.hpp>
46 #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
47 #include <com/sun/star/sheet/FormulaLanguage.hpp>
48 #include <com/sun/star/sheet/FormulaMapGroup.hpp>
49 #include <comphelper/processfactory.hxx>
50 #include <unotools/transliterationwrapper.hxx>
51 #include <tools/urlobj.hxx>
52 #include <rtl/math.hxx>
58 #include "compiler.hxx"
59 #include "rangenam.hxx"
60 #include "dbcolect.hxx"
61 #include "document.hxx"
62 #include "callform.hxx"
63 #include "addincol.hxx"
64 #include "refupdat.hxx"
65 #include "scresid.hxx"
67 #include "globstr.hrc"
69 #include "dociter.hxx"
70 #include "docoptio.hxx"
71 #include <formula/errorcodes.hxx>
72 #include "parclass.hxx"
73 #include "autonamecache.hxx"
74 #include "externalrefmgr.hxx"
75 #include "rangeutl.hxx"
76 #include "convuno.hxx"
77 #include "tokenuno.hxx"
78 #include "formulaparserpool.hxx"
80 using namespace formula
;
81 using namespace ::com::sun::star
;
85 #if OSL_DEBUG_LEVEL > 1
86 // For some unknown reason the identical dbg_dump utilities in
87 // tools/source/string/debugprint.cxx tend to crash when called from within
88 // gdb. Having them here also comes handy as libtl*.so doesn't have to be
90 const char* dbg_sc_dump( const ByteString
& rStr
)
92 static ByteString aStr
;
94 aStr
.Append(static_cast<char>(0));
95 return aStr
.GetBuffer();
97 const char* dbg_sc_dump( const UniString
& rStr
)
99 return dbg_sc_dump(ByteString(rStr
, RTL_TEXTENCODING_UTF8
));
101 const char* dbg_sc_dump( const sal_Unicode
* pBuf
)
103 return dbg_sc_dump( UniString( pBuf
));
105 const char* dbg_sc_dump( const sal_Unicode c
)
107 return dbg_sc_dump( UniString( c
));
111 CharClass
* ScCompiler::pCharClassEnglish
= NULL
;
112 const ScCompiler::Convention
* ScCompiler::pConventions
[ ] = { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
127 static const sal_Char
* pInternal
[ 5 ] = { "GAME", "SPEW", "TTT", "STARCALCTEAM", "ANTWORT" };
129 using namespace ::com::sun::star::i18n
;
131 /////////////////////////////////////////////////////////////////////////
135 class ScCompilerRecursionGuard
140 ScCompilerRecursionGuard( short& rRec
)
141 : rRecursion( rRec
) { ++rRecursion
; }
142 ~ScCompilerRecursionGuard() { --rRecursion
; }
146 void ScCompiler::fillFromAddInMap( NonConstOpCodeMapPtr xMap
,FormulaGrammar::Grammar _eGrammar
) const
148 size_t nSymbolOffset
;
151 case FormulaGrammar::GRAM_PODF
:
152 nSymbolOffset
= offsetof( AddInMap
, pUpper
);
155 case FormulaGrammar::GRAM_ODFF
:
156 nSymbolOffset
= offsetof( AddInMap
, pODFF
);
158 case FormulaGrammar::GRAM_ENGLISH
:
159 nSymbolOffset
= offsetof( AddInMap
, pEnglish
);
162 const AddInMap
* pMap
= GetAddInMap();
163 const AddInMap
* const pStop
= pMap
+ GetAddInMapCount();
164 for ( ; pMap
< pStop
; ++pMap
)
166 char const * const * ppSymbol
=
167 reinterpret_cast< char const * const * >(
168 reinterpret_cast< char const * >(pMap
) + nSymbolOffset
);
169 xMap
->putExternal( String::CreateFromAscii( *ppSymbol
),
170 String::CreateFromAscii( pMap
->pOriginal
));
174 void ScCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr xMap
) const
176 ScUnoAddInCollection
* pColl
= ScGlobal::GetAddInCollection();
177 long nCount
= pColl
->GetFuncCount();
178 for (long i
=0; i
< nCount
; ++i
)
180 const ScUnoAddInFuncData
* pFuncData
= pColl
->GetFuncData(i
);
182 xMap
->putExternalSoftly( pFuncData
->GetUpperName(),
183 pFuncData
->GetOriginalName());
187 void ScCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr xMap
) const
189 ScUnoAddInCollection
* pColl
= ScGlobal::GetAddInCollection();
190 long nCount
= pColl
->GetFuncCount();
191 for (long i
=0; i
< nCount
; ++i
)
193 const ScUnoAddInFuncData
* pFuncData
= pColl
->GetFuncData(i
);
197 if (pFuncData
->GetExcelName( LANGUAGE_ENGLISH_US
, aName
))
198 xMap
->putExternalSoftly( aName
, pFuncData
->GetOriginalName());
200 xMap
->putExternalSoftly( pFuncData
->GetUpperName(),
201 pFuncData
->GetOriginalName());
207 #ifdef erGENERATEMAPPING
208 // Run in en-US UI by calling from within gdb, edit pODFF entries afterwards.
209 void dbg_call_generateMappingODFF()
211 // static ScCompiler members
212 fprintf( stdout
, "%s", "static struct AddInMap\n{\n const char* pODFF;\n const char* pEnglish;\n bool bMapDupToInternal;\n const char* pOriginal;\n const char* pUpper;\n} maAddInMap[];\n");
213 fprintf( stdout
, "%s", "static const AddInMap* GetAddInMap();\n");
214 fprintf( stdout
, "%s", "static size_t GetAddInMapCount();\n");
215 fprintf( stdout
, "addinfuncdata___:%s", "ScCompiler::AddInMap ScCompiler::maAddInMap[] =\n{\n");
216 ScUnoAddInCollection
* pColl
= ScGlobal::GetAddInCollection();
217 long nCount
= pColl
->GetFuncCount();
218 for (long i
=0; i
< nCount
; ++i
)
220 const ScUnoAddInFuncData
* pFuncData
= pColl
->GetFuncData(i
);
223 #define out(rStr) (ByteString( rStr, RTL_TEXTENCODING_UTF8).GetBuffer())
224 String aL
= pFuncData
->GetUpperLocal();
225 String aP
= pFuncData
->GetOriginalName();
226 String aU
= pFuncData
->GetUpperName();
227 fprintf( stdout
, "addinfuncdata%3ld: { \"%s\", \"%s\", false, \"%s\", \"%s\" },\n",
228 i
, out(aL
), out(aL
), out(aP
), out(aU
));
232 fprintf( stdout
, "addinfuncdata___:%s", "};\n");
233 fprintf( stdout
, "%s", "\n// static\nconst ScCompiler::AddInMap* ScCompiler::GetAddInMap()\n{\n return maAddInMap;\n}\n");
234 fprintf( stdout
, "%s", "\n// static\nsize_t ScCompiler::GetAddInMapCount()\n{\n return sizeof(maAddInMap)/sizeof(maAddInMap[0]);\n}\n");
237 #endif // erGENERATEMAPPING
239 #ifdef erGENERATEMAPPINGDIFF
240 // Run in en-US UI by calling from within gdb.
241 void dbg_call_generateMappingDiff()
243 using namespace ::com::sun::star::sheet
;
244 ScCompiler::OpCodeMapPtr xPODF
= ScCompiler::GetOpCodeMap(
245 FormulaLanguage::ODF_11
);
246 ScCompiler::OpCodeMapPtr xODFF
= ScCompiler::GetOpCodeMap(
247 FormulaLanguage::ODFF
);
248 ScCompiler::OpCodeMapPtr xENUS
= ScCompiler::GetOpCodeMap(
249 FormulaLanguage::ENGLISH
);
250 USHORT nPODF
= xPODF
->getSymbolCount();
251 USHORT nODFF
= xODFF
->getSymbolCount();
252 USHORT nENUS
= xENUS
->getSymbolCount();
253 printf( "%s\n", "This is a semicolon separated file, you may import it as such to Calc.");
254 printf( "%s\n", "Spreadsheet functions name differences between PODF (ODF < 1.2) and ODFF (ODF >= 1.2), plus English UI names.");
255 printf( "\nInternal OpCodes; PODF: %d; ODFF: %d; ENUS: %d\n",
256 (int)nPODF
, (int)nODFF
, (int)nENUS
);
257 USHORT nMax
= ::std::max( ::std::max( nPODF
, nODFF
), nENUS
);
258 #define out(rStr) (ByteString( rStr, RTL_TEXTENCODING_UTF8).GetBuffer())
259 for (USHORT i
=0; i
< nMax
; ++i
)
261 const String
& rPODF
= xPODF
->getSymbol(static_cast<OpCode
>(i
));
262 const String
& rODFF
= xODFF
->getSymbol(static_cast<OpCode
>(i
));
263 const String
& rENUS
= xENUS
->getSymbol(static_cast<OpCode
>(i
));
265 printf( "%d;%s;%s;%s\n", (int)i
, out(rPODF
), out(rODFF
), out(rENUS
));
267 // Actually they should all differ, so we could simply list them all, but
268 // this is correct and we would find odd things, if any.
269 const ExternalHashMap
* pPODF
= xPODF
->getReverseExternalHashMap();
270 const ExternalHashMap
* pODFF
= xODFF
->getReverseExternalHashMap();
271 const ExternalHashMap
* pENUS
= xENUS
->getReverseExternalHashMap();
272 printf( "\n%s\n", "Add-In mapping");
273 for (ExternalHashMap::const_iterator it
= pPODF
->begin(); it
!= pPODF
->end(); ++it
)
275 ExternalHashMap::const_iterator iLookODFF
= pODFF
->find( (*it
).first
);
276 ExternalHashMap::const_iterator iLookENUS
= pENUS
->find( (*it
).first
);
277 String
aNative( iLookENUS
== pENUS
->end() ?
278 String::CreateFromAscii( "ENGLISH_SYMBOL_NOT_FOUND") :
279 (*iLookENUS
).second
);
280 if (iLookODFF
== pODFF
->end())
281 printf( "NOT FOUND;%s;;%s\n", out((*it
).first
), out(aNative
));
282 else if((*it
).second
== (*iLookODFF
).second
) // upper equal
283 printf( "EQUAL;%s;%s;%s\n", out((*it
).first
), out((*iLookODFF
).second
), out(aNative
));
285 printf( ";%s;%s;%s\n", out((*it
).first
), out((*iLookODFF
).second
), out(aNative
));
290 #endif // erGENERATEMAPPINGDIFF
293 void ScCompiler::DeInit()
295 if (pCharClassEnglish
)
297 delete pCharClassEnglish
;
298 pCharClassEnglish
= NULL
;
302 bool ScCompiler::IsEnglishSymbol( const String
& rName
)
304 // function names are always case-insensitive
305 String
aUpper( ScGlobal::pCharClass
->upper( rName
) );
307 // 1. built-in function name
308 OpCode eOp
= ScCompiler::GetEnglishOpCode( aUpper
);
313 // 2. old add in functions
315 if ( ScGlobal::GetFuncCollection()->SearchFunc( aUpper
, nIndex
) )
320 // 3. new (uno) add in functions
321 String
aIntName(ScGlobal::GetAddInCollection()->FindFunction( aUpper
, FALSE
));
326 return false; // no valid function name
330 void ScCompiler::InitCharClassEnglish()
332 ::com::sun::star::lang::Locale
aLocale(
333 OUString( RTL_CONSTASCII_USTRINGPARAM( "en")),
334 OUString( RTL_CONSTASCII_USTRINGPARAM( "US")),
336 pCharClassEnglish
= new CharClass(
337 ::comphelper::getProcessServiceFactory(), aLocale
);
341 void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar
)
343 DBG_ASSERT( eGrammar
!= FormulaGrammar::GRAM_UNSPECIFIED
, "ScCompiler::SetGrammar: don't pass FormulaGrammar::GRAM_UNSPECIFIED");
344 if (eGrammar
== GetGrammar())
345 return; // nothing to be done
347 if( eGrammar
== FormulaGrammar::GRAM_EXTERNAL
)
349 meGrammar
= eGrammar
;
350 mxSymbols
= GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE
);
354 FormulaGrammar::Grammar eMyGrammar
= eGrammar
;
355 const sal_Int32 nFormulaLanguage
= FormulaGrammar::extractFormulaLanguage( eMyGrammar
);
356 OpCodeMapPtr xMap
= GetOpCodeMap( nFormulaLanguage
);
357 DBG_ASSERT( xMap
, "ScCompiler::SetGrammar: unknown formula language");
360 xMap
= GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE
);
361 eMyGrammar
= xMap
->getGrammar();
364 // Save old grammar for call to SetGrammarAndRefConvention().
365 FormulaGrammar::Grammar eOldGrammar
= GetGrammar();
366 // This also sets the grammar associated with the map!
367 SetFormulaLanguage( xMap
);
369 // Override if necessary.
370 if (eMyGrammar
!= GetGrammar())
371 SetGrammarAndRefConvention( eMyGrammar
, eOldGrammar
);
375 void ScCompiler::SetEncodeUrlMode( EncodeUrlMode eMode
)
377 meEncodeUrlMode
= eMode
;
380 ScCompiler::EncodeUrlMode
ScCompiler::GetEncodeUrlMode() const
382 return meEncodeUrlMode
;
385 void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr
& xMap
)
390 if (mxSymbols
->isEnglish())
392 if (!pCharClassEnglish
)
393 InitCharClassEnglish();
394 pCharClass
= pCharClassEnglish
;
397 pCharClass
= ScGlobal::pCharClass
;
398 SetGrammarAndRefConvention( mxSymbols
->getGrammar(), GetGrammar());
403 void ScCompiler::SetGrammarAndRefConvention(
404 const FormulaGrammar::Grammar eNewGrammar
, const FormulaGrammar::Grammar eOldGrammar
)
406 meGrammar
= eNewGrammar
; //! SetRefConvention needs the new grammar set!
407 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::extractRefConvention( meGrammar
);
408 if (eConv
== FormulaGrammar::CONV_UNSPECIFIED
&& eOldGrammar
== FormulaGrammar::GRAM_UNSPECIFIED
)
411 SetRefConvention( pDoc
->GetAddressConvention());
413 SetRefConvention( pConvOOO_A1
);
416 SetRefConvention( eConv
);
419 String
ScCompiler::FindAddInFunction( const String
& rUpperName
, BOOL bLocalFirst
) const
421 return ScGlobal::GetAddInCollection()->FindFunction(rUpperName
, bLocalFirst
); // bLocalFirst=FALSE for english
426 void dbg_call_testcreatemapping()
428 using namespace ::com::sun::star::sheet
;
429 ScCompiler::OpCodeMapPtr xMap
= ScCompiler::GetOpCodeMap( FormulaLanguage::ODFF
);
430 xMap
->createSequenceOfAvailableMappings( FormulaMapGroup::FUNCTIONS
);
434 //-----------------------------------------------------------------------------
436 ScCompiler::Convention::~Convention()
438 delete [] mpCharTable
;
442 ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv
)
447 ULONG
*t
= new ULONG
[128];
449 ScCompiler::pConventions
[ meConv
] = this;
452 for (i
= 0; i
< 128; i
++)
453 t
[i
] = SC_COMPILER_C_ILLEGAL
;
455 /* */ t
[32] = SC_COMPILER_C_CHAR_DONTCARE
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
456 /* ! */ t
[33] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
457 if (FormulaGrammar::CONV_ODF
== meConv
)
458 /* ! */ t
[33] |= SC_COMPILER_C_ODF_LABEL_OP
;
459 /* " */ t
[34] = SC_COMPILER_C_CHAR_STRING
| SC_COMPILER_C_STRING_SEP
;
460 /* # */ t
[35] = SC_COMPILER_C_WORD_SEP
;
461 /* $ */ t
[36] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_IDENT
| SC_COMPILER_C_IDENT
;
462 if (FormulaGrammar::CONV_ODF
== meConv
)
463 /* $ */ t
[36] |= SC_COMPILER_C_ODF_NAME_MARKER
;
464 /* % */ t
[37] = SC_COMPILER_C_VALUE
;
465 /* & */ t
[38] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
466 /* ' */ t
[39] = SC_COMPILER_C_NAME_SEP
;
467 /* ( */ t
[40] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
468 /* ) */ t
[41] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
469 /* * */ t
[42] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
470 /* + */ t
[43] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_EXP
| SC_COMPILER_C_VALUE_SIGN
;
471 /* , */ t
[44] = SC_COMPILER_C_CHAR_VALUE
| SC_COMPILER_C_VALUE
;
472 /* - */ t
[45] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_EXP
| SC_COMPILER_C_VALUE_SIGN
;
473 /* . */ t
[46] = SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_VALUE
| SC_COMPILER_C_VALUE
| SC_COMPILER_C_IDENT
| SC_COMPILER_C_NAME
;
474 /* / */ t
[47] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
476 for (i
= 48; i
< 58; i
++)
477 /* 0-9 */ t
[i
] = SC_COMPILER_C_CHAR_VALUE
| SC_COMPILER_C_WORD
| SC_COMPILER_C_VALUE
| SC_COMPILER_C_VALUE_EXP
| SC_COMPILER_C_VALUE_VALUE
| SC_COMPILER_C_IDENT
| SC_COMPILER_C_NAME
;
479 /* : */ t
[58] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD
;
480 /* ; */ t
[59] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
481 /* < */ t
[60] = SC_COMPILER_C_CHAR_BOOL
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
482 /* = */ t
[61] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_BOOL
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
483 /* > */ t
[62] = SC_COMPILER_C_CHAR_BOOL
| SC_COMPILER_C_BOOL
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
484 /* ? */ t
[63] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
| SC_COMPILER_C_NAME
;
487 for (i
= 65; i
< 91; i
++)
488 /* A-Z */ t
[i
] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_IDENT
| SC_COMPILER_C_IDENT
| SC_COMPILER_C_CHAR_NAME
| SC_COMPILER_C_NAME
;
490 if (FormulaGrammar::CONV_ODF
== meConv
)
492 /* [ */ t
[91] = SC_COMPILER_C_ODF_LBRACKET
;
494 /* ] */ t
[93] = SC_COMPILER_C_ODF_RBRACKET
;
502 /* ^ */ t
[94] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
503 /* _ */ t
[95] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_IDENT
| SC_COMPILER_C_IDENT
| SC_COMPILER_C_CHAR_NAME
| SC_COMPILER_C_NAME
;
506 for (i
= 97; i
< 123; i
++)
507 /* a-z */ t
[i
] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_IDENT
| SC_COMPILER_C_IDENT
| SC_COMPILER_C_CHAR_NAME
| SC_COMPILER_C_NAME
;
509 /* { */ t
[123] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
; // array open
510 /* | */ t
[124] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
; // array row sep (Should be OOo specific)
511 /* } */ t
[125] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
; // array close
512 /* ~ */ t
[126] = SC_COMPILER_C_CHAR
; // OOo specific
515 if( FormulaGrammar::CONV_XL_A1
== meConv
|| FormulaGrammar::CONV_XL_R1C1
== meConv
|| FormulaGrammar::CONV_XL_OOX
== meConv
)
517 /* */ t
[32] |= SC_COMPILER_C_WORD
;
518 /* ! */ t
[33] |= SC_COMPILER_C_IDENT
| SC_COMPILER_C_WORD
;
519 /* " */ t
[34] |= SC_COMPILER_C_WORD
;
520 /* # */ t
[35] &= (~SC_COMPILER_C_WORD_SEP
);
521 /* # */ t
[35] |= SC_COMPILER_C_WORD
;
522 /* % */ t
[37] |= SC_COMPILER_C_WORD
;
523 /* ' */ t
[39] |= SC_COMPILER_C_WORD
;
525 /* % */ t
[37] |= SC_COMPILER_C_WORD
;
526 /* & */ t
[38] |= SC_COMPILER_C_WORD
;
527 /* ' */ t
[39] |= SC_COMPILER_C_WORD
;
528 /* ( */ t
[40] |= SC_COMPILER_C_WORD
;
529 /* ) */ t
[41] |= SC_COMPILER_C_WORD
;
530 /* * */ t
[42] |= SC_COMPILER_C_WORD
;
531 /* + */ t
[43] |= SC_COMPILER_C_WORD
;
532 #if 0 /* this really needs to be locale specific. */
533 /* , */ t
[44] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
535 /* , */ t
[44] |= SC_COMPILER_C_WORD
;
537 /* - */ t
[45] |= SC_COMPILER_C_WORD
;
539 /* ; */ t
[59] |= SC_COMPILER_C_WORD
;
540 /* < */ t
[60] |= SC_COMPILER_C_WORD
;
541 /* = */ t
[61] |= SC_COMPILER_C_WORD
;
542 /* > */ t
[62] |= SC_COMPILER_C_WORD
;
543 /* ? */ // question really is not permitted in sheet name
544 /* @ */ t
[64] |= SC_COMPILER_C_WORD
;
545 /* [ */ t
[91] |= SC_COMPILER_C_WORD
;
546 /* ] */ t
[93] |= SC_COMPILER_C_WORD
;
547 /* { */ t
[123]|= SC_COMPILER_C_WORD
;
548 /* | */ t
[124]|= SC_COMPILER_C_WORD
;
549 /* } */ t
[125]|= SC_COMPILER_C_WORD
;
550 /* ~ */ t
[126]|= SC_COMPILER_C_WORD
;
552 if( FormulaGrammar::CONV_XL_R1C1
== meConv
)
554 /* - */ t
[45] |= SC_COMPILER_C_IDENT
;
555 /* [ */ t
[91] |= SC_COMPILER_C_IDENT
;
556 /* ] */ t
[93] |= SC_COMPILER_C_IDENT
;
558 if( FormulaGrammar::CONV_XL_OOX
== meConv
)
560 /* [ */ t
[91] |= SC_COMPILER_C_CHAR_IDENT
;
561 /* ] */ t
[93] |= SC_COMPILER_C_IDENT
;
566 //-----------------------------------------------------------------------------
568 static bool lcl_isValidQuotedText( const String
& rFormula
, xub_StrLen nSrcPos
, ParseResult
& rRes
)
570 // Tokens that start at ' can have anything in them until a final '
571 // but '' marks an escaped '
572 // We've earlier guaranteed that a string containing '' will be
574 if (rFormula
.GetChar(nSrcPos
) == '\'')
576 xub_StrLen nPos
= nSrcPos
+1;
577 while (nPos
< rFormula
.Len())
579 if (rFormula
.GetChar(nPos
) == '\'')
581 if ( (nPos
+1 == rFormula
.Len()) || (rFormula
.GetChar(nPos
+1) != '\'') )
583 rRes
.TokenType
= KParseType::SINGLE_QUOTE_NAME
;
584 rRes
.EndPos
= nPos
+1;
596 static bool lcl_parseExternalName(
597 const String
& rSymbol
,
600 const sal_Unicode cSep
,
601 const ScDocument
* pDoc
= NULL
,
602 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
= NULL
)
604 /* TODO: future versions will have to support sheet-local names too, thus
605 * return a possible sheet name as well. */
606 const sal_Unicode
* const pStart
= rSymbol
.GetBuffer();
607 const sal_Unicode
* p
= pStart
;
608 xub_StrLen nLen
= rSymbol
.Len();
609 sal_Unicode cPrev
= 0;
610 String aTmpFile
, aTmpName
;
612 bool bInName
= false;
615 // For XL use existing parser that resolves bracketed and quoted and
616 // indexed external document names.
618 String aStartTabName
, aEndTabName
;
620 p
= aRange
.Parse_XL_Header( p
, pDoc
, aTmpFile
, aStartTabName
,
621 aEndTabName
, nFlags
, true, pExternalLinks
);
622 if (!p
|| p
== pStart
)
624 i
= xub_StrLen(p
- pStart
);
627 for ( ; i
< nLen
; ++i
, ++p
)
632 if (c
== '.' || c
== cSep
)
637 // Move to the next chart and loop until the second single
641 for (xub_StrLen j
= i
; j
< nLen
; ++j
, ++p
)
648 // empty quote e.g. (=''!Name)
654 // two consecutive quotes equals a single
655 // quote in the file name.
665 if (cPrev
== '\'' && j
!= i
)
667 // this is not a quote but the previous one
668 // is. This ends the parsing of the quoted
681 // premature ending of the quoted segment.
687 // only the separator is allowed after the closing quote.
700 // A second separator ? Not a valid external name.
715 if (CharClass::isAsciiAlphaNumeric(c
))
720 // non-ASCII character is allowed.
729 // these special characters are allowed.
747 // No name found - most likely the symbol has no '!'s.
756 static String
lcl_makeExternalNameStr( const String
& rFile
, const String
& rName
,
757 const sal_Unicode cSep
, bool bODF
)
759 String
aFile( rFile
), aName( rName
), aEscQuote( RTL_CONSTASCII_USTRINGPARAM("''"));
760 aFile
.SearchAndReplaceAllAscii( "'", aEscQuote
);
762 aName
.SearchAndReplaceAllAscii( "'", aEscQuote
);
763 rtl::OUStringBuffer
aBuf( aFile
.Len() + aName
.Len() + 9);
765 aBuf
.append( sal_Unicode( '['));
766 aBuf
.append( sal_Unicode( '\''));
768 aBuf
.append( sal_Unicode( '\''));
771 aBuf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "$$'"));
774 aBuf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "']"));
775 return String( aBuf
.makeStringAndClear());
778 static bool lcl_getLastTabName( String
& rTabName2
, const String
& rTabName1
,
779 const vector
<String
>& rTabNames
, const ScComplexRefData
& rRef
)
781 SCsTAB nTabSpan
= rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
;
784 size_t nCount
= rTabNames
.size();
785 vector
<String
>::const_iterator itrBeg
= rTabNames
.begin(), itrEnd
= rTabNames
.end();
786 vector
<String
>::const_iterator itr
= ::std::find(itrBeg
, itrEnd
, rTabName1
);
787 if (itr
== rTabNames
.end())
789 rTabName2
= ScGlobal::GetRscString(STR_NO_REF_TABLE
);
793 size_t nDist
= ::std::distance(itrBeg
, itr
);
794 if (nDist
+ static_cast<size_t>(nTabSpan
) >= nCount
)
796 rTabName2
= ScGlobal::GetRscString(STR_NO_REF_TABLE
);
800 rTabName2
= rTabNames
[nDist
+nTabSpan
];
803 rTabName2
= rTabName1
;
808 struct Convention_A1
: public ScCompiler::Convention
810 Convention_A1( FormulaGrammar::AddressConvention eConv
) : ScCompiler::Convention( eConv
) { }
811 static void MakeColStr( rtl::OUStringBuffer
& rBuffer
, SCCOL nCol
);
812 static void MakeRowStr( rtl::OUStringBuffer
& rBuffer
, SCROW nRow
);
814 ParseResult
parseAnyToken( const String
& rFormula
,
816 const CharClass
* pCharClass
) const
819 if ( lcl_isValidQuotedText(rFormula
, nSrcPos
, aRet
) )
822 static const sal_Int32 nStartFlags
= KParseTokens::ANY_LETTER_OR_NUMBER
|
823 KParseTokens::ASC_UNDERSCORE
| KParseTokens::ASC_DOLLAR
;
824 static const sal_Int32 nContFlags
= nStartFlags
| KParseTokens::ASC_DOT
;
825 // '?' allowed in range names because of Xcl :-/
826 static const String
aAddAllowed(String::CreateFromAscii("?#"));
827 return pCharClass
->parseAnyToken( rFormula
,
828 nSrcPos
, nStartFlags
, aAddAllowed
, nContFlags
, aAddAllowed
);
832 void Convention_A1::MakeColStr( rtl::OUStringBuffer
& rBuffer
, SCCOL nCol
)
834 if ( !ValidCol( nCol
) )
835 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
837 ::ScColToAlpha( rBuffer
, nCol
);
840 void Convention_A1::MakeRowStr( rtl::OUStringBuffer
& rBuffer
, SCROW nRow
)
842 if ( !ValidRow(nRow
) )
843 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
845 rBuffer
.append(sal_Int32(nRow
+ 1));
848 //-----------------------------------------------------------------------------
850 struct ConventionOOO_A1
: public Convention_A1
852 ConventionOOO_A1() : Convention_A1 (FormulaGrammar::CONV_OOO
) { }
853 ConventionOOO_A1( FormulaGrammar::AddressConvention eConv
) : Convention_A1 (eConv
) { }
854 static String
MakeTabStr( const ScCompiler
& rComp
, SCTAB nTab
, String
& aDoc
)
857 if (!rComp
.GetDoc()->GetName( nTab
, aString
))
858 aString
= ScGlobal::GetRscString(STR_NO_REF_TABLE
);
861 if ( aString
.GetChar(0) == '\'' )
863 xub_StrLen nPos
= ScGlobal::FindUnquoted( aString
, SC_COMPILER_FILE_TAB_SEP
);
864 if (nPos
!= STRING_NOTFOUND
&& nPos
> 0 && aString
.GetChar(nPos
-1) == '\'')
866 aDoc
= aString
.Copy( 0, nPos
+ 1 );
867 aString
.Erase( 0, nPos
+ 1 );
868 aDoc
= INetURLObject::decode( aDoc
, INET_HEX_ESCAPE
,
869 INetURLObject::DECODE_UNAMBIGUOUS
);
876 ScCompiler::CheckTabQuotes( aString
, FormulaGrammar::CONV_OOO
);
882 void MakeRefStrImpl( rtl::OUStringBuffer
& rBuffer
,
883 const ScCompiler
& rComp
,
884 const ScComplexRefData
& rRef
,
889 rBuffer
.append(sal_Unicode('['));
890 ScComplexRefData
aRef( rRef
);
891 // In case absolute/relative positions weren't separately available:
892 // transform relative to absolute!
893 // AdjustReference( aRef.Ref1 );
895 // AdjustReference( aRef.Ref2 );
896 aRef
.Ref1
.CalcAbsIfRel( rComp
.GetPos() );
898 aRef
.Ref2
.CalcAbsIfRel( rComp
.GetPos() );
899 if( aRef
.Ref1
.IsFlag3D() )
901 if (aRef
.Ref1
.IsTabDeleted())
903 if (!aRef
.Ref1
.IsTabRel())
904 rBuffer
.append(sal_Unicode('$'));
905 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
906 rBuffer
.append(sal_Unicode('.'));
911 String
aRefStr( MakeTabStr( rComp
, aRef
.Ref1
.nTab
, aDoc
) );
912 rBuffer
.append(aDoc
);
913 if (!aRef
.Ref1
.IsTabRel()) rBuffer
.append(sal_Unicode('$'));
914 rBuffer
.append(aRefStr
);
918 rBuffer
.append(sal_Unicode('.'));
919 if (!aRef
.Ref1
.IsColRel())
920 rBuffer
.append(sal_Unicode('$'));
921 if ( aRef
.Ref1
.IsColDeleted() )
922 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
924 MakeColStr(rBuffer
, aRef
.Ref1
.nCol
);
925 if (!aRef
.Ref1
.IsRowRel())
926 rBuffer
.append(sal_Unicode('$'));
927 if ( aRef
.Ref1
.IsRowDeleted() )
928 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
930 MakeRowStr( rBuffer
, aRef
.Ref1
.nRow
);
933 rBuffer
.append(sal_Unicode(':'));
934 if (aRef
.Ref2
.IsFlag3D() || aRef
.Ref2
.nTab
!= aRef
.Ref1
.nTab
)
936 if (aRef
.Ref2
.IsTabDeleted())
938 if (!aRef
.Ref2
.IsTabRel())
939 rBuffer
.append(sal_Unicode('$'));
940 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
941 rBuffer
.append(sal_Unicode('.'));
946 String
aRefStr( MakeTabStr( rComp
, aRef
.Ref2
.nTab
, aDoc
) );
947 rBuffer
.append(aDoc
);
948 if (!aRef
.Ref2
.IsTabRel()) rBuffer
.append(sal_Unicode('$'));
949 rBuffer
.append(aRefStr
);
953 rBuffer
.append(sal_Unicode('.'));
954 if (!aRef
.Ref2
.IsColRel())
955 rBuffer
.append(sal_Unicode('$'));
956 if ( aRef
.Ref2
.IsColDeleted() )
957 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
959 MakeColStr( rBuffer
, aRef
.Ref2
.nCol
);
960 if (!aRef
.Ref2
.IsRowRel())
961 rBuffer
.append(sal_Unicode('$'));
962 if ( aRef
.Ref2
.IsRowDeleted() )
963 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
965 MakeRowStr( rBuffer
, aRef
.Ref2
.nRow
);
968 rBuffer
.append(sal_Unicode(']'));
971 void MakeRefStr( rtl::OUStringBuffer
& rBuffer
,
972 const ScCompiler
& rComp
,
973 const ScComplexRefData
& rRef
,
974 BOOL bSingleRef
) const
976 MakeRefStrImpl( rBuffer
, rComp
, rRef
, bSingleRef
, false);
979 virtual sal_Unicode
getSpecialSymbol( SpecialSymbolType eSymType
) const
983 case ScCompiler::Convention::ABS_SHEET_PREFIX
:
985 case ScCompiler::Convention::SHEET_SEPARATOR
:
989 return sal_Unicode(0);
992 virtual bool parseExternalName( const String
& rSymbol
, String
& rFile
, String
& rName
,
993 const ScDocument
* pDoc
,
994 const ::com::sun::star::uno::Sequence
<
995 const ::com::sun::star::sheet::ExternalLinkInfo
> * pExternalLinks
) const
997 return lcl_parseExternalName(rSymbol
, rFile
, rName
, sal_Unicode('#'), pDoc
, pExternalLinks
);
1000 virtual String
makeExternalNameStr( const String
& rFile
, const String
& rName
) const
1002 return lcl_makeExternalNameStr( rFile
, rName
, sal_Unicode('#'), false);
1005 bool makeExternalSingleRefStr( ::rtl::OUStringBuffer
& rBuffer
, sal_uInt16 nFileId
,
1006 const String
& rTabName
, const ScSingleRefData
& rRef
,
1007 ScExternalRefManager
* pRefMgr
, bool bDisplayTabName
, bool bEncodeUrl
) const
1009 if (bDisplayTabName
)
1012 const String
* p
= pRefMgr
->getExternalFileName(nFileId
);
1018 aFile
= INetURLObject::decode(*p
, INET_HEX_ESCAPE
, INetURLObject::DECODE_UNAMBIGUOUS
);
1020 aFile
.SearchAndReplaceAllAscii("'", String::CreateFromAscii("''"));
1022 rBuffer
.append(sal_Unicode('\''));
1023 rBuffer
.append(aFile
);
1024 rBuffer
.append(sal_Unicode('\''));
1025 rBuffer
.append(sal_Unicode('#'));
1027 if (!rRef
.IsTabRel())
1028 rBuffer
.append(sal_Unicode('$'));
1029 ScRangeStringConverter::AppendTableName(rBuffer
, rTabName
);
1031 rBuffer
.append(sal_Unicode('.'));
1034 if (!rRef
.IsColRel())
1035 rBuffer
.append(sal_Unicode('$'));
1036 MakeColStr( rBuffer
, rRef
.nCol
);
1037 if (!rRef
.IsRowRel())
1038 rBuffer
.append(sal_Unicode('$'));
1039 MakeRowStr( rBuffer
, rRef
.nRow
);
1044 void makeExternalRefStrImpl( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1045 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1046 ScExternalRefManager
* pRefMgr
, bool bODF
) const
1048 ScSingleRefData
aRef(rRef
);
1049 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1052 rBuffer
.append( sal_Unicode('['));
1054 bool bEncodeUrl
= true;
1055 switch (rCompiler
.GetEncodeUrlMode())
1057 case ScCompiler::ENCODE_BY_GRAMMAR
:
1060 case ScCompiler::ENCODE_ALWAYS
:
1063 case ScCompiler::ENCODE_NEVER
:
1069 makeExternalSingleRefStr(rBuffer
, nFileId
, rTabName
, aRef
, pRefMgr
, true, bEncodeUrl
);
1071 rBuffer
.append( sal_Unicode(']'));
1074 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1075 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1076 ScExternalRefManager
* pRefMgr
) const
1078 makeExternalRefStrImpl( rBuffer
, rCompiler
, nFileId
, rTabName
, rRef
, pRefMgr
, false);
1081 void makeExternalRefStrImpl( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1082 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1083 ScExternalRefManager
* pRefMgr
, bool bODF
) const
1085 ScComplexRefData
aRef(rRef
);
1086 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1089 rBuffer
.append( sal_Unicode('['));
1090 // Ensure that there's always a closing bracket, no premature returns.
1091 bool bEncodeUrl
= true;
1092 switch (rCompiler
.GetEncodeUrlMode())
1094 case ScCompiler::ENCODE_BY_GRAMMAR
:
1097 case ScCompiler::ENCODE_ALWAYS
:
1100 case ScCompiler::ENCODE_NEVER
:
1109 if (!makeExternalSingleRefStr(rBuffer
, nFileId
, rTabName
, aRef
.Ref1
, pRefMgr
, true, bEncodeUrl
))
1112 rBuffer
.append(sal_Unicode(':'));
1114 String aLastTabName
;
1115 bool bDisplayTabName
= (aRef
.Ref1
.nTab
!= aRef
.Ref2
.nTab
);
1116 if (bDisplayTabName
)
1118 // Get the name of the last table.
1119 vector
<String
> aTabNames
;
1120 pRefMgr
->getAllCachedTableNames(nFileId
, aTabNames
);
1121 if (aTabNames
.empty())
1123 DBG_ERROR1( "ConventionOOO_A1::makeExternalRefStrImpl: no sheet names for document ID %s", nFileId
);
1126 if (!lcl_getLastTabName(aLastTabName
, rTabName
, aTabNames
, aRef
))
1128 DBG_ERROR( "ConventionOOO_A1::makeExternalRefStrImpl: sheet name not found");
1129 // aLastTabName contains #REF!, proceed.
1133 rBuffer
.append( sal_Unicode('.')); // need at least the sheet separator in ODF
1134 makeExternalSingleRefStr( rBuffer
, nFileId
, aLastTabName
,
1135 aRef
.Ref2
, pRefMgr
, bDisplayTabName
, bEncodeUrl
);
1138 rBuffer
.append( sal_Unicode(']'));
1141 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1142 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1143 ScExternalRefManager
* pRefMgr
) const
1145 makeExternalRefStrImpl( rBuffer
, rCompiler
, nFileId
, rTabName
, rRef
, pRefMgr
, false);
1150 static const ConventionOOO_A1 ConvOOO_A1
;
1151 const ScCompiler::Convention
* const ScCompiler::pConvOOO_A1
= &ConvOOO_A1
;
1153 //-----------------------------------------------------------------------------
1155 struct ConventionOOO_A1_ODF
: public ConventionOOO_A1
1157 ConventionOOO_A1_ODF() : ConventionOOO_A1 (FormulaGrammar::CONV_ODF
) { }
1158 void MakeRefStr( rtl::OUStringBuffer
& rBuffer
,
1159 const ScCompiler
& rComp
,
1160 const ScComplexRefData
& rRef
,
1161 BOOL bSingleRef
) const
1163 MakeRefStrImpl( rBuffer
, rComp
, rRef
, bSingleRef
, true);
1166 virtual String
makeExternalNameStr( const String
& rFile
, const String
& rName
) const
1168 return lcl_makeExternalNameStr( rFile
, rName
, sal_Unicode('#'), true);
1171 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1172 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1173 ScExternalRefManager
* pRefMgr
) const
1175 makeExternalRefStrImpl( rBuffer
, rCompiler
, nFileId
, rTabName
, rRef
, pRefMgr
, true);
1178 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1179 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1180 ScExternalRefManager
* pRefMgr
) const
1182 makeExternalRefStrImpl( rBuffer
, rCompiler
, nFileId
, rTabName
, rRef
, pRefMgr
, true);
1186 static const ConventionOOO_A1_ODF ConvOOO_A1_ODF
;
1187 const ScCompiler::Convention
* const ScCompiler::pConvOOO_A1_ODF
= &ConvOOO_A1_ODF
;
1189 //-----------------------------------------------------------------------------
1193 static bool GetDocAndTab( const ScCompiler
& rComp
,
1194 const ScSingleRefData
& rRef
,
1198 bool bHasDoc
= false;
1201 if (rRef
.IsTabDeleted() ||
1202 !rComp
.GetDoc()->GetName( rRef
.nTab
, rTabName
))
1204 rTabName
= ScGlobal::GetRscString( STR_NO_REF_TABLE
);
1208 // Cheesy hack to unparse the OOO style "'Doc'#Tab"
1209 if ( rTabName
.GetChar(0) == '\'' )
1211 xub_StrLen nPos
= ScGlobal::FindUnquoted( rTabName
, SC_COMPILER_FILE_TAB_SEP
);
1212 if (nPos
!= STRING_NOTFOUND
&& nPos
> 0 && rTabName
.GetChar(nPos
-1) == '\'')
1214 rDocName
= rTabName
.Copy( 0, nPos
);
1215 // TODO : More research into how XL escapes the doc path
1216 rDocName
= INetURLObject::decode( rDocName
, INET_HEX_ESCAPE
,
1217 INetURLObject::DECODE_UNAMBIGUOUS
);
1218 rTabName
.Erase( 0, nPos
+ 1 );
1223 // XL uses the same sheet name quoting conventions in both modes
1224 // it is safe to use A1 here
1225 ScCompiler::CheckTabQuotes( rTabName
, FormulaGrammar::CONV_XL_A1
);
1229 static void MakeDocStr( rtl::OUStringBuffer
& rBuf
,
1230 const ScCompiler
& rComp
,
1231 const ScComplexRefData
& rRef
,
1234 if( rRef
.Ref1
.IsFlag3D() )
1236 String aStartTabName
, aStartDocName
, aEndTabName
, aEndDocName
;
1237 bool bStartHasDoc
= false, bEndHasDoc
= false;
1239 bStartHasDoc
= GetDocAndTab( rComp
, rRef
.Ref1
,
1240 aStartDocName
, aStartTabName
);
1242 if( !bSingleRef
&& rRef
.Ref2
.IsFlag3D() )
1244 bEndHasDoc
= GetDocAndTab( rComp
, rRef
.Ref2
,
1245 aEndDocName
, aEndTabName
);
1248 bEndHasDoc
= bStartHasDoc
;
1252 // A ref across multipled workbooks ?
1256 rBuf
.append( sal_Unicode( '[' ) );
1257 rBuf
.append( aStartDocName
);
1258 rBuf
.append( sal_Unicode( ']' ) );
1261 rBuf
.append( aStartTabName
);
1262 if( !bSingleRef
&& rRef
.Ref2
.IsFlag3D() && aStartTabName
!= aEndTabName
)
1264 rBuf
.append( sal_Unicode( ':' ) );
1265 rBuf
.append( aEndTabName
);
1268 rBuf
.append( sal_Unicode( '!' ) );
1272 static sal_Unicode
getSpecialSymbol( ScCompiler::Convention::SpecialSymbolType eSymType
)
1276 case ScCompiler::Convention::ABS_SHEET_PREFIX
:
1277 return sal_Unicode(0);
1278 case ScCompiler::Convention::SHEET_SEPARATOR
:
1281 return sal_Unicode(0);
1284 static bool parseExternalName( const String
& rSymbol
, String
& rFile
, String
& rName
,
1285 const ScDocument
* pDoc
,
1286 const ::com::sun::star::uno::Sequence
<
1287 const ::com::sun::star::sheet::ExternalLinkInfo
> * pExternalLinks
)
1289 return lcl_parseExternalName( rSymbol
, rFile
, rName
, sal_Unicode('!'), pDoc
, pExternalLinks
);
1292 static String
makeExternalNameStr( const String
& rFile
, const String
& rName
)
1294 return lcl_makeExternalNameStr( rFile
, rName
, sal_Unicode('!'), false);
1297 static void makeExternalDocStr( ::rtl::OUStringBuffer
& rBuffer
, const String
& rFullName
, bool bEncodeUrl
)
1299 // Format that is easier to deal with inside OOo, because we use file
1300 // URL, and all characetrs are allowed. Check if it makes sense to do
1301 // it the way Gnumeric does it. Gnumeric doesn't use the URL form
1302 // and allows relative file path.
1304 // ['file:///path/to/source/filename.xls']
1306 rBuffer
.append(sal_Unicode('['));
1307 rBuffer
.append(sal_Unicode('\''));
1310 aFullName
= rFullName
;
1312 aFullName
= INetURLObject::decode(rFullName
, INET_HEX_ESCAPE
, INetURLObject::DECODE_UNAMBIGUOUS
);
1314 const sal_Unicode
* pBuf
= aFullName
.GetBuffer();
1315 xub_StrLen nLen
= aFullName
.Len();
1316 for (xub_StrLen i
= 0; i
< nLen
; ++i
)
1318 const sal_Unicode c
= pBuf
[i
];
1319 if (c
== sal_Unicode('\''))
1323 rBuffer
.append(sal_Unicode('\''));
1324 rBuffer
.append(sal_Unicode(']'));
1327 static void makeExternalTabNameRange( ::rtl::OUStringBuffer
& rBuf
, const String
& rTabName
,
1328 const vector
<String
>& rTabNames
,
1329 const ScComplexRefData
& rRef
)
1331 String aLastTabName
;
1332 if (!lcl_getLastTabName(aLastTabName
, rTabName
, rTabNames
, rRef
))
1334 ScRangeStringConverter::AppendTableName(rBuf
, aLastTabName
);
1338 ScRangeStringConverter::AppendTableName(rBuf
, rTabName
);
1339 if (rTabName
!= aLastTabName
)
1341 rBuf
.append(sal_Unicode(':'));
1342 ScRangeStringConverter::AppendTableName(rBuf
, rTabName
);
1346 static void parseExternalDocName( const String
& rFormula
, xub_StrLen
& rSrcPos
)
1348 xub_StrLen nLen
= rFormula
.Len();
1349 const sal_Unicode
* p
= rFormula
.GetBuffer();
1350 sal_Unicode cPrev
= 0;
1351 for (xub_StrLen i
= rSrcPos
; i
< nLen
; ++i
)
1353 sal_Unicode c
= p
[i
];
1356 // first character must be '['.
1360 else if (i
== rSrcPos
+ 1)
1362 // second character must be a single quote.
1369 // two successive single quote is treated as a single
1377 // valid source document path found. Increment the
1378 // current position to skip the source path.
1380 if (rSrcPos
>= nLen
)
1389 // any other character
1390 if (i
> rSrcPos
+ 2 && cPrev
== '\'')
1391 // unless it's the 3rd character, a normal character
1392 // following immediately a single quote is invalid.
1400 struct ConventionXL_A1
: public Convention_A1
, public ConventionXL
1402 ConventionXL_A1() : Convention_A1( FormulaGrammar::CONV_XL_A1
) { }
1403 ConventionXL_A1( FormulaGrammar::AddressConvention eConv
) : Convention_A1( eConv
) { }
1405 void makeSingleCellStr( ::rtl::OUStringBuffer
& rBuf
, const ScSingleRefData
& rRef
) const
1407 if (!rRef
.IsColRel())
1408 rBuf
.append(sal_Unicode('$'));
1409 MakeColStr(rBuf
, rRef
.nCol
);
1410 if (!rRef
.IsRowRel())
1411 rBuf
.append(sal_Unicode('$'));
1412 MakeRowStr(rBuf
, rRef
.nRow
);
1415 void MakeRefStr( rtl::OUStringBuffer
& rBuf
,
1416 const ScCompiler
& rComp
,
1417 const ScComplexRefData
& rRef
,
1418 BOOL bSingleRef
) const
1420 ScComplexRefData
aRef( rRef
);
1422 // Play fast and loose with invalid refs. There is not much point in producing
1423 // Foo!A1:#REF! versus #REF! at this point
1424 aRef
.Ref1
.CalcAbsIfRel( rComp
.GetPos() );
1426 MakeDocStr( rBuf
, rComp
, aRef
, bSingleRef
);
1428 if( aRef
.Ref1
.IsColDeleted() || aRef
.Ref1
.IsRowDeleted() )
1430 rBuf
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1436 aRef
.Ref2
.CalcAbsIfRel( rComp
.GetPos() );
1437 if( aRef
.Ref2
.IsColDeleted() || aRef
.Ref2
.IsRowDeleted() )
1439 rBuf
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1443 if( aRef
.Ref1
.nCol
== 0 && aRef
.Ref2
.nCol
>= MAXCOL
)
1445 if (!aRef
.Ref1
.IsRowRel())
1446 rBuf
.append(sal_Unicode( '$' ));
1447 MakeRowStr( rBuf
, aRef
.Ref1
.nRow
);
1448 rBuf
.append(sal_Unicode( ':' ));
1449 if (!aRef
.Ref2
.IsRowRel())
1450 rBuf
.append(sal_Unicode( '$' ));
1451 MakeRowStr( rBuf
, aRef
.Ref2
.nRow
);
1455 if( aRef
.Ref1
.nRow
== 0 && aRef
.Ref2
.nRow
>= MAXROW
)
1457 if (!aRef
.Ref1
.IsColRel())
1458 rBuf
.append(sal_Unicode( '$' ));
1459 MakeColStr(rBuf
, aRef
.Ref1
.nCol
);
1460 rBuf
.append(sal_Unicode( ':' ));
1461 if (!aRef
.Ref2
.IsColRel())
1462 rBuf
.append(sal_Unicode( '$' ));
1463 MakeColStr(rBuf
, aRef
.Ref2
.nCol
);
1468 makeSingleCellStr(rBuf
, aRef
.Ref1
);
1471 rBuf
.append(sal_Unicode( ':' ));
1472 makeSingleCellStr(rBuf
, aRef
.Ref2
);
1476 virtual ParseResult
parseAnyToken( const String
& rFormula
,
1478 const CharClass
* pCharClass
) const
1481 if ( lcl_isValidQuotedText(rFormula
, nSrcPos
, aRet
) )
1484 static const sal_Int32 nStartFlags
= KParseTokens::ANY_LETTER_OR_NUMBER
|
1485 KParseTokens::ASC_UNDERSCORE
| KParseTokens::ASC_DOLLAR
;
1486 static const sal_Int32 nContFlags
= nStartFlags
| KParseTokens::ASC_DOT
;
1487 // '?' allowed in range names
1488 static const String aAddAllowed
= String::CreateFromAscii("?!");
1489 return pCharClass
->parseAnyToken( rFormula
,
1490 nSrcPos
, nStartFlags
, aAddAllowed
, nContFlags
, aAddAllowed
);
1493 virtual sal_Unicode
getSpecialSymbol( SpecialSymbolType eSymType
) const
1495 return ConventionXL::getSpecialSymbol(eSymType
);
1498 virtual bool parseExternalName( const String
& rSymbol
, String
& rFile
, String
& rName
,
1499 const ScDocument
* pDoc
,
1500 const ::com::sun::star::uno::Sequence
<
1501 const ::com::sun::star::sheet::ExternalLinkInfo
> * pExternalLinks
) const
1503 return ConventionXL::parseExternalName( rSymbol
, rFile
, rName
, pDoc
, pExternalLinks
);
1506 virtual String
makeExternalNameStr( const String
& rFile
, const String
& rName
) const
1508 return ConventionXL::makeExternalNameStr(rFile
, rName
);
1511 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1512 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1513 ScExternalRefManager
* pRefMgr
) const
1515 // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
1516 // This is a little different from the format Excel uses, as Excel
1517 // puts [] only around the file name. But we need to enclose the
1518 // whole file path with [] because the file name can contain any
1521 const String
* pFullName
= pRefMgr
->getExternalFileName(nFileId
);
1525 ScSingleRefData
aRef(rRef
);
1526 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1528 ConventionXL::makeExternalDocStr(
1529 rBuffer
, *pFullName
, rCompiler
.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS
);
1530 ScRangeStringConverter::AppendTableName(rBuffer
, rTabName
);
1531 rBuffer
.append(sal_Unicode('!'));
1533 makeSingleCellStr(rBuffer
, aRef
);
1536 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1537 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1538 ScExternalRefManager
* pRefMgr
) const
1540 const String
* pFullName
= pRefMgr
->getExternalFileName(nFileId
);
1544 vector
<String
> aTabNames
;
1545 pRefMgr
->getAllCachedTableNames(nFileId
, aTabNames
);
1546 if (aTabNames
.empty())
1549 ScComplexRefData
aRef(rRef
);
1550 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1552 ConventionXL::makeExternalDocStr(
1553 rBuffer
, *pFullName
, rCompiler
.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS
);
1554 ConventionXL::makeExternalTabNameRange(rBuffer
, rTabName
, aTabNames
, aRef
);
1555 rBuffer
.append(sal_Unicode('!'));
1557 makeSingleCellStr(rBuffer
, aRef
.Ref1
);
1558 if (aRef
.Ref1
!= aRef
.Ref2
)
1560 rBuffer
.append(sal_Unicode(':'));
1561 makeSingleCellStr(rBuffer
, aRef
.Ref2
);
1566 static const ConventionXL_A1 ConvXL_A1
;
1567 const ScCompiler::Convention
* const ScCompiler::pConvXL_A1
= &ConvXL_A1
;
1570 struct ConventionXL_OOX
: public ConventionXL_A1
1572 ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX
) { }
1575 static const ConventionXL_OOX ConvXL_OOX
;
1576 const ScCompiler::Convention
* const ScCompiler::pConvXL_OOX
= &ConvXL_OOX
;
1579 //-----------------------------------------------------------------------------
1582 r1c1_add_col( rtl::OUStringBuffer
&rBuf
, const ScSingleRefData
& rRef
)
1584 rBuf
.append( sal_Unicode( 'C' ) );
1585 if( rRef
.IsColRel() )
1587 if (rRef
.nRelCol
!= 0)
1589 rBuf
.append( sal_Unicode( '[' ) );
1590 rBuf
.append( String::CreateFromInt32( rRef
.nRelCol
) );
1591 rBuf
.append( sal_Unicode( ']' ) );
1595 rBuf
.append( String::CreateFromInt32( rRef
.nCol
+ 1 ) );
1598 r1c1_add_row( rtl::OUStringBuffer
&rBuf
, const ScSingleRefData
& rRef
)
1600 rBuf
.append( sal_Unicode( 'R' ) );
1601 if( rRef
.IsRowRel() )
1603 if (rRef
.nRelRow
!= 0)
1605 rBuf
.append( sal_Unicode( '[' ) );
1606 rBuf
.append( String::CreateFromInt32( rRef
.nRelRow
) );
1607 rBuf
.append( sal_Unicode( ']' ) );
1611 rBuf
.append( String::CreateFromInt32( rRef
.nRow
+ 1 ) );
1614 struct ConventionXL_R1C1
: public ScCompiler::Convention
, public ConventionXL
1616 ConventionXL_R1C1() : ScCompiler::Convention( FormulaGrammar::CONV_XL_R1C1
) { }
1617 void MakeRefStr( rtl::OUStringBuffer
& rBuf
,
1618 const ScCompiler
& rComp
,
1619 const ScComplexRefData
& rRef
,
1620 BOOL bSingleRef
) const
1622 ScComplexRefData
aRef( rRef
);
1624 MakeDocStr( rBuf
, rComp
, aRef
, bSingleRef
);
1626 // Play fast and loose with invalid refs. There is not much point in producing
1627 // Foo!A1:#REF! versus #REF! at this point
1628 aRef
.Ref1
.CalcAbsIfRel( rComp
.GetPos() );
1629 if( aRef
.Ref1
.IsColDeleted() || aRef
.Ref1
.IsRowDeleted() )
1631 rBuf
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1637 aRef
.Ref2
.CalcAbsIfRel( rComp
.GetPos() );
1638 if( aRef
.Ref2
.IsColDeleted() || aRef
.Ref2
.IsRowDeleted() )
1640 rBuf
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1644 if( aRef
.Ref1
.nCol
== 0 && aRef
.Ref2
.nCol
>= MAXCOL
)
1646 r1c1_add_row( rBuf
, rRef
.Ref1
);
1647 if( rRef
.Ref1
.nRow
!= rRef
.Ref2
.nRow
||
1648 rRef
.Ref1
.IsRowRel() != rRef
.Ref2
.IsRowRel() ) {
1649 rBuf
.append (sal_Unicode ( ':' ) );
1650 r1c1_add_row( rBuf
, rRef
.Ref2
);
1656 if( aRef
.Ref1
.nRow
== 0 && aRef
.Ref2
.nRow
>= MAXROW
)
1658 r1c1_add_col( rBuf
, rRef
.Ref1
);
1659 if( rRef
.Ref1
.nCol
!= rRef
.Ref2
.nCol
||
1660 rRef
.Ref1
.IsColRel() != rRef
.Ref2
.IsColRel() )
1662 rBuf
.append (sal_Unicode ( ':' ) );
1663 r1c1_add_col( rBuf
, rRef
.Ref2
);
1669 r1c1_add_row( rBuf
, rRef
.Ref1
);
1670 r1c1_add_col( rBuf
, rRef
.Ref1
);
1673 rBuf
.append (sal_Unicode ( ':' ) );
1674 r1c1_add_row( rBuf
, rRef
.Ref2
);
1675 r1c1_add_col( rBuf
, rRef
.Ref2
);
1679 ParseResult
parseAnyToken( const String
& rFormula
,
1681 const CharClass
* pCharClass
) const
1683 ConventionXL::parseExternalDocName(rFormula
, nSrcPos
);
1686 if ( lcl_isValidQuotedText(rFormula
, nSrcPos
, aRet
) )
1689 static const sal_Int32 nStartFlags
= KParseTokens::ANY_LETTER_OR_NUMBER
|
1690 KParseTokens::ASC_UNDERSCORE
;
1691 static const sal_Int32 nContFlags
= nStartFlags
| KParseTokens::ASC_DOT
;
1692 // '?' allowed in range names
1693 static const String aAddAllowed
= String::CreateFromAscii( "?-[]!" );
1695 return pCharClass
->parseAnyToken( rFormula
,
1696 nSrcPos
, nStartFlags
, aAddAllowed
, nContFlags
, aAddAllowed
);
1699 virtual sal_Unicode
getSpecialSymbol( SpecialSymbolType eSymType
) const
1701 return ConventionXL::getSpecialSymbol(eSymType
);
1704 virtual bool parseExternalName( const String
& rSymbol
, String
& rFile
, String
& rName
,
1705 const ScDocument
* pDoc
,
1706 const ::com::sun::star::uno::Sequence
<
1707 const ::com::sun::star::sheet::ExternalLinkInfo
> * pExternalLinks
) const
1709 return ConventionXL::parseExternalName( rSymbol
, rFile
, rName
, pDoc
, pExternalLinks
);
1712 virtual String
makeExternalNameStr( const String
& rFile
, const String
& rName
) const
1714 return ConventionXL::makeExternalNameStr(rFile
, rName
);
1717 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1718 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1719 ScExternalRefManager
* pRefMgr
) const
1721 // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
1722 // This is a little different from the format Excel uses, as Excel
1723 // puts [] only around the file name. But we need to enclose the
1724 // whole file path with [] because the file name can contain any
1727 const String
* pFullName
= pRefMgr
->getExternalFileName(nFileId
);
1731 ScSingleRefData
aRef(rRef
);
1732 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1734 ConventionXL::makeExternalDocStr(
1735 rBuffer
, *pFullName
, rCompiler
.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS
);
1736 ScRangeStringConverter::AppendTableName(rBuffer
, rTabName
);
1737 rBuffer
.append(sal_Unicode('!'));
1739 r1c1_add_row(rBuffer
, aRef
);
1740 r1c1_add_col(rBuffer
, aRef
);
1743 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1744 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1745 ScExternalRefManager
* pRefMgr
) const
1747 const String
* pFullName
= pRefMgr
->getExternalFileName(nFileId
);
1751 vector
<String
> aTabNames
;
1752 pRefMgr
->getAllCachedTableNames(nFileId
, aTabNames
);
1753 if (aTabNames
.empty())
1756 ScComplexRefData
aRef(rRef
);
1757 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1759 ConventionXL::makeExternalDocStr(
1760 rBuffer
, *pFullName
, rCompiler
.GetEncodeUrlMode() == ScCompiler::ENCODE_ALWAYS
);
1761 ConventionXL::makeExternalTabNameRange(rBuffer
, rTabName
, aTabNames
, aRef
);
1762 rBuffer
.append(sal_Unicode('!'));
1764 if (aRef
.Ref2
.IsColDeleted() || aRef
.Ref2
.IsRowDeleted())
1766 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1770 if (aRef
.Ref1
.nCol
== 0 && aRef
.Ref2
.nCol
>= MAXCOL
)
1772 r1c1_add_row(rBuffer
, rRef
.Ref1
);
1773 if (rRef
.Ref1
.nRow
!= rRef
.Ref2
.nRow
|| rRef
.Ref1
.IsRowRel() != rRef
.Ref2
.IsRowRel())
1775 rBuffer
.append (sal_Unicode(':'));
1776 r1c1_add_row(rBuffer
, rRef
.Ref2
);
1781 if (aRef
.Ref1
.nRow
== 0 && aRef
.Ref2
.nRow
>= MAXROW
)
1783 r1c1_add_col(rBuffer
, aRef
.Ref1
);
1784 if (aRef
.Ref1
.nCol
!= aRef
.Ref2
.nCol
|| aRef
.Ref1
.IsColRel() != aRef
.Ref2
.IsColRel())
1786 rBuffer
.append (sal_Unicode(':'));
1787 r1c1_add_col(rBuffer
, aRef
.Ref2
);
1792 r1c1_add_row(rBuffer
, aRef
.Ref1
);
1793 r1c1_add_col(rBuffer
, aRef
.Ref1
);
1794 rBuffer
.append (sal_Unicode (':'));
1795 r1c1_add_row(rBuffer
, aRef
.Ref2
);
1796 r1c1_add_col(rBuffer
, aRef
.Ref2
);
1800 static const ConventionXL_R1C1 ConvXL_R1C1
;
1801 const ScCompiler::Convention
* const ScCompiler::pConvXL_R1C1
= &ConvXL_R1C1
;
1803 //-----------------------------------------------------------------------------
1804 ScCompiler::ScCompiler( ScDocument
* pDocument
, const ScAddress
& rPos
,ScTokenArray
& rArr
)
1805 : FormulaCompiler(rArr
),
1808 pCharClass( ScGlobal::pCharClass
),
1809 mnPredetectedReference(0),
1810 mnRangeOpPosInSymbol(-1),
1811 pConv( pConvOOO_A1
),
1812 meEncodeUrlMode( ENCODE_BY_GRAMMAR
),
1813 mbCloseBrackets( true ),
1814 mbExtendedErrorDetection( false ),
1817 nMaxTab
= pDoc
? pDoc
->GetTableCount() - 1 : 0;
1820 ScCompiler::ScCompiler( ScDocument
* pDocument
, const ScAddress
& rPos
)
1824 pCharClass( ScGlobal::pCharClass
),
1825 mnPredetectedReference(0),
1826 mnRangeOpPosInSymbol(-1),
1827 pConv( pConvOOO_A1
),
1828 meEncodeUrlMode( ENCODE_BY_GRAMMAR
),
1829 mbCloseBrackets( true ),
1830 mbExtendedErrorDetection( false ),
1833 nMaxTab
= pDoc
? pDoc
->GetTableCount() - 1 : 0;
1836 void ScCompiler::CheckTabQuotes( String
& rString
,
1837 const FormulaGrammar::AddressConvention eConv
)
1839 using namespace ::com::sun::star::i18n
;
1840 sal_Int32 nStartFlags
= KParseTokens::ANY_LETTER_OR_NUMBER
| KParseTokens::ASC_UNDERSCORE
;
1841 sal_Int32 nContFlags
= nStartFlags
;
1842 ParseResult aRes
= ScGlobal::pCharClass
->parsePredefinedToken(
1843 KParseType::IDENTNAME
, rString
, 0, nStartFlags
, EMPTY_STRING
, nContFlags
, EMPTY_STRING
);
1844 bool bNeedsQuote
= !((aRes
.TokenType
& KParseType::IDENTNAME
) && aRes
.EndPos
== rString
.Len());
1849 case FormulaGrammar::CONV_UNSPECIFIED
:
1851 case FormulaGrammar::CONV_OOO
:
1852 case FormulaGrammar::CONV_XL_A1
:
1853 case FormulaGrammar::CONV_XL_R1C1
:
1854 case FormulaGrammar::CONV_XL_OOX
:
1857 static const String one_quote
= static_cast<sal_Unicode
>( '\'' );
1858 static const String two_quote
= String::CreateFromAscii( "''" );
1859 // escape embedded quotes
1860 rString
.SearchAndReplaceAll( one_quote
, two_quote
);
1865 if ( !bNeedsQuote
&& CharClass::isAsciiNumeric( rString
) )
1867 // Prevent any possible confusion resulting from pure numeric sheet names.
1873 rString
.Insert( '\'', 0 );
1878 //---------------------------------------------------------------------------
1880 void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv
)
1883 case FormulaGrammar::CONV_UNSPECIFIED
:
1886 case FormulaGrammar::CONV_OOO
: SetRefConvention( pConvOOO_A1
); break;
1887 case FormulaGrammar::CONV_ODF
: SetRefConvention( pConvOOO_A1_ODF
); break;
1888 case FormulaGrammar::CONV_XL_A1
: SetRefConvention( pConvXL_A1
); break;
1889 case FormulaGrammar::CONV_XL_R1C1
: SetRefConvention( pConvXL_R1C1
); break;
1890 case FormulaGrammar::CONV_XL_OOX
: SetRefConvention( pConvXL_OOX
); break;
1894 void ScCompiler::SetRefConvention( const ScCompiler::Convention
*pConvP
)
1897 meGrammar
= FormulaGrammar::mergeToGrammar( meGrammar
, pConv
->meConv
);
1898 DBG_ASSERT( FormulaGrammar::isSupported( meGrammar
),
1899 "ScCompiler::SetRefConvention: unsupported grammar resulting");
1902 void ScCompiler::SetError(USHORT nError
)
1904 if( !pArr
->GetCodeError() )
1905 pArr
->SetCodeError( nError
);
1909 sal_Unicode
* lcl_UnicodeStrNCpy( sal_Unicode
* pDst
, const sal_Unicode
* pSrc
, xub_StrLen nMax
)
1911 const sal_Unicode
* const pStop
= pDst
+ nMax
;
1912 while ( *pSrc
&& pDst
< pStop
)
1921 //---------------------------------------------------------------------------
1923 //---------------------------------------------------------------------------
1924 // Zerlegt die Formel in einzelne Symbole fuer die weitere
1925 // Verarbeitung (Turing-Maschine).
1926 //---------------------------------------------------------------------------
1927 // Ausgangs Zustand = GetChar
1928 //---------------+-------------------+-----------------------+---------------
1929 // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
1930 //---------------+-------------------+-----------------------+---------------
1931 // GetChar | ;()+-*/^=& | Symbol=Zeichen | Stop
1932 // | <> | Symbol=Zeichen | GetBool
1933 // | $ Buchstabe | Symbol=Zeichen | GetWord
1934 // | Ziffer | Symbol=Zeichen | GetValue
1935 // | " | Keine | GetString
1936 // | Sonst | Keine | GetChar
1937 //---------------+-------------------+-----------------------+---------------
1938 // GetBool | => | Symbol=Symbol+Zeichen | Stop
1939 // | Sonst | Dec(CharPos) | Stop
1940 //---------------+-------------------+-----------------------+---------------
1941 // GetWord | SepSymbol | Dec(CharPos) | Stop
1942 // | ()+-*/^=<>&~ | |
1943 // | Leerzeichen | Dec(CharPos) | Stop
1945 // | Buchstabe,Ziffer | Symbol=Symbol+Zeichen | GetWord
1946 // | Sonst | Fehler | Stop
1947 //---------------|-------------------+-----------------------+---------------
1948 // GetValue | ;()*/^=<>& | |
1949 // | Leerzeichen | Dec(CharPos) | Stop
1950 // | Ziffer E+-%,. | Symbol=Symbol+Zeichen | GetValue
1951 // | Sonst | Fehler | Stop
1952 //---------------+-------------------+-----------------------+---------------
1953 // GetString | " | Keine | Stop
1954 // | Sonst | Symbol=Symbol+Zeichen | GetString
1955 //---------------+-------------------+-----------------------+---------------
1957 xub_StrLen
ScCompiler::NextSymbol(bool bInArray
)
1959 cSymbol
[MAXSTRLEN
-1] = 0; // Stopper
1960 sal_Unicode
* pSym
= cSymbol
;
1961 const sal_Unicode
* const pStart
= aFormula
.GetBuffer();
1962 const sal_Unicode
* pSrc
= pStart
+ nSrcPos
;
1964 sal_Unicode c
= *pSrc
;
1965 sal_Unicode cLast
= 0;
1966 bool bQuote
= false;
1967 mnRangeOpPosInSymbol
= -1;
1968 ScanState eState
= ssGetChar
;
1969 xub_StrLen nSpaces
= 0;
1970 sal_Unicode cSep
= mxSymbols
->getSymbol( ocSep
).GetChar(0);
1971 sal_Unicode cArrayColSep
= mxSymbols
->getSymbol( ocArrayColSep
).GetChar(0);
1972 sal_Unicode cArrayRowSep
= mxSymbols
->getSymbol( ocArrayRowSep
).GetChar(0);
1973 sal_Unicode cDecSep
= (mxSymbols
->isEnglish() ? '.' :
1974 ScGlobal::pLocaleData
->getNumDecimalSep().GetChar(0));
1976 // special symbols specific to address convention used
1977 sal_Unicode cSheetPrefix
= pConv
->getSpecialSymbol(ScCompiler::Convention::ABS_SHEET_PREFIX
);
1978 sal_Unicode cSheetSep
= pConv
->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR
);
1981 bool bAutoIntersection
= false;
1983 mnPredetectedReference
= 0;
1984 // try to parse simple tokens before calling i18n parser
1985 while ((c
!= 0) && (eState
!= ssStop
) )
1988 ULONG nMask
= GetCharTableFlags( c
);
1989 // The parameter separator and the array column and row separators end
1990 // things unconditionally if not in string or reference.
1991 if (c
== cSep
|| (bInArray
&& (c
== cArrayColSep
|| c
== cArrayRowSep
)))
1995 // these are to be continued
1998 case ssGetReference
:
1999 case ssSkipReference
:
2002 if (eState
== ssGetChar
)
2009 Label_MaskStateMachine
:
2014 // Order is important!
2015 if( nMask
& SC_COMPILER_C_ODF_LABEL_OP
)
2017 // '!!' automatic intersection
2018 if (GetCharTableFlags( pSrc
[0] ) & SC_COMPILER_C_ODF_LABEL_OP
)
2020 /* TODO: For now the UI "space operator" is used, this
2021 * could be enhanced using a specialized OpCode to get
2022 * rid of the space ambiguity, which would need some
2023 * places to be adapted though. And we would still need
2024 * to support the ambiguous space operator for UI
2025 * purposes anyway. However, we then could check for
2026 * invalid usage of '!!', which currently isn't
2028 if (!bAutoIntersection
)
2031 nSpaces
+= 2; // must match the character count
2032 bAutoIntersection
= true;
2042 nMask
&= ~SC_COMPILER_C_ODF_LABEL_OP
;
2043 goto Label_MaskStateMachine
;
2046 else if( nMask
& SC_COMPILER_C_ODF_NAME_MARKER
)
2048 // '$$' defined name marker
2049 if (GetCharTableFlags( pSrc
[0] ) & SC_COMPILER_C_ODF_NAME_MARKER
)
2051 // both eaten, not added to pSym
2056 nMask
&= ~SC_COMPILER_C_ODF_NAME_MARKER
;
2057 goto Label_MaskStateMachine
;
2060 else if( nMask
& SC_COMPILER_C_CHAR
)
2065 else if( nMask
& SC_COMPILER_C_ODF_LBRACKET
)
2067 // eaten, not added to pSym
2068 eState
= ssGetReference
;
2069 mnPredetectedReference
= 1;
2071 else if( nMask
& SC_COMPILER_C_CHAR_BOOL
)
2076 else if( nMask
& SC_COMPILER_C_CHAR_VALUE
)
2079 eState
= ssGetValue
;
2081 else if( nMask
& SC_COMPILER_C_CHAR_STRING
)
2084 eState
= ssGetString
;
2086 else if( nMask
& SC_COMPILER_C_CHAR_DONTCARE
)
2090 else if( nMask
& SC_COMPILER_C_CHAR_IDENT
)
2091 { // try to get a simple ASCII identifier before calling
2092 // i18n, to gain performance during import
2094 eState
= ssGetIdent
;
2105 if ( nMask
& SC_COMPILER_C_IDENT
)
2106 { // This catches also $Sheet1.A$1, for example.
2107 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2109 SetError(errStringOverflow
);
2115 else if (c
== ':' && mnRangeOpPosInSymbol
< 0)
2117 // One range operator may form Sheet1.A:A, which we need to
2118 // pass as one entity to IsReference().
2119 mnRangeOpPosInSymbol
= pSym
- &cSymbol
[0];
2120 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2122 SetError(errStringOverflow
);
2128 else if ( 128 <= c
|| '\'' == c
)
2129 { // High values need reparsing with i18n,
2130 // single quoted $'sheet' names too (otherwise we'd had to
2131 // implement everything twice).
2144 if( nMask
& SC_COMPILER_C_BOOL
)
2158 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2160 SetError(errStringOverflow
);
2163 else if (c
== cDecSep
)
2167 // reparse with i18n, may be numeric sheet name as well
2174 else if( nMask
& SC_COMPILER_C_VALUE
)
2176 else if( nMask
& SC_COMPILER_C_VALUE_SEP
)
2181 else if (c
== 'E' || c
== 'e')
2183 if (GetCharTableFlags( pSrc
[0] ) & SC_COMPILER_C_VALUE_EXP
)
2187 // reparse with i18n
2192 else if( nMask
& SC_COMPILER_C_VALUE_SIGN
)
2194 if (((cLast
== 'E') || (cLast
== 'e')) &&
2195 (GetCharTableFlags( pSrc
[0] ) & SC_COMPILER_C_VALUE_VALUE
))
2207 // reparse with i18n
2215 if( nMask
& SC_COMPILER_C_STRING_SEP
)
2220 bQuote
= true; // "" => literal "
2229 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2231 SetError(errStringOverflow
);
2232 eState
= ssSkipString
;
2240 if( nMask
& SC_COMPILER_C_STRING_SEP
)
2243 case ssGetReference
:
2244 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2246 SetError( errStringOverflow
);
2247 eState
= ssSkipReference
;
2249 // fall through and follow logic
2250 case ssSkipReference
:
2251 // ODF reference: ['External'#$'Sheet'.A1:.B2] with dots being
2252 // mandatory also if no sheet name. 'External'# is optional,
2253 // sheet name is optional, quotes around sheet name are
2254 // optional if no quote contained.
2255 // 2nd usage: ['Sheet'.$$'DefinedName']
2256 // 3rd usage: ['External'#$$'DefinedName']
2257 // 4th usage: ['External'#$'Sheet'.$$'DefinedName']
2258 // Also for all these names quotes are optional if no quote
2262 // nRefInName: 0 := not in sheet name yet. 'External'
2263 // is parsed as if it was a sheet name and nRefInName
2264 // is reset when # is encountered immediately after closing
2265 // quote. Same with 'DefinedName', nRefInName is cleared
2266 // when : is encountered.
2268 // Encountered leading $ before sheet name.
2269 static const int kDollar
= (1 << 1);
2270 // Encountered ' opening quote, which may be after $ or
2272 static const int kOpen
= (1 << 2);
2273 // Somewhere in name.
2274 static const int kName
= (1 << 3);
2275 // Encountered ' in name, will be cleared if double or
2276 // transformed to kClose if not, in which case kOpen is
2278 static const int kQuote
= (1 << 4);
2279 // Past ' closing quote.
2280 static const int kClose
= (1 << 5);
2281 // Past . sheet name separator.
2282 static const int kPast
= (1 << 6);
2283 // Marked name $$ follows sheet name separator, detected
2284 // while we're still on the separator. Will be cleared when
2285 // entering the name.
2286 static const int kMarkAhead
= (1 << 7);
2287 // In marked defined name.
2288 static const int kDefName
= (1 << 8);
2290 bool bAddToSymbol
= true;
2291 if ((nMask
& SC_COMPILER_C_ODF_RBRACKET
) && !(nRefInName
& kOpen
))
2293 DBG_ASSERT( nRefInName
& (kPast
| kDefName
),
2294 "ScCompiler::NextSymbol: reference: "
2295 "closing bracket ']' without prior sheet name separator '.' violates ODF spec");
2296 // eaten, not added to pSym
2297 bAddToSymbol
= false;
2300 else if (cSheetSep
== c
&& nRefInName
== 0)
2302 // eat it, no sheet name [.A1]
2303 bAddToSymbol
= false;
2304 nRefInName
|= kPast
;
2305 if ('$' == pSrc
[0] && '$' == pSrc
[1])
2306 nRefInName
|= kMarkAhead
;
2308 else if (!(nRefInName
& kPast
) || (nRefInName
& (kMarkAhead
| kDefName
)))
2310 // Not in col/row yet.
2312 if ('$' == c
&& '$' == pSrc
[0] && !(nRefInName
& kOpen
))
2314 nRefInName
&= ~kMarkAhead
;
2315 if (!(nRefInName
& kDefName
))
2317 // eaten, not added to pSym (2 chars)
2318 bAddToSymbol
= false;
2320 nRefInName
&= kPast
;
2321 nRefInName
|= kDefName
;
2325 // ScAddress::Parse() will recognize this as
2327 if (eState
!= ssSkipReference
)
2332 bAddToSymbol
= false;
2335 else if (cSheetPrefix
== c
&& nRefInName
== 0)
2336 nRefInName
|= kDollar
;
2339 // TODO: The conventions' parseExternalName()
2340 // should handle quoted names, but as long as they
2341 // don't remove non-embedded quotes here.
2342 if (!(nRefInName
& kName
))
2344 nRefInName
|= (kOpen
| kName
);
2345 bAddToSymbol
= !(nRefInName
& kDefName
);
2347 else if (!(nRefInName
& kOpen
))
2349 DBG_ERRORFILE("ScCompiler::NextSymbol: reference: "
2350 "a ''' without the name being enclosed in '...' violates ODF spec");
2352 else if (nRefInName
& kQuote
)
2354 // escaped embedded quote
2355 nRefInName
&= ~kQuote
;
2359 if ('\'' == pSrc
[0])
2361 // escapes embedded quote
2362 nRefInName
|= kQuote
;
2366 // quote not followed by quote => close
2367 nRefInName
|= kClose
;
2368 nRefInName
&= ~kOpen
;
2370 bAddToSymbol
= !(nRefInName
& kDefName
);
2373 else if (cSheetSep
== c
&& !(nRefInName
& kOpen
))
2375 // unquoted sheet name separator
2376 nRefInName
|= kPast
;
2377 if ('$' == pSrc
[0] && '$' == pSrc
[1])
2378 nRefInName
|= kMarkAhead
;
2380 else if (':' == c
&& !(nRefInName
& kOpen
))
2382 DBG_ERRORFILE("ScCompiler::NextSymbol: reference: "
2383 "range operator ':' without prior sheet name separator '.' violates ODF spec");
2385 ++mnPredetectedReference
;
2387 else if (!(nRefInName
& kName
))
2389 // start unquoted name
2390 nRefInName
|= kName
;
2397 ++mnPredetectedReference
;
2399 if (bAddToSymbol
&& eState
!= ssSkipReference
)
2400 *pSym
++ = c
; // everything is part of reference
2404 ; // nothing, prevent warning
2412 nSrcPos
= sal::static_int_cast
<xub_StrLen
>( nSrcPos
+ nSpaces
);
2414 mnRangeOpPosInSymbol
= -1;
2419 // special case (e.g. $'sheetname' in OOO A1)
2420 if ( pStart
[nSrcPos
] == cSheetPrefix
&& pStart
[nSrcPos
+1] == '\'' )
2421 aSymbol
+= pStart
[nSrcPos
++];
2423 ParseResult aRes
= pConv
->parseAnyToken( aFormula
, nSrcPos
, pCharClass
);
2425 if ( !aRes
.TokenType
)
2426 SetError( nErr
= errIllegalChar
); // parsed chars as string
2427 if ( aRes
.EndPos
<= nSrcPos
)
2429 SetError( nErr
= errIllegalChar
);
2430 nSrcPos
= aFormula
.Len();
2435 aSymbol
.Append( pStart
+ nSrcPos
, (xub_StrLen
)aRes
.EndPos
- nSrcPos
);
2436 nSrcPos
= (xub_StrLen
) aRes
.EndPos
;
2437 c
= pStart
[nSrcPos
];
2438 if ( aRes
.TokenType
& KParseType::SINGLE_QUOTE_NAME
)
2439 { // special cases (e.g. 'sheetname'. or 'filename'# in OOO A1)
2440 bi18n
= (c
== cSheetSep
|| c
== SC_COMPILER_FILE_TAB_SEP
);
2442 // One range operator restarts parsing for second reference.
2443 if (c
== ':' && mnRangeOpPosInSymbol
< 0)
2445 mnRangeOpPosInSymbol
= aSymbol
.Len();
2449 aSymbol
+= pStart
[nSrcPos
++];
2451 } while ( bi18n
&& !nErr
);
2452 xub_StrLen nLen
= aSymbol
.Len();
2453 if ( nLen
>= MAXSTRLEN
)
2455 SetError( errStringOverflow
);
2458 lcl_UnicodeStrNCpy( cSymbol
, aSymbol
.GetBuffer(), nLen
);
2462 nSrcPos
= sal::static_int_cast
<xub_StrLen
>( pSrc
- pStart
);
2465 if (mnRangeOpPosInSymbol
>= 0 && mnRangeOpPosInSymbol
== (pSym
-1) - &cSymbol
[0])
2467 // This is a trailing range operator, which is nonsense. Will be caught
2469 mnRangeOpPosInSymbol
= -1;
2474 aCorrectedSymbol
= cSymbol
;
2475 if (bAutoIntersection
&& nSpaces
> 1)
2476 --nSpaces
; // replace '!!' with only one space
2480 //---------------------------------------------------------------------------
2481 // Convert symbol to token
2482 //---------------------------------------------------------------------------
2484 BOOL
ScCompiler::IsOpCode( const String
& rName
, bool bInArray
)
2486 OpCodeHashMap::const_iterator
iLook( mxSymbols
->getHashMap()->find( rName
));
2487 BOOL bFound
= (iLook
!= mxSymbols
->getHashMap()->end());
2491 OpCode eOp
= iLook
->second
;
2494 if (rName
.Equals(mxSymbols
->getSymbol(ocArrayColSep
)))
2495 eOp
= ocArrayColSep
;
2496 else if (rName
.Equals(mxSymbols
->getSymbol(ocArrayRowSep
)))
2497 eOp
= ocArrayRowSep
;
2499 aToken
.SetOpCode(eOp
);
2500 pRawToken
= aToken
.Clone();
2505 if (mxSymbols
->hasExternals())
2507 // If symbols are set by filters get mapping to exact name.
2508 ExternalHashMap::const_iterator
iExt(
2509 mxSymbols
->getExternalHashMap()->find( rName
));
2510 if (iExt
!= mxSymbols
->getExternalHashMap()->end())
2512 if (ScGlobal::GetAddInCollection()->GetFuncData( (*iExt
).second
))
2513 aIntName
= (*iExt
).second
;
2515 if (!aIntName
.Len())
2517 // If that isn't found we might continue with rName lookup as a
2518 // last resort by just falling through to FindFunction(), but
2519 // it shouldn't happen if the map was setup correctly. Don't
2520 // waste time and bail out.
2524 if (!aIntName
.Len())
2526 // Old (deprecated) addins first for legacy.
2528 bFound
= ScGlobal::GetFuncCollection()->SearchFunc( cSymbol
, nIndex
);
2532 aToken
.SetExternal( cSymbol
);
2533 pRawToken
= aToken
.Clone();
2536 // bLocalFirst=FALSE for (English) upper full original name
2537 // (service.function)
2538 aIntName
= ScGlobal::GetAddInCollection()->FindFunction(
2539 rName
, !mxSymbols
->isEnglish());
2544 aToken
.SetExternal( aIntName
.GetBuffer() ); // international name
2545 pRawToken
= aToken
.Clone();
2550 if (bFound
&& ((eOp
= pRawToken
->GetOpCode()) == ocSub
|| eOp
== ocNegSub
))
2552 bool bShouldBeNegSub
=
2553 (eLastOp
== ocOpen
|| eLastOp
== ocSep
|| eLastOp
== ocNegSub
||
2554 (SC_OPCODE_START_BIN_OP
<= eLastOp
&& eLastOp
< SC_OPCODE_STOP_BIN_OP
) ||
2555 eLastOp
== ocArrayOpen
||
2556 eLastOp
== ocArrayColSep
|| eLastOp
== ocArrayRowSep
);
2557 if (bShouldBeNegSub
&& eOp
== ocSub
)
2558 pRawToken
->NewOpCode( ocNegSub
);
2559 //! if ocNegSub had ForceArray we'd have to set it here
2560 else if (!bShouldBeNegSub
&& eOp
== ocNegSub
)
2561 pRawToken
->NewOpCode( ocSub
);
2566 BOOL
ScCompiler::IsOpCode2( const String
& rName
)
2568 BOOL bFound
= FALSE
;
2571 for( i
= ocInternalBegin
; i
<= ocInternalEnd
&& !bFound
; i
++ )
2572 bFound
= rName
.EqualsAscii( pInternal
[ i
-ocInternalBegin
] );
2577 aToken
.SetOpCode( (OpCode
) --i
);
2578 pRawToken
= aToken
.Clone();
2583 BOOL
ScCompiler::IsValue( const String
& rSym
)
2586 sal_uInt32 nIndex
= ( mxSymbols
->isEnglish() ?
2587 pDoc
->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US
) : 0 );
2588 // ULONG nIndex = 0;
2589 //// ULONG nIndex = pDoc->GetFormatTable()->GetStandardIndex(ScGlobal::eLnge);
2590 if (pDoc
->GetFormatTable()->IsNumberFormat( rSym
, nIndex
, fVal
) )
2592 USHORT nType
= pDoc
->GetFormatTable()->GetType(nIndex
);
2594 // Don't accept 3:3 as time, it is a reference to entire row 3 instead.
2595 // Dates should never be entered directly and automatically converted
2596 // to serial, because the serial would be wrong if null-date changed.
2597 // Usually it wouldn't be accepted anyway because the date separator
2598 // clashed with other separators or operators.
2599 if (nType
& (NUMBERFORMAT_TIME
| NUMBERFORMAT_DATE
))
2602 if (nType
== NUMBERFORMAT_LOGICAL
)
2604 const sal_Unicode
* p
= aFormula
.GetBuffer() + nSrcPos
;
2608 return FALSE
; // Boolean function instead.
2611 if( aFormula
.GetChar(nSrcPos
) == '.' )
2612 // numerical sheet name?
2615 if( nType
== NUMBERFORMAT_TEXT
)
2616 // HACK: number too big!
2617 SetError( errIllegalArgument
);
2619 aToken
.SetDouble( fVal
);
2620 pRawToken
= aToken
.Clone();
2627 BOOL
ScCompiler::IsString()
2629 register const sal_Unicode
* p
= cSymbol
;
2632 xub_StrLen nLen
= sal::static_int_cast
<xub_StrLen
>( p
- cSymbol
- 1 );
2633 BOOL bQuote
= ((cSymbol
[0] == '"') && (cSymbol
[nLen
] == '"'));
2634 if ((bQuote
? nLen
-2 : nLen
) > MAXSTRLEN
-1)
2636 SetError(errStringOverflow
);
2641 cSymbol
[nLen
] = '\0';
2643 aToken
.SetString( cSymbol
+1 );
2644 pRawToken
= aToken
.Clone();
2651 BOOL
ScCompiler::IsPredetectedReference( const String
& rName
)
2653 // Speedup documents with lots of broken references, e.g. sheet deleted.
2654 xub_StrLen nPos
= rName
.SearchAscii( "#REF!");
2655 if (nPos
!= STRING_NOTFOUND
)
2657 /* TODO: this may be enhanced by reusing scan information from
2658 * NextSymbol(), the positions of quotes and special characters found
2659 * there for $'sheet'.A1:... could be stored in a vector. We don't
2660 * fully rescan here whether found positions are within single quotes
2661 * for performance reasons. This code does not check for possible
2662 * occurrences of insane "valid" sheet names like
2663 * 'haha.#REF!1fooledyou' and will generate an error on such. */
2665 return false; // #REF!.AB42 or #REF!42 or #REF!#REF!
2666 sal_Unicode c
= rName
.GetChar(nPos
-1); // before #REF!
2670 return false; // $#REF!.AB42 or $#REF!42 or $#REF!#REF!
2671 c
= rName
.GetChar(nPos
-2); // before $#REF!
2673 sal_Unicode c2
= rName
.GetChar(nPos
+5); // after #REF!
2677 if ('$' == c2
|| '#' == c2
|| ('0' <= c2
&& c2
<= '9'))
2678 return false; // sheet.#REF!42 or sheet.#REF!#REF!
2681 if (mnPredetectedReference
> 1 &&
2682 ('.' == c2
|| '$' == c2
|| '#' == c2
||
2683 ('0' <= c2
&& c2
<= '9')))
2684 return false; // :#REF!.AB42 or :#REF!42 or :#REF!#REF!
2687 if ((('A' <= c
&& c
<= 'Z') || ('a' <= c
&& c
<= 'z')) &&
2688 ((mnPredetectedReference
> 1 && ':' == c2
) || 0 == c2
))
2689 return false; // AB#REF!: or AB#REF!
2692 switch (mnPredetectedReference
)
2695 return IsSingleReference( rName
);
2697 return IsDoubleReference( rName
);
2703 BOOL
ScCompiler::IsDoubleReference( const String
& rName
)
2705 ScRange
aRange( aPos
, aPos
);
2706 const ScAddress::Details
aDetails( pConv
->meConv
, aPos
);
2707 ScAddress::ExternalInfo aExtInfo
;
2708 USHORT nFlags
= aRange
.Parse( rName
, pDoc
, aDetails
, &aExtInfo
, &maExternalLinks
);
2709 if( nFlags
& SCA_VALID
)
2712 ScComplexRefData aRef
;
2713 aRef
.InitRange( aRange
);
2714 aRef
.Ref1
.SetColRel( (nFlags
& SCA_COL_ABSOLUTE
) == 0 );
2715 aRef
.Ref1
.SetRowRel( (nFlags
& SCA_ROW_ABSOLUTE
) == 0 );
2716 aRef
.Ref1
.SetTabRel( (nFlags
& SCA_TAB_ABSOLUTE
) == 0 );
2717 if ( !(nFlags
& SCA_VALID_TAB
) )
2718 aRef
.Ref1
.SetTabDeleted( TRUE
); // #REF!
2719 aRef
.Ref1
.SetFlag3D( ( nFlags
& SCA_TAB_3D
) != 0 );
2720 aRef
.Ref2
.SetColRel( (nFlags
& SCA_COL2_ABSOLUTE
) == 0 );
2721 aRef
.Ref2
.SetRowRel( (nFlags
& SCA_ROW2_ABSOLUTE
) == 0 );
2722 aRef
.Ref2
.SetTabRel( (nFlags
& SCA_TAB2_ABSOLUTE
) == 0 );
2723 if ( !(nFlags
& SCA_VALID_TAB2
) )
2724 aRef
.Ref2
.SetTabDeleted( TRUE
); // #REF!
2725 aRef
.Ref2
.SetFlag3D( ( nFlags
& SCA_TAB2_3D
) != 0 );
2726 aRef
.CalcRelFromAbs( aPos
);
2727 if (aExtInfo
.mbExternal
)
2729 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
2730 const String
* pRealTab
= pRefMgr
->getRealTableName(aExtInfo
.mnFileId
, aExtInfo
.maTabName
);
2731 aToken
.SetExternalDoubleRef(
2732 aExtInfo
.mnFileId
, pRealTab
? *pRealTab
: aExtInfo
.maTabName
, aRef
);
2736 aToken
.SetDoubleReference(aRef
);
2738 pRawToken
= aToken
.Clone();
2741 return ( nFlags
& SCA_VALID
) != 0;
2745 BOOL
ScCompiler::IsSingleReference( const String
& rName
)
2747 ScAddress
aAddr( aPos
);
2748 const ScAddress::Details
aDetails( pConv
->meConv
, aPos
);
2749 ScAddress::ExternalInfo aExtInfo
;
2750 USHORT nFlags
= aAddr
.Parse( rName
, pDoc
, aDetails
, &aExtInfo
, &maExternalLinks
);
2751 // Something must be valid in order to recognize Sheet1.blah or blah.a1
2752 // as a (wrong) reference.
2753 if( nFlags
& ( SCA_VALID_COL
|SCA_VALID_ROW
|SCA_VALID_TAB
) )
2756 ScSingleRefData aRef
;
2757 aRef
.InitAddress( aAddr
);
2758 aRef
.SetColRel( (nFlags
& SCA_COL_ABSOLUTE
) == 0 );
2759 aRef
.SetRowRel( (nFlags
& SCA_ROW_ABSOLUTE
) == 0 );
2760 aRef
.SetTabRel( (nFlags
& SCA_TAB_ABSOLUTE
) == 0 );
2761 aRef
.SetFlag3D( ( nFlags
& SCA_TAB_3D
) != 0 );
2762 // the reference is really invalid
2763 if( !( nFlags
& SCA_VALID
) )
2765 if( !( nFlags
& SCA_VALID_COL
) )
2766 aRef
.nCol
= MAXCOL
+1;
2767 if( !( nFlags
& SCA_VALID_ROW
) )
2768 aRef
.nRow
= MAXROW
+1;
2769 if( !( nFlags
& SCA_VALID_TAB
) )
2770 aRef
.nTab
= MAXTAB
+3;
2771 nFlags
|= SCA_VALID
;
2773 aRef
.CalcRelFromAbs( aPos
);
2775 if (aExtInfo
.mbExternal
)
2777 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
2778 const String
* pRealTab
= pRefMgr
->getRealTableName(aExtInfo
.mnFileId
, aExtInfo
.maTabName
);
2779 aToken
.SetExternalSingleRef(
2780 aExtInfo
.mnFileId
, pRealTab
? *pRealTab
: aExtInfo
.maTabName
, aRef
);
2783 aToken
.SetSingleReference(aRef
);
2784 pRawToken
= aToken
.Clone();
2787 return ( nFlags
& SCA_VALID
) != 0;
2791 BOOL
ScCompiler::IsReference( const String
& rName
)
2793 // Has to be called before IsValue
2794 sal_Unicode ch1
= rName
.GetChar(0);
2795 sal_Unicode cDecSep
= ( mxSymbols
->isEnglish() ? '.' :
2796 ScGlobal::pLocaleData
->getNumDecimalSep().GetChar(0) );
2797 if ( ch1
== cDecSep
)
2799 // Who was that imbecile introducing '.' as the sheet name separator!?!
2800 if ( CharClass::isAsciiNumeric( ch1
) )
2802 // Numerical sheet name is valid.
2803 // But English 1.E2 or 1.E+2 is value 100, 1.E-2 is 0.01
2804 // Don't create a #REF! of values. But also do not bail out on
2805 // something like 3:3, meaning entire row 3.
2808 const xub_StrLen nPos
= ScGlobal::FindUnquoted( rName
, '.');
2809 if ( nPos
== STRING_NOTFOUND
)
2811 if (ScGlobal::FindUnquoted( rName
, ':') != STRING_NOTFOUND
)
2812 break; // may be 3:3, continue as usual
2815 sal_Unicode
const * const pTabSep
= rName
.GetBuffer() + nPos
;
2816 sal_Unicode ch2
= pTabSep
[1]; // maybe a column identifier
2817 if ( !(ch2
== '$' || CharClass::isAsciiAlpha( ch2
)) )
2819 if ( cDecSep
== '.' && (ch2
== 'E' || ch2
== 'e') // E + - digit
2820 && (GetCharTableFlags( pTabSep
[2] ) & SC_COMPILER_C_VALUE_EXP
) )
2822 // If it is an 1.E2 expression check if "1" is an existent sheet
2823 // name. If so, a desired value 1.E2 would have to be entered as
2824 // 1E2 or 1.0E2 or 1.E+2, sorry. Another possibility would be to
2825 // require numerical sheet names always being entered quoted, which
2826 // is not desirable (too many 1999, 2000, 2001 sheets in use).
2827 // Furthermore, XML files created with versions prior to SRC640e
2828 // wouldn't contain the quotes added by MakeTabStr()/CheckTabQuotes()
2829 // and would produce wrong formulas if the conditions here are met.
2830 // If you can live with these restrictions you may remove the
2831 // check and return an unconditional FALSE.
2832 String
aTabName( rName
.Copy( 0, nPos
) );
2834 if ( !pDoc
->GetTable( aTabName
, nTab
) )
2836 // If sheet "1" exists and the expression is 1.E+2 continue as
2837 // usual, the ScRange/ScAddress parser will take care of it.
2842 if (IsSingleReference( rName
))
2845 // Though the range operator is handled explicitly, when encountering
2846 // something like Sheet1.A:A we will have to treat it as one entity if it
2847 // doesn't pass as single cell reference.
2848 if (mnRangeOpPosInSymbol
> 0) // ":foo" would be nonsense
2850 if (IsDoubleReference( rName
))
2852 // Now try with a symbol up to the range operator, rewind source
2854 sal_Int32 nLen
= mnRangeOpPosInSymbol
;
2855 while (cSymbol
[++nLen
])
2857 cSymbol
[mnRangeOpPosInSymbol
] = 0;
2858 nSrcPos
-= static_cast<xub_StrLen
>(nLen
- mnRangeOpPosInSymbol
);
2859 mnRangeOpPosInSymbol
= -1;
2861 return true; // end all checks
2865 // Special treatment for the 'E:\[doc]Sheet1:Sheet3'!D5 Excel sickness,
2866 // mnRangeOpPosInSymbol did not catch the range operator as it is
2867 // within a quoted name.
2868 switch (pConv
->meConv
)
2870 case FormulaGrammar::CONV_XL_A1
:
2871 case FormulaGrammar::CONV_XL_R1C1
:
2872 case FormulaGrammar::CONV_XL_OOX
:
2873 if (rName
.GetChar(0) == '\'' && IsDoubleReference( rName
))
2883 BOOL
ScCompiler::IsMacro( const String
& rName
)
2885 StarBASIC
* pObj
= 0;
2886 SfxObjectShell
* pDocSh
= pDoc
->GetDocumentShell();
2888 SfxApplication
* pSfxApp
= SFX_APP();
2889 pSfxApp
->EnterBasicCall(); // initialize document's BASIC
2892 pObj
= pDocSh
->GetBasic();
2894 pObj
= pSfxApp
->GetBasic();
2896 SbxMethod
* pMeth
= (SbxMethod
*) pObj
->Find( rName
, SbxCLASS_METHOD
);
2899 pSfxApp
->LeaveBasicCall();
2902 // It really should be a BASIC function!
2903 if( pMeth
->GetType() == SbxVOID
2904 || ( pMeth
->IsFixed() && pMeth
->GetType() == SbxEMPTY
)
2905 || !pMeth
->ISA(SbMethod
) )
2907 pSfxApp
->LeaveBasicCall();
2911 aToken
.SetExternal( rName
.GetBuffer() );
2912 aToken
.eOp
= ocMacro
;
2913 pRawToken
= aToken
.Clone();
2914 pSfxApp
->LeaveBasicCall();
2918 BOOL
ScCompiler::IsNamedRange( const String
& rUpperName
)
2920 // IsNamedRange is called only from NextNewToken, with an upper-case string
2923 ScRangeName
* pRangeName
= pDoc
->GetRangeName();
2924 if (pRangeName
->SearchNameUpper( rUpperName
, n
) )
2926 ScRangeData
* pData
= (*pRangeName
)[n
];
2928 aToken
.SetName( pData
->GetIndex() );
2929 pRawToken
= aToken
.Clone();
2936 bool ScCompiler::IsExternalNamedRange( const String
& rSymbol
)
2938 /* FIXME: This code currently (2008-12-02T15:41+0100 in CWS mooxlsc)
2939 * correctly parses external named references in OOo, as required per RFE
2940 * #i3740#, just that we can't store them in ODF yet. We will need an OASIS
2941 * spec first. Until then don't pretend to support external names that
2942 * wouldn't survive a save and reload cycle, return false instead. */
2948 String aFile
, aName
;
2949 if (!pConv
->parseExternalName( rSymbol
, aFile
, aName
, pDoc
, &maExternalLinks
))
2953 if (aFile
.Len() > MAXSTRLEN
|| aName
.Len() > MAXSTRLEN
)
2956 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
2957 pRefMgr
->convertToAbsName(aFile
);
2958 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId(aFile
);
2959 if (!pRefMgr
->getRangeNameTokens(nFileId
, aName
).get())
2960 // range name doesn't exist in the source document.
2963 const String
* pRealName
= pRefMgr
->getRealRangeName(nFileId
, aName
);
2964 aToken
.SetExternalName(nFileId
, pRealName
? *pRealName
: aName
);
2965 pRawToken
= aToken
.Clone();
2973 BOOL
ScCompiler::IsDBRange( const String
& rName
)
2976 ScDBCollection
* pDBColl
= pDoc
->GetDBCollection();
2977 if (pDBColl
->SearchName( rName
, n
) )
2979 ScDBData
* pData
= (*pDBColl
)[n
];
2981 aToken
.SetName( pData
->GetIndex() );
2982 aToken
.eOp
= ocDBArea
;
2983 pRawToken
= aToken
.Clone();
2990 BOOL
ScCompiler::IsColRowName( const String
& rName
)
2992 BOOL bInList
= FALSE
;
2993 BOOL bFound
= FALSE
;
2994 ScSingleRefData aRef
;
2995 String
aName( rName
);
2997 SCTAB nThisTab
= aPos
.Tab();
2998 for ( short jThisTab
= 1; jThisTab
>= 0 && !bInList
; jThisTab
-- )
2999 { // #50300# first check ranges on this sheet, in case of duplicated names
3000 for ( short jRow
=0; jRow
<2 && !bInList
; jRow
++ )
3002 ScRangePairList
* pRL
;
3004 pRL
= pDoc
->GetColNameRanges();
3006 pRL
= pDoc
->GetRowNameRanges();
3007 for ( ScRangePair
* pR
= pRL
->First(); pR
&& !bInList
; pR
= pRL
->Next() )
3009 const ScRange
& rNameRange
= pR
->GetRange(0);
3010 if ( jThisTab
&& !(rNameRange
.aStart
.Tab() <= nThisTab
&&
3011 nThisTab
<= rNameRange
.aEnd
.Tab()) )
3013 ScCellIterator
aIter( pDoc
, rNameRange
);
3014 for ( ScBaseCell
* pCell
= aIter
.GetFirst(); pCell
&& !bInList
;
3015 pCell
= aIter
.GetNext() )
3017 // Don't crash if cell (via CompileNameFormula) encounters
3018 // a formula cell without code and
3019 // HasStringData/Interpret/Compile is executed and all that
3021 // Furthermore, *this* cell won't be touched, since no RPN exists yet.
3022 CellType eType
= pCell
->GetCellType();
3023 BOOL bOk
= sal::static_int_cast
<BOOL
>( (eType
== CELLTYPE_FORMULA
?
3024 ((ScFormulaCell
*)pCell
)->GetCode()->GetCodeLen() > 0
3025 && ((ScFormulaCell
*)pCell
)->aPos
!= aPos
// noIter
3027 if ( bOk
&& pCell
->HasStringData() )
3032 case CELLTYPE_STRING
:
3033 ((ScStringCell
*)pCell
)->GetString( aStr
);
3035 case CELLTYPE_FORMULA
:
3036 ((ScFormulaCell
*)pCell
)->GetString( aStr
);
3039 ((ScEditCell
*)pCell
)->GetString( aStr
);
3042 case CELLTYPE_VALUE
:
3044 case CELLTYPE_SYMBOLS
:
3046 case CELLTYPE_DESTROYED
:
3048 ; // nothing, prevent compiler warning
3051 if ( ScGlobal::GetpTransliteration()->isEqual( aStr
, aName
) )
3054 aRef
.nCol
= aIter
.GetCol();
3055 aRef
.nRow
= aIter
.GetRow();
3056 aRef
.nTab
= aIter
.GetTab();
3058 aRef
.SetColRel( TRUE
); // ColName
3060 aRef
.SetRowRel( TRUE
); // RowName
3061 aRef
.CalcRelFromAbs( aPos
);
3062 bInList
= bFound
= TRUE
;
3069 if ( !bInList
&& pDoc
->GetDocOptions().IsLookUpColRowNames() )
3070 { // search in current sheet
3071 long nDistance
= 0, nMax
= 0;
3072 long nMyCol
= (long) aPos
.Col();
3073 long nMyRow
= (long) aPos
.Row();
3075 ScAddress
aOne( 0, 0, aPos
.Tab() );
3076 ScAddress
aTwo( MAXCOL
, MAXROW
, aPos
.Tab() );
3078 ScAutoNameCache
* pNameCache
= pDoc
->GetAutoNameCache();
3081 // #b6355215# use GetNameOccurences to collect all positions of aName on the sheet
3082 // (only once), similar to the outer part of the loop in the "else" branch.
3084 const ScAutoNameAddresses
& rAddresses
= pNameCache
->GetNameOccurences( aName
, aPos
.Tab() );
3086 // Loop through the found positions, similar to the inner part of the loop in the "else" branch.
3087 // The order of addresses in the vector is the same as from ScCellIterator.
3089 ScAutoNameAddresses::const_iterator
aEnd(rAddresses
.end());
3090 for ( ScAutoNameAddresses::const_iterator
aAdrIter(rAddresses
.begin()); aAdrIter
!= aEnd
; ++aAdrIter
)
3092 ScAddress
aAddress( *aAdrIter
); // cell address with an equal string
3095 { // stop if everything else is further away
3096 if ( nMax
< (long)aAddress
.Col() )
3099 if ( aAddress
!= aPos
)
3101 // same treatment as in isEqual case below
3103 SCCOL nCol
= aAddress
.Col();
3104 SCROW nRow
= aAddress
.Row();
3105 long nC
= nMyCol
- nCol
;
3106 long nR
= nMyRow
- nRow
;
3109 long nD
= nC
* nC
+ nR
* nR
;
3110 if ( nD
< nDistance
)
3112 if ( nC
< 0 || nR
< 0 )
3115 aTwo
.Set( nCol
, nRow
, aAddress
.Tab() );
3116 nMax
= Max( nMyCol
+ Abs( nC
), nMyRow
+ Abs( nR
) );
3119 else if ( !(nRow
< aOne
.Row() && nMyRow
>= (long)aOne
.Row()) )
3121 // upper left, only if not further up than the
3122 // current entry and nMyRow is below (CellIter
3123 // runs column-wise)
3125 aOne
.Set( nCol
, nRow
, aAddress
.Tab() );
3126 nMax
= Max( nMyCol
+ nC
, nMyRow
+ nR
);
3133 aOne
.Set( nCol
, nRow
, aAddress
.Tab() );
3134 nDistance
= nC
* nC
+ nR
* nR
;
3135 nMax
= Max( nMyCol
+ Abs( nC
), nMyRow
+ Abs( nR
) );
3143 ScCellIterator
aIter( pDoc
, ScRange( aOne
, aTwo
) );
3144 for ( ScBaseCell
* pCell
= aIter
.GetFirst(); pCell
; pCell
= aIter
.GetNext() )
3147 { // stop if everything else is further away
3148 if ( nMax
< (long)aIter
.GetCol() )
3151 CellType eType
= pCell
->GetCellType();
3152 BOOL bOk
= sal::static_int_cast
<BOOL
>( (eType
== CELLTYPE_FORMULA
?
3153 ((ScFormulaCell
*)pCell
)->GetCode()->GetCodeLen() > 0
3154 && ((ScFormulaCell
*)pCell
)->aPos
!= aPos
// noIter
3156 if ( bOk
&& pCell
->HasStringData() )
3161 case CELLTYPE_STRING
:
3162 ((ScStringCell
*)pCell
)->GetString( aStr
);
3164 case CELLTYPE_FORMULA
:
3165 ((ScFormulaCell
*)pCell
)->GetString( aStr
);
3168 ((ScEditCell
*)pCell
)->GetString( aStr
);
3171 case CELLTYPE_VALUE
:
3173 case CELLTYPE_SYMBOLS
:
3175 case CELLTYPE_DESTROYED
:
3177 ; // nothing, prevent compiler warning
3180 if ( ScGlobal::GetpTransliteration()->isEqual( aStr
, aName
) )
3182 SCCOL nCol
= aIter
.GetCol();
3183 SCROW nRow
= aIter
.GetRow();
3184 long nC
= nMyCol
- nCol
;
3185 long nR
= nMyRow
- nRow
;
3188 long nD
= nC
* nC
+ nR
* nR
;
3189 if ( nD
< nDistance
)
3191 if ( nC
< 0 || nR
< 0 )
3194 aTwo
.Set( nCol
, nRow
, aIter
.GetTab() );
3195 nMax
= Max( nMyCol
+ Abs( nC
), nMyRow
+ Abs( nR
) );
3198 else if ( !(nRow
< aOne
.Row() && nMyRow
>= (long)aOne
.Row()) )
3200 // upper left, only if not further up than the
3201 // current entry and nMyRow is below (CellIter
3202 // runs column-wise)
3204 aOne
.Set( nCol
, nRow
, aIter
.GetTab() );
3205 nMax
= Max( nMyCol
+ nC
, nMyRow
+ nR
);
3212 aOne
.Set( nCol
, nRow
, aIter
.GetTab() );
3213 nDistance
= nC
* nC
+ nR
* nR
;
3214 nMax
= Max( nMyCol
+ Abs( nC
), nMyRow
+ Abs( nR
) );
3227 if ( nMyCol
>= (long)aOne
.Col() && nMyRow
>= (long)aOne
.Row() )
3228 aAdr
= aOne
; // upper left takes precedence
3231 if ( nMyCol
< (long)aOne
.Col() )
3232 { // two to the right
3233 if ( nMyRow
>= (long)aTwo
.Row() )
3234 aAdr
= aTwo
; // directly right
3239 { // two below or below and right, take the nearest
3240 long nC1
= nMyCol
- aOne
.Col();
3241 long nR1
= nMyRow
- aOne
.Row();
3242 long nC2
= nMyCol
- aTwo
.Col();
3243 long nR2
= nMyRow
- aTwo
.Row();
3244 if ( nC1
* nC1
+ nR1
* nR1
<= nC2
* nC2
+ nR2
* nR2
)
3253 aRef
.InitAddress( aAdr
);
3254 if ( (aRef
.nRow
!= MAXROW
&& pDoc
->HasStringData(
3255 aRef
.nCol
, aRef
.nRow
+ 1, aRef
.nTab
))
3256 || (aRef
.nRow
!= 0 && pDoc
->HasStringData(
3257 aRef
.nCol
, aRef
.nRow
- 1, aRef
.nTab
)) )
3258 aRef
.SetRowRel( TRUE
); // RowName
3260 aRef
.SetColRel( TRUE
); // ColName
3261 aRef
.CalcRelFromAbs( aPos
);
3267 aToken
.SetSingleReference( aRef
);
3268 aToken
.eOp
= ocColRowName
;
3269 pRawToken
= aToken
.Clone();
3276 BOOL
ScCompiler::IsBoolean( const String
& rName
)
3278 OpCodeHashMap::const_iterator
iLook( mxSymbols
->getHashMap()->find( rName
) );
3279 if( iLook
!= mxSymbols
->getHashMap()->end() &&
3280 ((*iLook
).second
== ocTrue
||
3281 (*iLook
).second
== ocFalse
) )
3284 aToken
.SetOpCode( (*iLook
).second
);
3285 pRawToken
= aToken
.Clone();
3292 //---------------------------------------------------------------------------
3294 void ScCompiler::AutoCorrectParsedSymbol()
3296 xub_StrLen nPos
= aCorrectedSymbol
.Len();
3300 const sal_Unicode cQuote
= '\"';
3301 const sal_Unicode cx
= 'x';
3302 const sal_Unicode cX
= 'X';
3303 sal_Unicode c1
= aCorrectedSymbol
.GetChar( 0 );
3304 sal_Unicode c2
= aCorrectedSymbol
.GetChar( nPos
);
3305 if ( c1
== cQuote
&& c2
!= cQuote
)
3307 // What's not a word doesn't belong to it.
3308 // Don't be pedantic: c < 128 should be sufficient here.
3309 while ( nPos
&& ((aCorrectedSymbol
.GetChar(nPos
) < 128) &&
3310 ((GetCharTableFlags( aCorrectedSymbol
.GetChar(nPos
) ) &
3311 (SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_DONTCARE
)) == 0)) )
3313 if ( nPos
== MAXSTRLEN
- 2 )
3314 aCorrectedSymbol
.SetChar( nPos
, cQuote
); // '"' the 255th character
3316 aCorrectedSymbol
.Insert( cQuote
, nPos
+ 1 );
3319 else if ( c1
!= cQuote
&& c2
== cQuote
)
3321 aCorrectedSymbol
.Insert( cQuote
, 0 );
3324 else if ( nPos
== 0 && (c1
== cx
|| c1
== cX
) )
3326 aCorrectedSymbol
= mxSymbols
->getSymbol(ocMul
);
3329 else if ( (GetCharTableFlags( c1
) & SC_COMPILER_C_CHAR_VALUE
)
3330 && (GetCharTableFlags( c2
) & SC_COMPILER_C_CHAR_VALUE
) )
3333 if ( (nXcount
= aCorrectedSymbol
.GetTokenCount( cx
)) > 1 )
3335 xub_StrLen nIndex
= 0;
3336 sal_Unicode c
= mxSymbols
->getSymbol(ocMul
).GetChar(0);
3337 while ( (nIndex
= aCorrectedSymbol
.SearchAndReplace(
3338 cx
, c
, nIndex
)) != STRING_NOTFOUND
)
3342 if ( (nXcount
= aCorrectedSymbol
.GetTokenCount( cX
)) > 1 )
3344 xub_StrLen nIndex
= 0;
3345 sal_Unicode c
= mxSymbols
->getSymbol(ocMul
).GetChar(0);
3346 while ( (nIndex
= aCorrectedSymbol
.SearchAndReplace(
3347 cX
, c
, nIndex
)) != STRING_NOTFOUND
)
3354 String
aSymbol( aCorrectedSymbol
);
3356 xub_StrLen nPosition
;
3357 if ( aSymbol
.GetChar(0) == '\''
3358 && ((nPosition
= aSymbol
.SearchAscii( "'#" )) != STRING_NOTFOUND
) )
3359 { // Split off 'Doc'#, may be d:\... or whatever
3360 aDoc
= aSymbol
.Copy( 0, nPosition
+ 2 );
3361 aSymbol
.Erase( 0, nPosition
+ 2 );
3363 xub_StrLen nRefs
= aSymbol
.GetTokenCount( ':' );
3366 { // duplicated or too many ':'? B:2::C10 => B2:C10
3368 xub_StrLen nIndex
= 0;
3369 String
aTmp1( aSymbol
.GetToken( 0, ':', nIndex
) );
3370 xub_StrLen nLen1
= aTmp1
.Len();
3372 BOOL bLastAlp
, bNextNum
;
3373 bLastAlp
= bNextNum
= TRUE
;
3374 xub_StrLen nStrip
= 0;
3375 xub_StrLen nCount
= nRefs
;
3376 for ( xub_StrLen j
=1; j
<nCount
; j
++ )
3378 aTmp2
= aSymbol
.GetToken( 0, ':', nIndex
);
3379 xub_StrLen nLen2
= aTmp2
.Len();
3380 if ( nLen1
|| nLen2
)
3385 bLastAlp
= CharClass::isAsciiAlpha( aTmp1
);
3389 bNextNum
= CharClass::isAsciiNumeric( aTmp2
);
3390 if ( bLastAlp
== bNextNum
&& nStrip
< 1 )
3392 // Must be alternating number/string, only
3393 // strip within a reference.
3399 xub_StrLen nSymLen
= aSym
.Len();
3401 && (aSym
.GetChar( nSymLen
- 1 ) != ':') )
3405 bLastAlp
= !bNextNum
;
3411 { // B10::C10 ? append ':' on next round
3412 if ( !bLastAlp
&& !CharClass::isAsciiNumeric( aTmp1
) )
3415 bNextNum
= !bLastAlp
;
3428 if ( nRefs
&& nRefs
<= 2 )
3429 { // reference twisted? 4A => A4 etc.
3430 String aTab
[2], aRef
[2];
3431 const ScAddress::Details
aDetails( pConv
->meConv
, aPos
);
3434 aRef
[0] = aSymbol
.GetToken( 0, ':' );
3435 aRef
[1] = aSymbol
.GetToken( 1, ':' );
3440 BOOL bChanged
= FALSE
;
3442 USHORT nMask
= SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
;
3443 for ( int j
=0; j
<nRefs
; j
++ )
3445 xub_StrLen nTmp
= 0;
3446 xub_StrLen nDotPos
= STRING_NOTFOUND
;
3447 while ( (nTmp
= aRef
[j
].Search( '.', nTmp
)) != STRING_NOTFOUND
)
3448 nDotPos
= nTmp
++; // the last one counts
3449 if ( nDotPos
!= STRING_NOTFOUND
)
3451 aTab
[j
] = aRef
[j
].Copy( 0, nDotPos
+ 1 ); // with '.'
3452 aRef
[j
].Erase( 0, nDotPos
+ 1 );
3454 String
aOld( aRef
[j
] );
3456 const sal_Unicode
* p
= aRef
[j
].GetBuffer();
3457 while ( *p
&& CharClass::isAsciiNumeric( *p
) )
3459 aRef
[j
] = String( p
);
3461 if ( bColons
|| aRef
[j
] != aOld
)
3465 bOk
&= ((aAdr
.Parse( aRef
[j
], pDoc
, aDetails
) & nMask
) == nMask
);
3468 if ( bChanged
&& bOk
)
3470 aCorrectedSymbol
= aDoc
;
3471 aCorrectedSymbol
+= aTab
[0];
3472 aCorrectedSymbol
+= aRef
[0];
3475 aCorrectedSymbol
+= ':';
3476 aCorrectedSymbol
+= aTab
[1];
3477 aCorrectedSymbol
+= aRef
[1];
3486 inline bool lcl_UpperAsciiOrI18n( String
& rUpper
, const String
& rOrg
, FormulaGrammar::Grammar eGrammar
)
3488 if (FormulaGrammar::isODFF( eGrammar
))
3490 // ODFF has a defined set of English function names, avoid i18n
3493 rUpper
.ToUpperAscii();
3498 rUpper
= ScGlobal::pCharClass
->upper( rOrg
);
3503 BOOL
ScCompiler::NextNewToken( bool bInArray
)
3505 bool bAllowBooleans
= bInArray
;
3506 xub_StrLen nSpaces
= NextSymbol(bInArray
);
3509 fprintf( stderr
, "NextNewToken '%s' (spaces = %d)\n",
3510 rtl::OUStringToOString( cSymbol
, RTL_TEXTENCODING_UTF8
).getStr(), nSpaces
);
3519 aToken
.SetOpCode( ocSpaces
);
3520 aToken
.sbyte
.cByte
= (BYTE
) ( nSpaces
> 255 ? 255 : nSpaces
);
3521 if( !static_cast<ScTokenArray
*>(pArr
)->AddRawToken( aToken
) )
3523 SetError(errCodeOverflow
);
3528 // Short cut for references when reading ODF to speedup things.
3529 if (mnPredetectedReference
)
3531 String
aStr( cSymbol
);
3532 if (!IsPredetectedReference( aStr
) && !IsExternalNamedRange( aStr
))
3534 /* TODO: it would be nice to generate a #REF! error here, which
3535 * would need an ocBad token with additional error value.
3536 * FormulaErrorToken wouldn't do because we want to preserve the
3537 * original string containing partial valid address
3540 aToken
.SetString( aStr
.GetBuffer() );
3541 aToken
.NewOpCode( ocBad
);
3542 pRawToken
= aToken
.Clone();
3547 if ( (cSymbol
[0] == '#' || cSymbol
[0] == '$') && cSymbol
[1] == 0 &&
3549 { // #101100# special case to speed up broken [$]#REF documents
3550 /* FIXME: ISERROR(#REF!) would be valid and TRUE and the formula to
3551 * be processed as usual. That would need some special treatment,
3552 * also in NextSymbol() because of possible combinations of
3553 * #REF!.#REF!#REF! parts. In case of reading ODF that is all
3554 * handled by IsPredetectedReference(), this case here remains for
3555 * manual/API input. */
3556 String
aBad( aFormula
.Copy( nSrcPos
-1 ) );
3557 eLastOp
= pArr
->AddBad( aBad
)->GetOpCode();
3564 bool bMayBeFuncName
;
3565 bool bAsciiNonAlnum
; // operators, separators, ...
3566 if ( cSymbol
[0] < 128 )
3568 bMayBeFuncName
= CharClass::isAsciiAlpha( cSymbol
[0] );
3569 bAsciiNonAlnum
= !bMayBeFuncName
&& !CharClass::isAsciiDigit( cSymbol
[0] );
3573 String
aTmpStr( cSymbol
[0] );
3574 bMayBeFuncName
= ScGlobal::pCharClass
->isLetter( aTmpStr
, 0 );
3575 bAsciiNonAlnum
= false;
3577 if ( bMayBeFuncName
)
3579 // a function name must be followed by a parenthesis
3580 const sal_Unicode
* p
= aFormula
.GetBuffer() + nSrcPos
;
3583 bMayBeFuncName
= ( *p
== '(' );
3587 fprintf( stderr
, "Token '%s'\n",
3588 rtl::OUStringToOString( aUpper
, RTL_TEXTENCODING_UTF8
).getStr() );
3591 // #42016# Italian ARCTAN.2 resulted in #REF! => IsOpcode() before
3599 const String
aOrg( cSymbol
);
3601 if (bAsciiNonAlnum
&& IsOpCode( aOrg
, bInArray
))
3605 bool bAsciiUpper
= false;
3608 bAsciiUpper
= lcl_UpperAsciiOrI18n( aUpper
, aOrg
, meGrammar
);
3609 if (IsOpCode( aUpper
, bInArray
))
3613 // Column 'DM' ("Deutsche Mark", German currency) couldn't be
3614 // referred => IsReference() before IsValue().
3615 // Preserve case of file names in external references.
3616 if (IsReference( aOrg
))
3618 if (mbRewind
) // Range operator, but no direct reference.
3619 continue; // do; up to range operator.
3624 bAsciiUpper
= lcl_UpperAsciiOrI18n( aUpper
, aOrg
, meGrammar
);
3626 // IsBoolean() before IsValue() to catch inline bools without the kludge
3627 // for inline arrays.
3628 if (bAllowBooleans
&& IsBoolean( aUpper
))
3631 if (IsValue( aUpper
))
3634 // User defined names and such do need i18n upper also in ODF.
3636 aUpper
= ScGlobal::pCharClass
->upper( aOrg
);
3638 if (IsNamedRange( aUpper
))
3640 // Preserve case of file names in external references.
3641 if (IsExternalNamedRange( aOrg
))
3643 if (IsDBRange( aUpper
))
3645 if (IsColRowName( aUpper
))
3647 if (bMayBeFuncName
&& IsMacro( aUpper
))
3649 if (bMayBeFuncName
&& IsOpCode2( aUpper
))
3654 if ( mbExtendedErrorDetection
)
3656 // set an error and end compilation
3657 SetError( errNoName
);
3661 // Provide single token information and continue. Do not set an error, that
3662 // would prematurely end compilation. Simple unknown names are handled by
3664 ScGlobal::pCharClass
->toLower( aUpper
);
3666 aToken
.SetString( aUpper
.GetBuffer() );
3667 aToken
.NewOpCode( ocBad
);
3668 pRawToken
= aToken
.Clone();
3670 AutoCorrectParsedSymbol();
3674 void ScCompiler::CreateStringFromXMLTokenArray( String
& rFormula
, String
& rFormulaNmsp
)
3676 bool bExternal
= GetGrammar() == FormulaGrammar::GRAM_EXTERNAL
;
3677 USHORT nExpectedCount
= bExternal
? 2 : 1;
3678 DBG_ASSERT( pArr
->GetLen() == nExpectedCount
, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" );
3679 if( pArr
->GetLen() == nExpectedCount
)
3681 FormulaToken
** ppTokens
= pArr
->GetArray();
3682 // string tokens expected, GetString() will assert if token type is wrong
3683 rFormula
= ppTokens
[ 0 ]->GetString();
3685 rFormulaNmsp
= ppTokens
[ 1 ]->GetString();
3689 ScTokenArray
* ScCompiler::CompileString( const String
& rFormula
)
3692 fprintf( stderr
, "CompileString '%s'\n",
3693 rtl::OUStringToOString( rFormula
, RTL_TEXTENCODING_UTF8
).getStr() );
3696 OSL_ENSURE( meGrammar
!= FormulaGrammar::GRAM_EXTERNAL
, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" );
3697 if( meGrammar
== FormulaGrammar::GRAM_EXTERNAL
)
3698 SetGrammar( FormulaGrammar::GRAM_PODF
);
3702 aFormula
= rFormula
;
3704 aFormula
.EraseLeadingChars();
3705 aFormula
.EraseTrailingChars();
3710 aCorrectedFormula
.Erase();
3711 aCorrectedSymbol
.Erase();
3713 BYTE nForced
= 0; // ==formula forces recalc even if cell is not visible
3714 if( aFormula
.GetChar(nSrcPos
) == '=' )
3719 aCorrectedFormula
+= '=';
3721 if( aFormula
.GetChar(nSrcPos
) == '=' )
3726 aCorrectedFormula
+= '=';
3728 struct FunctionStack
3733 // FunctionStack only used if PODF!
3734 bool bPODF
= FormulaGrammar::isPODF( meGrammar
);
3735 const size_t nAlloc
= 512;
3736 FunctionStack aFuncs
[ nAlloc
];
3737 FunctionStack
* pFunctionStack
= (bPODF
&& rFormula
.Len() > nAlloc
?
3738 new FunctionStack
[ rFormula
.Len() ] : &aFuncs
[0]);
3739 pFunctionStack
[0].eOp
= ocNone
;
3740 pFunctionStack
[0].nPar
= 0;
3741 size_t nFunction
= 0;
3742 short nBrackets
= 0;
3743 bool bInArray
= false;
3745 while( NextNewToken( bInArray
) )
3747 const OpCode eOp
= pRawToken
->GetOpCode();
3756 pFunctionStack
[ nFunction
].eOp
= eLastOp
;
3757 pFunctionStack
[ nFunction
].nPar
= 0;
3765 SetError( errPairExpected
);
3769 aCorrectedSymbol
.Erase();
3774 if (bPODF
&& nFunction
)
3781 ++pFunctionStack
[ nFunction
].nPar
;
3787 SetError( errNestedArray
);
3790 // Don't count following column separator as parameter separator.
3794 pFunctionStack
[ nFunction
].eOp
= eOp
;
3795 pFunctionStack
[ nFunction
].nPar
= 0;
3807 SetError( errPairExpected
);
3811 aCorrectedSymbol
.Erase();
3814 if (bPODF
&& nFunction
)
3820 if( (eLastOp
== ocSep
||
3821 eLastOp
== ocArrayRowSep
||
3822 eLastOp
== ocArrayColSep
||
3823 eLastOp
== ocArrayOpen
) &&
3825 eOp
== ocArrayRowSep
||
3826 eOp
== ocArrayColSep
||
3827 eOp
== ocArrayClose
) )
3829 // FIXME: should we check for known functions with optional empty
3830 // args so the correction dialog can do better?
3831 if ( !static_cast<ScTokenArray
*>(pArr
)->Add( new FormulaMissingToken
) )
3833 SetError(errCodeOverflow
); break;
3838 /* TODO: for now this is the only PODF adapter. If there were more,
3839 * factor this out. */
3840 // Insert ADDRESS() new empty parameter 4 if there is a 4th, now to be 5th.
3842 pFunctionStack
[ nFunction
].eOp
== ocAddress
&&
3843 pFunctionStack
[ nFunction
].nPar
== 3)
3845 if (!static_cast<ScTokenArray
*>(pArr
)->Add( new FormulaToken( svSep
,ocSep
)) ||
3846 !static_cast<ScTokenArray
*>(pArr
)->Add( new FormulaDoubleToken( 1.0)))
3848 SetError(errCodeOverflow
); break;
3850 ++pFunctionStack
[ nFunction
].nPar
;
3853 FormulaToken
* pNewToken
= static_cast<ScTokenArray
*>(pArr
)->Add( pRawToken
->CreateToken());
3856 SetError(errCodeOverflow
); break;
3858 else if (eLastOp
== ocRange
&& pNewToken
->GetOpCode() == ocPush
&&
3859 pNewToken
->GetType() == svSingleRef
)
3860 static_cast<ScTokenArray
*>(pArr
)->MergeRangeReference( aPos
);
3861 eLastOp
= pRawToken
->GetOpCode();
3863 aCorrectedFormula
+= aCorrectedSymbol
;
3865 if ( mbCloseBrackets
)
3869 FormulaByteToken
aToken( ocArrayClose
);
3870 if( !pArr
->AddToken( aToken
) )
3872 SetError(errCodeOverflow
);
3874 else if ( bAutoCorrect
)
3875 aCorrectedFormula
+= mxSymbols
->getSymbol(ocArrayClose
);
3878 FormulaByteToken
aToken( ocClose
);
3879 while( nBrackets
-- )
3881 if( !pArr
->AddToken( aToken
) )
3883 SetError(errCodeOverflow
); break;
3886 aCorrectedFormula
+= mxSymbols
->getSymbol(ocClose
);
3890 pArr
->SetRecalcModeForced();
3892 if (pFunctionStack
!= &aFuncs
[0])
3893 delete [] pFunctionStack
;
3895 // remember pArr, in case a subsequent CompileTokenArray() is executed.
3896 ScTokenArray
* pNew
= new ScTokenArray( aArr
);
3902 ScTokenArray
* ScCompiler::CompileString( const String
& rFormula
, const String
& rFormulaNmsp
)
3904 DBG_ASSERT( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL
) || (rFormulaNmsp
.Len() == 0),
3905 "ScCompiler::CompileString - unexpected formula namespace for internal grammar" );
3906 if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL
) try
3908 ScFormulaParserPool
& rParserPool
= pDoc
->GetFormulaParserPool();
3909 uno::Reference
< sheet::XFormulaParser
> xParser( rParserPool
.getFormulaParser( rFormulaNmsp
), uno::UNO_SET_THROW
);
3910 table::CellAddress aReferencePos
;
3911 ScUnoConversion::FillApiAddress( aReferencePos
, aPos
);
3912 uno::Sequence
< sheet::FormulaToken
> aTokenSeq
= xParser
->parseFormula( rFormula
, aReferencePos
);
3913 ScTokenArray aTokenArray
;
3914 if( ScTokenConversion::ConvertToTokenArray( *pDoc
, aTokenArray
, aTokenSeq
) )
3916 // remember pArr, in case a subsequent CompileTokenArray() is executed.
3917 ScTokenArray
* pNew
= new ScTokenArray( aTokenArray
);
3922 catch( uno::Exception
& )
3925 // no success - fallback to some internal grammar and hope the best
3926 return CompileString( rFormula
);
3930 BOOL
ScCompiler::HandleRange()
3932 ScRangeData
* pRangeData
= pDoc
->GetRangeName()->FindIndex( pToken
->GetIndex() );
3935 USHORT nErr
= pRangeData
->GetErrCode();
3937 SetError( errNoName
);
3938 else if ( !bCompileForFAP
)
3941 // #35168# put named formula into parentheses.
3942 // #37680# But only if there aren't any yet, parenthetical
3943 // ocSep doesn't work, e.g. SUM((...;...))
3944 // or if not directly between ocSep/parenthesis,
3945 // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes,
3946 // in short: if it isn't a self-contained expression.
3947 FormulaToken
* p1
= pArr
->PeekPrevNoSpaces();
3948 FormulaToken
* p2
= pArr
->PeekNextNoSpaces();
3949 OpCode eOp1
= (p1
? p1
->GetOpCode() : static_cast<OpCode
>( ocSep
) );
3950 OpCode eOp2
= (p2
? p2
->GetOpCode() : static_cast<OpCode
>( ocSep
) );
3951 BOOL bBorder1
= (eOp1
== ocSep
|| eOp1
== ocOpen
);
3952 BOOL bBorder2
= (eOp2
== ocSep
|| eOp2
== ocClose
);
3953 BOOL bAddPair
= !(bBorder1
&& bBorder2
);
3956 pNew
= new ScTokenArray();
3957 pNew
->AddOpCode( ocClose
);
3958 PushTokenArray( pNew
, TRUE
);
3961 pNew
= pRangeData
->GetCode()->Clone();
3962 PushTokenArray( pNew
, TRUE
);
3963 if( pRangeData
->HasReferences() )
3965 SetRelNameReference();
3966 MoveRelWrap(pRangeData
->GetMaxCol(), pRangeData
->GetMaxRow());
3971 pNew
= new ScTokenArray();
3972 pNew
->AddOpCode( ocOpen
);
3973 PushTokenArray( pNew
, TRUE
);
3980 SetError(errNoName
);
3983 // -----------------------------------------------------------------------------
3984 BOOL
ScCompiler::HandleExternalReference(const FormulaToken
& _aToken
)
3986 // Handle external range names.
3987 switch (_aToken
.GetType())
3989 case svExternalSingleRef
:
3990 case svExternalDoubleRef
:
3991 pArr
->IncrementRefs();
3993 case svExternalName
:
3995 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
3996 const String
* pFile
= pRefMgr
->getExternalFileName(_aToken
.GetIndex());
3999 SetError(errNoName
);
4003 const String
& rName
= _aToken
.GetString();
4004 ScExternalRefCache::TokenArrayRef xNew
= pRefMgr
->getRangeNameTokens(
4005 _aToken
.GetIndex(), rName
, &aPos
);
4009 SetError(errNoName
);
4013 ScTokenArray
* pNew
= xNew
->Clone();
4014 PushTokenArray( pNew
, true);
4015 if (pNew
->GetNextReference() != NULL
)
4017 SetRelNameReference();
4018 MoveRelWrap(MAXCOL
, MAXROW
);
4024 DBG_ERROR("Wrong type for external reference!");
4031 //---------------------------------------------------------------------------
4034 //---------------------------------------------------------------------------
4035 // Append token to RPN code
4036 //---------------------------------------------------------------------------
4039 //-----------------------------------------------------------------------------
4041 //---------------------------------------------------------------------------
4042 // RPN creation by recursion
4043 //---------------------------------------------------------------------------
4047 //-----------------------------------------------------------------------------
4049 BOOL
ScCompiler::HasModifiedRange()
4052 for ( FormulaToken
* t
= pArr
->Next(); t
; t
= pArr
->Next() )
4054 OpCode eOpCode
= t
->GetOpCode();
4055 if ( eOpCode
== ocName
)
4057 ScRangeData
* pRangeData
= pDoc
->GetRangeName()->FindIndex(t
->GetIndex());
4059 if (pRangeData
&& pRangeData
->IsModified())
4062 else if ( eOpCode
== ocDBArea
)
4064 ScDBData
* pDBData
= pDoc
->GetDBCollection()->FindIndex(t
->GetIndex());
4066 if (pDBData
&& pDBData
->IsModified())
4074 //---------------------------------------------------------------------------
4076 template< typename T
, typename S
>
4077 S
lcl_adjval( S
& n
, T pos
, T max
, BOOL bRel
)
4081 n
= sal::static_int_cast
<S
>( n
+ pos
);
4083 n
= sal::static_int_cast
<S
>( n
+ max
);
4085 n
= sal::static_int_cast
<S
>( n
- max
);
4087 n
= sal::static_int_cast
<S
>( n
- pos
);
4091 // reference of named range with relative references
4093 void ScCompiler::SetRelNameReference()
4096 for( ScToken
* t
= static_cast<ScToken
*>(pArr
->GetNextReference()); t
;
4097 t
= static_cast<ScToken
*>(pArr
->GetNextReference()) )
4099 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4100 if ( rRef1
.IsColRel() || rRef1
.IsRowRel() || rRef1
.IsTabRel() )
4101 rRef1
.SetRelName( TRUE
);
4102 if ( t
->GetType() == svDoubleRef
)
4104 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4105 if ( rRef2
.IsColRel() || rRef2
.IsRowRel() || rRef2
.IsTabRel() )
4106 rRef2
.SetRelName( TRUE
);
4111 // Wrap-adjust relative references of a RangeName to current position,
4112 // don't call for other token arrays!
4113 void ScCompiler::MoveRelWrap( SCCOL nMaxCol
, SCROW nMaxRow
)
4116 for( ScToken
* t
= static_cast<ScToken
*>(pArr
->GetNextReference()); t
;
4117 t
= static_cast<ScToken
*>(pArr
->GetNextReference()) )
4119 if ( t
->GetType() == svSingleRef
|| t
->GetType() == svExternalSingleRef
)
4120 ScRefUpdate::MoveRelWrap( pDoc
, aPos
, nMaxCol
, nMaxRow
, SingleDoubleRefModifier( t
->GetSingleRef() ).Ref() );
4122 ScRefUpdate::MoveRelWrap( pDoc
, aPos
, nMaxCol
, nMaxRow
, t
->GetDoubleRef() );
4127 // Wrap-adjust relative references of a RangeName to current position,
4128 // don't call for other token arrays!
4129 void ScCompiler::MoveRelWrap( ScTokenArray
& rArr
, ScDocument
* pDoc
, const ScAddress
& rPos
,
4130 SCCOL nMaxCol
, SCROW nMaxRow
)
4133 for( ScToken
* t
= static_cast<ScToken
*>(rArr
.GetNextReference()); t
;
4134 t
= static_cast<ScToken
*>(rArr
.GetNextReference()) )
4136 if ( t
->GetType() == svSingleRef
|| t
->GetType() == svExternalSingleRef
)
4137 ScRefUpdate::MoveRelWrap( pDoc
, rPos
, nMaxCol
, nMaxRow
, SingleDoubleRefModifier( t
->GetSingleRef() ).Ref() );
4139 ScRefUpdate::MoveRelWrap( pDoc
, rPos
, nMaxCol
, nMaxRow
, t
->GetDoubleRef() );
4143 ScRangeData
* ScCompiler::UpdateReference(UpdateRefMode eUpdateRefMode
,
4144 const ScAddress
& rOldPos
, const ScRange
& r
,
4145 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
4146 BOOL
& rChanged
, BOOL
& rRefSizeChanged
)
4148 rChanged
= rRefSizeChanged
= FALSE
;
4149 if ( eUpdateRefMode
== URM_COPY
)
4150 { // Normally nothing has to be done here since RelRefs are used, also
4151 // SharedFormulas don't need any special handling, except if they
4152 // wrapped around sheet borders.
4153 // #67383# But ColRowName tokens pointing to a ColRow header which was
4154 // copied along with this formula need to be updated to point to the
4155 // copied header instead of the old position's new intersection.
4158 while( (t
= static_cast<ScToken
*>(pArr
->GetNextColRowName())) != NULL
)
4160 ScSingleRefData
& rRef
= t
->GetSingleRef();
4161 rRef
.CalcAbsIfRel( rOldPos
);
4162 ScAddress
aNewRef( rRef
.nCol
+ nDx
, rRef
.nRow
+ nDy
, rRef
.nTab
+ nDz
);
4163 if ( r
.In( aNewRef
) )
4164 { // yes, this is URM_MOVE
4165 if ( ScRefUpdate::Update( pDoc
, URM_MOVE
, aPos
,
4167 SingleDoubleRefModifier( rRef
).Ref() )
4173 // Check for SharedFormulas.
4174 ScRangeData
* pRangeData
= NULL
;
4176 for( FormulaToken
* j
= pArr
->GetNextName(); j
&& !pRangeData
;
4177 j
= pArr
->GetNextName() )
4179 if( j
->GetOpCode() == ocName
)
4181 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex( j
->GetIndex() );
4182 if (pName
&& pName
->HasType(RT_SHARED
))
4186 // Check SharedFormulas for wraps.
4189 ScRangeData
* pName
= pRangeData
;
4192 for( t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN()); t
&& !pRangeData
;
4193 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN()) )
4195 BOOL bRelName
= (t
->GetType() == svSingleRef
?
4196 t
->GetSingleRef().IsRelName() :
4197 (t
->GetDoubleRef().Ref1
.IsRelName() ||
4198 t
->GetDoubleRef().Ref2
.IsRelName()));
4201 t
->CalcAbsIfRel( rOldPos
);
4202 BOOL bValid
= (t
->GetType() == svSingleRef
?
4203 t
->GetSingleRef().Valid() :
4204 t
->GetDoubleRef().Valid());
4205 // If the reference isn't valid, copying the formula
4206 // wrapped it. Replace SharedFormula.
4220 * Set SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE to 1 if we wanted to preserve as
4221 * many shared formulas as possible instead of replacing them with direct code.
4222 * Note that this may produce shared formula usage Excel doesn't understand,
4223 * which would have to be adapted for in the export filter. Advisable as a long
4224 * term goal, since it could decrease memory footprint.
4226 #define SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 0
4227 ScRangeData
* pRangeData
= NULL
;
4230 while( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName())) != NULL
)
4232 if( t
->GetOpCode() == ocName
)
4234 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex( t
->GetIndex() );
4235 if (pName
&& pName
->HasType(RT_SHAREDMOD
))
4237 pRangeData
= pName
; // maybe need a replacement of shared with own code
4238 #if ! SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4243 else if( t
->GetType() != svIndex
) // it may be a DB area!!!
4245 t
->CalcAbsIfRel( rOldPos
);
4246 switch (t
->GetType())
4248 case svExternalSingleRef
:
4249 case svExternalDoubleRef
:
4250 // External references never change their positioning
4251 // nor point to parts that will be removed or expanded.
4252 // In fact, calling ScRefUpdate::Update() for URM_MOVE
4253 // may have negative side effects. Simply adapt
4254 // relative references to the new position.
4255 t
->CalcRelFromAbs( aPos
);
4259 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
4260 aPos
, r
, nDx
, nDy
, nDz
,
4261 SingleDoubleRefModifier(
4262 t
->GetSingleRef()).Ref())
4269 ScComplexRefData
& rRef
= t
->GetDoubleRef();
4270 SCCOL nCols
= rRef
.Ref2
.nCol
- rRef
.Ref1
.nCol
;
4271 SCROW nRows
= rRef
.Ref2
.nRow
- rRef
.Ref1
.nRow
;
4272 SCTAB nTabs
= rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
;
4273 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
4274 aPos
, r
, nDx
, nDy
, nDz
,
4275 t
->GetDoubleRef()) != UR_NOTHING
)
4278 if (rRef
.Ref2
.nCol
- rRef
.Ref1
.nCol
!= nCols
||
4279 rRef
.Ref2
.nRow
- rRef
.Ref1
.nRow
!= nRows
||
4280 rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
!= nTabs
)
4281 rRefSizeChanged
= TRUE
;
4287 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4288 BOOL bEasyShared
, bPosInRange
;
4290 bEasyShared
= bPosInRange
= FALSE
;
4294 bPosInRange
= r
.In( eUpdateRefMode
== URM_MOVE
? aPos
: rOldPos
);
4298 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN())) != NULL
)
4300 if ( t
->GetRef() != 1 )
4302 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4303 bEasyShared
= FALSE
;
4307 { // if nRefCnt>1 it's already updated in token code
4308 if ( t
->GetType() == svSingleRef
)
4310 ScSingleRefData
& rRef
= t
->GetSingleRef();
4311 SingleDoubleRefModifier
aMod( rRef
);
4312 if ( rRef
.IsRelName() )
4314 ScRefUpdate::MoveRelWrap( pDoc
, aPos
, MAXCOL
, MAXROW
, aMod
.Ref() );
4319 aMod
.Ref().CalcAbsIfRel( rOldPos
);
4320 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
, aPos
,
4321 r
, nDx
, nDy
, nDz
, aMod
.Ref() )
4326 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4329 const ScSingleRefData
& rSRD
= aMod
.Ref().Ref1
;
4330 ScAddress
aRef( rSRD
.nCol
, rSRD
.nRow
, rSRD
.nTab
);
4331 if ( r
.In( aRef
) != bPosInRange
)
4332 bEasyShared
= FALSE
;
4338 ScComplexRefData
& rRef
= t
->GetDoubleRef();
4339 SCCOL nCols
= rRef
.Ref2
.nCol
- rRef
.Ref1
.nCol
;
4340 SCROW nRows
= rRef
.Ref2
.nRow
- rRef
.Ref1
.nRow
;
4341 SCTAB nTabs
= rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
;
4342 if ( rRef
.Ref1
.IsRelName() || rRef
.Ref2
.IsRelName() )
4344 ScRefUpdate::MoveRelWrap( pDoc
, aPos
, MAXCOL
, MAXROW
, rRef
);
4349 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
, aPos
,
4350 r
, nDx
, nDy
, nDz
, rRef
)
4355 if (rRef
.Ref2
.nCol
- rRef
.Ref1
.nCol
!= nCols
||
4356 rRef
.Ref2
.nRow
- rRef
.Ref1
.nRow
!= nRows
||
4357 rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
!= nTabs
)
4359 rRefSizeChanged
= TRUE
;
4360 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4361 bEasyShared
= FALSE
;
4366 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4369 ScRange
aRef( rRef
.Ref1
.nCol
, rRef
.Ref1
.nRow
,
4370 rRef
.Ref1
.nTab
, rRef
.Ref2
.nCol
, rRef
.Ref2
.nRow
,
4372 if ( r
.In( aRef
) != bPosInRange
)
4373 bEasyShared
= FALSE
;
4379 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4388 #undef SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4393 BOOL
ScCompiler::UpdateNameReference(UpdateRefMode eUpdateRefMode
,
4395 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
4396 BOOL
& rChanged
, BOOL bSharedFormula
)
4398 BOOL bRelRef
= FALSE
; // set if relative reference
4402 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReference())) != NULL
)
4404 SingleDoubleRefModifier
aMod( *t
);
4405 ScComplexRefData
& rRef
= aMod
.Ref();
4406 bRelRef
= rRef
.Ref1
.IsColRel() || rRef
.Ref1
.IsRowRel() ||
4407 rRef
.Ref1
.IsTabRel();
4408 if (!bRelRef
&& t
->GetType() == svDoubleRef
)
4409 bRelRef
= rRef
.Ref2
.IsColRel() || rRef
.Ref2
.IsRowRel() ||
4410 rRef
.Ref2
.IsTabRel();
4411 bool bUpdate
= !rRef
.Ref1
.IsColRel() || !rRef
.Ref1
.IsRowRel() ||
4412 !rRef
.Ref1
.IsTabRel();
4413 if (!bUpdate
&& t
->GetType() == svDoubleRef
)
4414 bUpdate
= !rRef
.Ref2
.IsColRel() || !rRef
.Ref2
.IsRowRel() ||
4415 !rRef
.Ref2
.IsTabRel();
4416 if (!bSharedFormula
)
4418 // We cannot update names with sheet-relative references, they may
4419 // be used on other sheets as well and the resulting reference
4420 // would be wrong. This is a dilemma if col/row would need to be
4421 // updated for the current usage.
4422 // TODO: seems the only way out of this would be to not allow
4423 // relative sheet references and have sheet-local names that can be
4424 // copied along with sheets.
4425 bUpdate
= bUpdate
&& !rRef
.Ref1
.IsTabRel() && !rRef
.Ref2
.IsTabRel();
4429 rRef
.CalcAbsIfRel( aPos
);
4430 if (ScRefUpdate::Update( pDoc
, eUpdateRefMode
, aPos
, r
,
4431 nDx
, nDy
, nDz
, rRef
, ScRefUpdate::ABSOLUTE
)
4440 void ScCompiler::UpdateSharedFormulaReference( UpdateRefMode eUpdateRefMode
,
4441 const ScAddress
& rOldPos
, const ScRange
& r
,
4442 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
4444 if ( eUpdateRefMode
== URM_COPY
)
4450 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReference())) != NULL
)
4452 if( t
->GetType() != svIndex
) // it may be a DB area!!!
4454 t
->CalcAbsIfRel( rOldPos
);
4455 // Absolute references have been already adjusted in the named
4456 // shared formula itself prior to breaking the shared formula
4457 // and calling this function. Don't readjust them again.
4458 SingleDoubleRefModifier
aMod( *t
);
4459 ScComplexRefData
& rRef
= aMod
.Ref();
4460 ScComplexRefData aBkp
= rRef
;
4461 ScRefUpdate::Update( pDoc
, eUpdateRefMode
, aPos
,
4462 r
, nDx
, nDy
, nDz
, rRef
);
4463 // restore absolute parts
4464 if ( !aBkp
.Ref1
.IsColRel() )
4466 rRef
.Ref1
.nCol
= aBkp
.Ref1
.nCol
;
4467 rRef
.Ref1
.nRelCol
= aBkp
.Ref1
.nRelCol
;
4468 rRef
.Ref1
.SetColDeleted( aBkp
.Ref1
.IsColDeleted() );
4470 if ( !aBkp
.Ref1
.IsRowRel() )
4472 rRef
.Ref1
.nRow
= aBkp
.Ref1
.nRow
;
4473 rRef
.Ref1
.nRelRow
= aBkp
.Ref1
.nRelRow
;
4474 rRef
.Ref1
.SetRowDeleted( aBkp
.Ref1
.IsRowDeleted() );
4476 if ( !aBkp
.Ref1
.IsTabRel() )
4478 rRef
.Ref1
.nTab
= aBkp
.Ref1
.nTab
;
4479 rRef
.Ref1
.nRelTab
= aBkp
.Ref1
.nRelTab
;
4480 rRef
.Ref1
.SetTabDeleted( aBkp
.Ref1
.IsTabDeleted() );
4482 if ( t
->GetType() == svDoubleRef
)
4484 if ( !aBkp
.Ref2
.IsColRel() )
4486 rRef
.Ref2
.nCol
= aBkp
.Ref2
.nCol
;
4487 rRef
.Ref2
.nRelCol
= aBkp
.Ref2
.nRelCol
;
4488 rRef
.Ref2
.SetColDeleted( aBkp
.Ref2
.IsColDeleted() );
4490 if ( !aBkp
.Ref2
.IsRowRel() )
4492 rRef
.Ref2
.nRow
= aBkp
.Ref2
.nRow
;
4493 rRef
.Ref2
.nRelRow
= aBkp
.Ref2
.nRelRow
;
4494 rRef
.Ref2
.SetRowDeleted( aBkp
.Ref2
.IsRowDeleted() );
4496 if ( !aBkp
.Ref2
.IsTabRel() )
4498 rRef
.Ref2
.nTab
= aBkp
.Ref2
.nTab
;
4499 rRef
.Ref2
.nRelTab
= aBkp
.Ref2
.nRelTab
;
4500 rRef
.Ref2
.SetTabDeleted( aBkp
.Ref2
.IsTabDeleted() );
4509 ScRangeData
* ScCompiler::UpdateInsertTab( SCTAB nTable
, BOOL bIsName
)
4511 ScRangeData
* pRangeData
= NULL
;
4512 SCTAB nPosTab
= aPos
.Tab(); // _after_ incremented!
4513 SCTAB nOldPosTab
= ((nPosTab
> nTable
) ? (nPosTab
- 1) : nPosTab
);
4514 BOOL bIsRel
= FALSE
;
4518 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4520 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4523 if( t
->GetOpCode() == ocName
)
4527 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex(t
->GetIndex());
4528 if (pName
&& pName
->HasType(RT_SHAREDMOD
))
4532 else if( t
->GetType() != svIndex
) // it may be a DB area!!!
4534 if ( !(bIsName
&& t
->GetSingleRef().IsTabRel()) )
4535 { // of names only adjust absolute references
4536 ScSingleRefData
& rRef
= t
->GetSingleRef();
4537 if ( rRef
.IsTabRel() )
4539 rRef
.nTab
= rRef
.nRelTab
+ nOldPosTab
;
4540 if ( rRef
.nTab
< 0 )
4541 rRef
.nTab
= sal::static_int_cast
<SCsTAB
>( rRef
.nTab
+ pDoc
->GetTableCount() ); // was a wrap
4543 if (nTable
<= rRef
.nTab
)
4545 rRef
.nRelTab
= rRef
.nTab
- nPosTab
;
4549 if ( t
->GetType() == svDoubleRef
)
4551 if ( !(bIsName
&& t
->GetDoubleRef().Ref2
.IsTabRel()) )
4552 { // of names only adjust absolute references
4553 ScSingleRefData
& rRef
= t
->GetDoubleRef().Ref2
;
4554 if ( rRef
.IsTabRel() )
4556 rRef
.nTab
= rRef
.nRelTab
+ nOldPosTab
;
4557 if ( rRef
.nTab
< 0 )
4558 rRef
.nTab
= sal::static_int_cast
<SCsTAB
>( rRef
.nTab
+ pDoc
->GetTableCount() ); // was a wrap
4560 if (nTable
<= rRef
.nTab
)
4562 rRef
.nRelTab
= rRef
.nTab
- nPosTab
;
4567 if ( bIsName
&& bIsRel
)
4568 pRangeData
= (ScRangeData
*) this; // not dereferenced in rangenam
4571 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4573 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4578 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN())) != NULL
)
4580 if ( t
->GetRef() == 1 )
4582 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4583 if ( !(rRef1
.IsRelName() && rRef1
.IsTabRel()) )
4584 { // of names only adjust absolute references
4585 if ( rRef1
.IsTabRel() )
4587 rRef1
.nTab
= rRef1
.nRelTab
+ nOldPosTab
;
4588 if ( rRef1
.nTab
< 0 )
4589 rRef1
.nTab
= sal::static_int_cast
<SCsTAB
>( rRef1
.nTab
+ pDoc
->GetTableCount() ); // was a wrap
4591 if (nTable
<= rRef1
.nTab
)
4593 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4595 if ( t
->GetType() == svDoubleRef
)
4597 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4598 if ( !(rRef2
.IsRelName() && rRef2
.IsTabRel()) )
4599 { // of names only adjust absolute references
4600 if ( rRef2
.IsTabRel() )
4602 rRef2
.nTab
= rRef2
.nRelTab
+ nOldPosTab
;
4603 if ( rRef2
.nTab
< 0 )
4604 rRef2
.nTab
= sal::static_int_cast
<SCsTAB
>( rRef2
.nTab
+ pDoc
->GetTableCount() ); // was a wrap
4606 if (nTable
<= rRef2
.nTab
)
4608 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4617 ScRangeData
* ScCompiler::UpdateDeleteTab(SCTAB nTable
, BOOL
/* bIsMove */, BOOL bIsName
,
4620 ScRangeData
* pRangeData
= NULL
;
4622 SCTAB nPosTab
= aPos
.Tab(); // _after_ decremented!
4623 SCTAB nOldPosTab
= ((nPosTab
>= nTable
) ? (nPosTab
+ 1) : nPosTab
);
4625 BOOL bIsRel
= FALSE
;
4629 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4631 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4634 if( t
->GetOpCode() == ocName
)
4638 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex(t
->GetIndex());
4639 if (pName
&& pName
->HasType(RT_SHAREDMOD
))
4644 else if( t
->GetType() != svIndex
) // it may be a DB area!!!
4646 if ( !(bIsName
&& t
->GetSingleRef().IsTabRel()) )
4647 { // of names only adjust absolute references
4648 ScSingleRefData
& rRef
= t
->GetSingleRef();
4649 if ( rRef
.IsTabRel() )
4650 nTab
= rRef
.nTab
= rRef
.nRelTab
+ nOldPosTab
;
4653 if ( nTable
< nTab
)
4655 rRef
.nTab
= nTab
- 1;
4658 else if ( nTable
== nTab
)
4660 if ( t
->GetType() == svDoubleRef
)
4662 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4663 if ( rRef2
.IsTabRel() )
4664 nTab2
= rRef2
.nRelTab
+ nOldPosTab
;
4668 || (nTab
+1) >= pDoc
->GetTableCount() )
4670 rRef
.nTab
= MAXTAB
+1;
4671 rRef
.SetTabDeleted( TRUE
);
4673 // else: nTab later points to what's nTable+1 now
4678 rRef
.nTab
= MAXTAB
+1;
4679 rRef
.SetTabDeleted( TRUE
);
4683 rRef
.nRelTab
= rRef
.nTab
- nPosTab
;
4687 if ( t
->GetType() == svDoubleRef
)
4689 if ( !(bIsName
&& t
->GetDoubleRef().Ref2
.IsTabRel()) )
4690 { // of names only adjust absolute references
4691 ScSingleRefData
& rRef
= t
->GetDoubleRef().Ref2
;
4692 if ( rRef
.IsTabRel() )
4693 nTab
= rRef
.nTab
= rRef
.nRelTab
+ nOldPosTab
;
4696 if ( nTable
< nTab
)
4698 rRef
.nTab
= nTab
- 1;
4701 else if ( nTable
== nTab
)
4703 if ( !t
->GetDoubleRef().Ref1
.IsTabDeleted() )
4704 rRef
.nTab
= nTab
- 1; // shrink area
4707 rRef
.nTab
= MAXTAB
+1;
4708 rRef
.SetTabDeleted( TRUE
);
4712 rRef
.nRelTab
= rRef
.nTab
- nPosTab
;
4717 if ( bIsName
&& bIsRel
)
4718 pRangeData
= (ScRangeData
*) this; // not dereferenced in rangenam
4721 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4723 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4728 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN())) != NULL
)
4730 if ( t
->GetRef() == 1 )
4732 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4733 if ( !(rRef1
.IsRelName() && rRef1
.IsTabRel()) )
4734 { // of names only adjust absolute references
4735 if ( rRef1
.IsTabRel() )
4736 nTab
= rRef1
.nTab
= rRef1
.nRelTab
+ nOldPosTab
;
4739 if ( nTable
< nTab
)
4741 rRef1
.nTab
= nTab
- 1;
4744 else if ( nTable
== nTab
)
4746 if ( t
->GetType() == svDoubleRef
)
4748 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4749 if ( rRef2
.IsTabRel() )
4750 nTab2
= rRef2
.nRelTab
+ nOldPosTab
;
4754 || (nTab
+1) >= pDoc
->GetTableCount() )
4756 rRef1
.nTab
= MAXTAB
+1;
4757 rRef1
.SetTabDeleted( TRUE
);
4759 // else: nTab later points to what's nTable+1 now
4764 rRef1
.nTab
= MAXTAB
+1;
4765 rRef1
.SetTabDeleted( TRUE
);
4769 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4771 if ( t
->GetType() == svDoubleRef
)
4773 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4774 if ( !(rRef2
.IsRelName() && rRef2
.IsTabRel()) )
4775 { // of names only adjust absolute references
4776 if ( rRef2
.IsTabRel() )
4777 nTab
= rRef2
.nTab
= rRef2
.nRelTab
+ nOldPosTab
;
4780 if ( nTable
< nTab
)
4782 rRef2
.nTab
= nTab
- 1;
4785 else if ( nTable
== nTab
)
4787 if ( !rRef1
.IsTabDeleted() )
4788 rRef2
.nTab
= nTab
- 1; // shrink area
4791 rRef2
.nTab
= MAXTAB
+1;
4792 rRef2
.SetTabDeleted( TRUE
);
4796 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4805 // aPos.Tab() must be already adjusted!
4806 ScRangeData
* ScCompiler::UpdateMoveTab( SCTAB nOldTab
, SCTAB nNewTab
,
4809 ScRangeData
* pRangeData
= NULL
;
4813 short nDir
; // direction in which others move
4814 if ( nOldTab
< nNewTab
)
4826 SCTAB nPosTab
= aPos
.Tab(); // current sheet
4827 SCTAB nOldPosTab
; // previously it was this one
4828 if ( nPosTab
== nNewTab
)
4829 nOldPosTab
= nOldTab
; // look, it's me!
4830 else if ( nPosTab
< nStart
|| nEnd
< nPosTab
)
4831 nOldPosTab
= nPosTab
; // wasn't moved
4833 nOldPosTab
= nPosTab
- nDir
; // moved by one
4835 BOOL bIsRel
= FALSE
;
4839 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4841 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4844 if( t
->GetOpCode() == ocName
)
4848 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex(t
->GetIndex());
4849 if (pName
&& pName
->HasType(RT_SHAREDMOD
))
4853 else if( t
->GetType() != svIndex
) // it may be a DB area!!!
4855 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4856 if ( !(bIsName
&& rRef1
.IsTabRel()) )
4857 { // of names only adjust absolute references
4858 if ( rRef1
.IsTabRel() )
4859 nTab
= rRef1
.nRelTab
+ nOldPosTab
;
4862 if ( nTab
== nOldTab
)
4863 rRef1
.nTab
= nNewTab
;
4864 else if ( nStart
<= nTab
&& nTab
<= nEnd
)
4865 rRef1
.nTab
= nTab
+ nDir
;
4866 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4870 if ( t
->GetType() == svDoubleRef
)
4872 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4873 if ( !(bIsName
&& rRef2
.IsTabRel()) )
4874 { // of names only adjust absolute references
4875 if ( rRef2
.IsTabRel() )
4876 nTab
= rRef2
.nRelTab
+ nOldPosTab
;
4879 if ( nTab
== nOldTab
)
4880 rRef2
.nTab
= nNewTab
;
4881 else if ( nStart
<= nTab
&& nTab
<= nEnd
)
4882 rRef2
.nTab
= nTab
+ nDir
;
4883 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4887 SCsTAB nTab1
, nTab2
;
4888 if ( rRef1
.IsTabRel() )
4889 nTab1
= rRef1
.nRelTab
+ nPosTab
;
4892 if ( rRef2
.IsTabRel() )
4893 nTab2
= rRef2
.nRelTab
+ nPosTab
;
4896 if ( nTab2
< nTab1
)
4900 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4901 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4904 if ( bIsName
&& bIsRel
)
4905 pRangeData
= (ScRangeData
*) this; // not dereferenced in rangenam
4908 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4910 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4914 SCsTAB nMaxTabMod
= (SCsTAB
) pDoc
->GetTableCount();
4916 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN())) != NULL
)
4918 if ( t
->GetRef() == 1 )
4920 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4921 if ( rRef1
.IsRelName() && rRef1
.IsTabRel() )
4922 { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx
4923 nTab
= rRef1
.nRelTab
+ nPosTab
;
4925 nTab
= sal::static_int_cast
<SCsTAB
>( nTab
+ nMaxTabMod
);
4926 else if ( nTab
> nMaxTab
)
4927 nTab
= sal::static_int_cast
<SCsTAB
>( nTab
- nMaxTabMod
);
4928 rRef1
.nRelTab
= nTab
- nPosTab
;
4932 if ( rRef1
.IsTabRel() )
4933 nTab
= rRef1
.nRelTab
+ nOldPosTab
;
4936 if ( nTab
== nOldTab
)
4937 rRef1
.nTab
= nNewTab
;
4938 else if ( nStart
<= nTab
&& nTab
<= nEnd
)
4939 rRef1
.nTab
= nTab
+ nDir
;
4940 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4942 if( t
->GetType() == svDoubleRef
)
4944 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4945 if ( rRef2
.IsRelName() && rRef2
.IsTabRel() )
4946 { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx
4947 nTab
= rRef2
.nRelTab
+ nPosTab
;
4949 nTab
= sal::static_int_cast
<SCsTAB
>( nTab
+ nMaxTabMod
);
4950 else if ( nTab
> nMaxTab
)
4951 nTab
= sal::static_int_cast
<SCsTAB
>( nTab
- nMaxTabMod
);
4952 rRef2
.nRelTab
= nTab
- nPosTab
;
4956 if ( rRef2
.IsTabRel() )
4957 nTab
= rRef2
.nRelTab
+ nOldPosTab
;
4960 if ( nTab
== nOldTab
)
4961 rRef2
.nTab
= nNewTab
;
4962 else if ( nStart
<= nTab
&& nTab
<= nEnd
)
4963 rRef2
.nTab
= nTab
+ nDir
;
4964 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4966 SCsTAB nTab1
, nTab2
;
4967 if ( rRef1
.IsTabRel() )
4968 nTab1
= rRef1
.nRelTab
+ nPosTab
;
4971 if ( rRef2
.IsTabRel() )
4972 nTab2
= rRef2
.nRelTab
+ nPosTab
;
4975 if ( nTab2
< nTab1
)
4979 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4980 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4990 void ScCompiler::CreateStringFromExternal(rtl::OUStringBuffer
& rBuffer
, FormulaToken
* pTokenP
)
4992 FormulaToken
* t
= pTokenP
;
4993 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
4994 switch (t
->GetType())
4996 case svExternalName
:
4998 const String
*pStr
= pRefMgr
->getExternalFileName(t
->GetIndex());
4999 String aFileName
= pStr
? *pStr
: ScGlobal::GetRscString(STR_NO_NAME_REF
);
5000 rBuffer
.append(pConv
->makeExternalNameStr( aFileName
, t
->GetString()));
5003 case svExternalSingleRef
:
5004 pConv
->makeExternalRefStr(
5005 rBuffer
, *this, t
->GetIndex(), t
->GetString(), static_cast<ScToken
*>(t
)->GetSingleRef(), pRefMgr
);
5007 case svExternalDoubleRef
:
5008 pConv
->makeExternalRefStr(
5009 rBuffer
, *this, t
->GetIndex(), t
->GetString(), static_cast<ScToken
*>(t
)->GetDoubleRef(), pRefMgr
);
5012 // warning, not error, otherwise we may end up with a never
5013 // ending message box loop if this was the cursor cell to be redrawn.
5014 DBG_WARNING("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef");
5018 void ScCompiler::CreateStringFromMatrix( rtl::OUStringBuffer
& rBuffer
,
5019 FormulaToken
* pTokenP
)
5021 const ScMatrix
* pMatrix
= static_cast<ScToken
*>(pTokenP
)->GetMatrix();
5022 SCSIZE nC
, nMaxC
, nR
, nMaxR
;
5024 pMatrix
->GetDimensions( nMaxC
, nMaxR
);
5026 rBuffer
.append( mxSymbols
->getSymbol(ocArrayOpen
) );
5027 for( nR
= 0 ; nR
< nMaxR
; nR
++)
5031 rBuffer
.append( mxSymbols
->getSymbol(ocArrayRowSep
) );
5034 for( nC
= 0 ; nC
< nMaxC
; nC
++)
5038 rBuffer
.append( mxSymbols
->getSymbol(ocArrayColSep
) );
5041 if( pMatrix
->IsValue( nC
, nR
) )
5044 const ScMatrixValue
* pVal
= pMatrix
->Get( nC
, nR
, nType
);
5046 if( nType
== SC_MATVAL_BOOLEAN
)
5047 AppendBoolean( rBuffer
, pVal
->GetBoolean() );
5050 USHORT nErr
= pVal
->GetError();
5052 rBuffer
.append( ScGlobal::GetErrorString( nErr
) );
5054 AppendDouble( rBuffer
, pVal
->fVal
);
5057 else if( pMatrix
->IsEmpty( nC
, nR
) )
5059 else if( pMatrix
->IsString( nC
, nR
) )
5060 AppendString( rBuffer
, pMatrix
->GetString( nC
, nR
) );
5063 rBuffer
.append( mxSymbols
->getSymbol(ocArrayClose
) );
5066 void ScCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer
& rBuffer
,FormulaToken
* _pTokenP
)
5068 const OpCode eOp
= _pTokenP
->GetOpCode();
5069 ScSingleRefData
& rRef
= static_cast<ScToken
*>(_pTokenP
)->GetSingleRef();
5070 ScComplexRefData aRef
;
5071 aRef
.Ref1
= aRef
.Ref2
= rRef
;
5072 if ( eOp
== ocColRowName
)
5074 rRef
.CalcAbsIfRel( aPos
);
5075 if ( pDoc
->HasStringData( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
) )
5078 pDoc
->GetString( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
, aStr
);
5080 rBuffer
.append(aStr
);
5084 rBuffer
.append(ScGlobal::GetRscString(STR_NO_NAME_REF
));
5085 pConv
->MakeRefStr (rBuffer
, *this, aRef
, TRUE
);
5089 pConv
->MakeRefStr( rBuffer
, *this, aRef
, TRUE
);
5091 // -----------------------------------------------------------------------------
5092 void ScCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer
& rBuffer
,FormulaToken
* _pTokenP
)
5094 pConv
->MakeRefStr( rBuffer
, *this, static_cast<ScToken
*>(_pTokenP
)->GetDoubleRef(), FALSE
);
5096 // -----------------------------------------------------------------------------
5097 void ScCompiler::CreateStringFromIndex(rtl::OUStringBuffer
& rBuffer
,FormulaToken
* _pTokenP
)
5099 const OpCode eOp
= _pTokenP
->GetOpCode();
5100 rtl::OUStringBuffer aBuffer
;
5105 ScRangeData
* pData
= pDoc
->GetRangeName()->FindIndex(_pTokenP
->GetIndex());
5108 if (pData
->HasType(RT_SHARED
))
5109 pData
->UpdateSymbol( aBuffer
, aPos
, GetGrammar());
5111 aBuffer
.append(pData
->GetName());
5117 ScDBData
* pDBData
= pDoc
->GetDBCollection()->FindIndex(_pTokenP
->GetIndex());
5119 aBuffer
.append(pDBData
->GetName());
5125 if ( aBuffer
.getLength() )
5126 rBuffer
.append(aBuffer
);
5128 rBuffer
.append(ScGlobal::GetRscString(STR_NO_NAME_REF
));
5130 // -----------------------------------------------------------------------------
5131 void ScCompiler::LocalizeString( String
& rName
)
5133 ScGlobal::GetAddInCollection()->LocalizeString( rName
);
5135 // -----------------------------------------------------------------------------
5136 BOOL
ScCompiler::IsImportingXML() const
5138 return pDoc
->IsImportingXML();
5141 // Put quotes around string if non-alphanumeric characters are contained,
5142 // quote characters contained within are escaped by '\\'.
5143 BOOL
ScCompiler::EnQuote( String
& rStr
)
5145 sal_Int32 nType
= ScGlobal::pCharClass
->getStringType( rStr
, 0, rStr
.Len() );
5146 if ( !CharClass::isNumericType( nType
)
5147 && CharClass::isAlphaNumericType( nType
) )
5150 xub_StrLen nPos
= 0;
5151 while ( (nPos
= rStr
.Search( '\'', nPos
)) != STRING_NOTFOUND
)
5153 rStr
.Insert( '\\', nPos
);
5156 rStr
.Insert( '\'', 0 );
5161 sal_Unicode
ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eType
) const
5163 return pConv
->getSpecialSymbol(eType
);
5166 void ScCompiler::fillAddInToken(::std::vector
< ::com::sun::star::sheet::FormulaOpCodeMapEntry
>& _rVec
,bool _bIsEnglish
) const
5168 // All known AddIn functions.
5169 sheet::FormulaOpCodeMapEntry aEntry
;
5170 aEntry
.Token
.OpCode
= ocExternal
;
5172 ScUnoAddInCollection
* pColl
= ScGlobal::GetAddInCollection();
5173 const long nCount
= pColl
->GetFuncCount();
5174 for (long i
=0; i
< nCount
; ++i
)
5176 const ScUnoAddInFuncData
* pFuncData
= pColl
->GetFuncData(i
);
5182 if (pFuncData
->GetExcelName( LANGUAGE_ENGLISH_US
, aName
))
5183 aEntry
.Name
= aName
;
5185 aEntry
.Name
= pFuncData
->GetUpperName();
5188 aEntry
.Name
= pFuncData
->GetUpperLocal();
5189 aEntry
.Token
.Data
<<= ::rtl::OUString( pFuncData
->GetOriginalName());
5190 _rVec
.push_back( aEntry
);
5193 // FIXME: what about those old non-UNO AddIns?
5195 // -----------------------------------------------------------------------------
5196 BOOL
ScCompiler::HandleSingleRef()
5198 ScSingleRefData
& rRef
= static_cast<ScToken
*>((FormulaToken
*)pToken
)->GetSingleRef();
5199 rRef
.CalcAbsIfRel( aPos
);
5200 if ( !rRef
.Valid() )
5202 SetError( errNoRef
);
5205 SCCOL nCol
= rRef
.nCol
;
5206 SCROW nRow
= rRef
.nRow
;
5207 SCTAB nTab
= rRef
.nTab
;
5208 ScAddress
aLook( nCol
, nRow
, nTab
);
5209 BOOL bColName
= rRef
.IsColRel();
5210 SCCOL nMyCol
= aPos
.Col();
5211 SCROW nMyRow
= aPos
.Row();
5212 BOOL bInList
= FALSE
;
5213 BOOL bValidName
= FALSE
;
5214 ScRangePairList
* pRL
= (bColName
?
5215 pDoc
->GetColNameRanges() : pDoc
->GetRowNameRanges());
5217 for ( ScRangePair
* pR
= pRL
->First(); pR
; pR
= pRL
->Next() )
5219 if ( pR
->GetRange(0).In( aLook
) )
5221 bInList
= bValidName
= TRUE
;
5222 aRange
= pR
->GetRange(1);
5225 aRange
.aStart
.SetCol( nCol
);
5226 aRange
.aEnd
.SetCol( nCol
);
5230 aRange
.aStart
.SetRow( nRow
);
5231 aRange
.aEnd
.SetRow( nRow
);
5236 if ( !bInList
&& pDoc
->GetDocOptions().IsLookUpColRowNames() )
5237 { // automagically or created by copying and NamePos isn't in list
5238 BOOL bString
= pDoc
->HasStringData( nCol
, nRow
, nTab
);
5239 if ( !bString
&& !pDoc
->GetCell( aLook
) )
5240 bString
= TRUE
; // empty cell is ok
5242 { //! coresponds with ScInterpreter::ScColRowNameAuto()
5246 SCROW nStartRow
= nRow
+ 1;
5247 if ( nStartRow
> MAXROW
)
5249 SCROW nMaxRow
= MAXROW
;
5250 if ( nMyCol
== nCol
)
5251 { // formula cell in same column
5252 if ( nMyRow
== nStartRow
)
5253 { // take remainder under name cell
5255 if ( nStartRow
> MAXROW
)
5258 else if ( nMyRow
> nStartRow
)
5259 { // from name cell down to formula cell
5260 nMaxRow
= nMyRow
- 1;
5263 for ( ScRangePair
* pR
= pRL
->First(); pR
; pR
= pRL
->Next() )
5264 { // next defined ColNameRange below limits row
5265 const ScRange
& rRange
= pR
->GetRange(1);
5266 if ( rRange
.aStart
.Col() <= nCol
&& nCol
<= rRange
.aEnd
.Col() )
5267 { // identical column range
5268 SCROW nTmp
= rRange
.aStart
.Row();
5269 if ( nStartRow
< nTmp
&& nTmp
<= nMaxRow
)
5273 aRange
.aStart
.Set( nCol
, nStartRow
, nTab
);
5274 aRange
.aEnd
.Set( nCol
, nMaxRow
, nTab
);
5278 SCCOL nStartCol
= nCol
+ 1;
5279 if ( nStartCol
> MAXCOL
)
5281 SCCOL nMaxCol
= MAXCOL
;
5282 if ( nMyRow
== nRow
)
5283 { // formula cell in same row
5284 if ( nMyCol
== nStartCol
)
5285 { // take remainder right from name cell
5287 if ( nStartCol
> MAXCOL
)
5290 else if ( nMyCol
> nStartCol
)
5291 { // from name cell right to formula cell
5292 nMaxCol
= nMyCol
- 1;
5295 for ( ScRangePair
* pR
= pRL
->First(); pR
; pR
= pRL
->Next() )
5296 { // next defined RowNameRange to the right limits column
5297 const ScRange
& rRange
= pR
->GetRange(1);
5298 if ( rRange
.aStart
.Row() <= nRow
&& nRow
<= rRange
.aEnd
.Row() )
5299 { // identical row range
5300 SCCOL nTmp
= rRange
.aStart
.Col();
5301 if ( nStartCol
< nTmp
&& nTmp
<= nMaxCol
)
5305 aRange
.aStart
.Set( nStartCol
, nRow
, nTab
);
5306 aRange
.aEnd
.Set( nMaxCol
, nRow
, nTab
);
5312 // And now the magic to distinguish between a range and a single
5313 // cell thereof, which is picked position-dependent of the formula
5314 // cell. If a direct neighbor is a binary operator (ocAdd, ...) a
5315 // SingleRef matching the column/row of the formula cell is
5316 // generated. A ocColRowName or ocIntersect as a neighbor results
5317 // in a range. Special case: if label is valid for a single cell, a
5318 // position independent SingleRef is generated.
5319 BOOL bSingle
= (aRange
.aStart
== aRange
.aEnd
);
5325 FormulaToken
* p1
= pArr
->PeekPrevNoSpaces();
5326 FormulaToken
* p2
= pArr
->PeekNextNoSpaces();
5327 // begin/end of a formula => single
5328 OpCode eOp1
= p1
? p1
->GetOpCode() : static_cast<OpCode
>( ocAdd
);
5329 OpCode eOp2
= p2
? p2
->GetOpCode() : static_cast<OpCode
>( ocAdd
);
5330 if ( eOp1
!= ocColRowName
&& eOp1
!= ocIntersect
5331 && eOp2
!= ocColRowName
&& eOp2
!= ocIntersect
)
5333 if ( (SC_OPCODE_START_BIN_OP
<= eOp1
&& eOp1
< SC_OPCODE_STOP_BIN_OP
) ||
5334 (SC_OPCODE_START_BIN_OP
<= eOp2
&& eOp2
< SC_OPCODE_STOP_BIN_OP
))
5338 { // column and/or row must match range
5341 bFound
= (aRange
.aStart
.Row() <= nMyRow
5342 && nMyRow
<= aRange
.aEnd
.Row());
5344 aRange
.aStart
.SetRow( nMyRow
);
5348 bFound
= (aRange
.aStart
.Col() <= nMyCol
5349 && nMyCol
<= aRange
.aEnd
.Col());
5351 aRange
.aStart
.SetCol( nMyCol
);
5359 else if ( !bCompileForFAP
)
5361 ScTokenArray
* pNew
= new ScTokenArray();
5364 ScSingleRefData aRefData
;
5365 aRefData
.InitAddress( aRange
.aStart
);
5367 aRefData
.SetColRel( TRUE
);
5369 aRefData
.SetRowRel( TRUE
);
5370 aRefData
.CalcRelFromAbs( aPos
);
5371 pNew
->AddSingleReference( aRefData
);
5375 ScComplexRefData aRefData
;
5376 aRefData
.InitRange( aRange
);
5379 aRefData
.Ref1
.SetColRel( TRUE
);
5380 aRefData
.Ref2
.SetColRel( TRUE
);
5384 aRefData
.Ref1
.SetRowRel( TRUE
);
5385 aRefData
.Ref2
.SetRowRel( TRUE
);
5387 aRefData
.CalcRelFromAbs( aPos
);
5389 pNew
->AddDoubleReference( aRefData
);
5392 pNew
->Add( new ScDoubleRefToken( aRefData
, ocColRowNameAuto
) );
5395 PushTokenArray( pNew
, TRUE
);
5401 SetError(errNoName
);
5404 // -----------------------------------------------------------------------------
5405 BOOL
ScCompiler::HandleDbData()
5407 ScDBData
* pDBData
= pDoc
->GetDBCollection()->FindIndex( pToken
->GetIndex() );
5409 SetError(errNoName
);
5410 else if ( !bCompileForFAP
)
5412 ScComplexRefData aRefData
;
5413 aRefData
.InitFlags();
5414 pDBData
->GetArea( (SCTAB
&) aRefData
.Ref1
.nTab
,
5415 (SCCOL
&) aRefData
.Ref1
.nCol
,
5416 (SCROW
&) aRefData
.Ref1
.nRow
,
5417 (SCCOL
&) aRefData
.Ref2
.nCol
,
5418 (SCROW
&) aRefData
.Ref2
.nRow
);
5419 aRefData
.Ref2
.nTab
= aRefData
.Ref1
.nTab
;
5420 aRefData
.CalcRelFromAbs( aPos
);
5421 ScTokenArray
* pNew
= new ScTokenArray();
5422 pNew
->AddDoubleReference( aRefData
);
5423 PushTokenArray( pNew
, TRUE
);
5430 String
GetScCompilerNativeSymbol( OpCode eOp
)
5432 return ScCompiler::GetNativeSymbol( eOp
);
5434 // -----------------------------------------------------------------------------
5435 FormulaTokenRef
ScCompiler::ExtendRangeReference( FormulaToken
& rTok1
, FormulaToken
& rTok2
, bool bReuseDoubleRef
)
5437 return ScToken::ExtendRangeReference( rTok1
, rTok2
, aPos
,bReuseDoubleRef
);