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
);
376 void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr
& xMap
)
381 if (mxSymbols
->isEnglish())
383 if (!pCharClassEnglish
)
384 InitCharClassEnglish();
385 pCharClass
= pCharClassEnglish
;
388 pCharClass
= ScGlobal::pCharClass
;
389 SetGrammarAndRefConvention( mxSymbols
->getGrammar(), GetGrammar());
394 void ScCompiler::SetGrammarAndRefConvention(
395 const FormulaGrammar::Grammar eNewGrammar
, const FormulaGrammar::Grammar eOldGrammar
)
397 meGrammar
= eNewGrammar
; //! SetRefConvention needs the new grammar set!
398 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::extractRefConvention( meGrammar
);
399 if (eConv
== FormulaGrammar::CONV_UNSPECIFIED
&& eOldGrammar
== FormulaGrammar::GRAM_UNSPECIFIED
)
402 SetRefConvention( pDoc
->GetAddressConvention());
404 SetRefConvention( pConvOOO_A1
);
407 SetRefConvention( eConv
);
410 String
ScCompiler::FindAddInFunction( const String
& rUpperName
, BOOL bLocalFirst
) const
412 return ScGlobal::GetAddInCollection()->FindFunction(rUpperName
, bLocalFirst
); // bLocalFirst=FALSE for english
417 void dbg_call_testcreatemapping()
419 using namespace ::com::sun::star::sheet
;
420 ScCompiler::OpCodeMapPtr xMap
= ScCompiler::GetOpCodeMap( FormulaLanguage::ODFF
);
421 xMap
->createSequenceOfAvailableMappings( FormulaMapGroup::FUNCTIONS
);
425 //-----------------------------------------------------------------------------
427 ScCompiler::Convention::~Convention()
429 delete [] mpCharTable
;
433 ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv
)
438 ULONG
*t
= new ULONG
[128];
440 ScCompiler::pConventions
[ meConv
] = this;
443 for (i
= 0; i
< 128; i
++)
444 t
[i
] = SC_COMPILER_C_ILLEGAL
;
446 /* */ t
[32] = SC_COMPILER_C_CHAR_DONTCARE
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
447 /* ! */ t
[33] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
448 if (FormulaGrammar::CONV_ODF
== meConv
)
449 /* ! */ t
[33] |= SC_COMPILER_C_ODF_LABEL_OP
;
450 /* " */ t
[34] = SC_COMPILER_C_CHAR_STRING
| SC_COMPILER_C_STRING_SEP
;
451 /* # */ t
[35] = SC_COMPILER_C_WORD_SEP
;
452 /* $ */ t
[36] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_IDENT
| SC_COMPILER_C_IDENT
;
453 if (FormulaGrammar::CONV_ODF
== meConv
)
454 /* $ */ t
[36] |= SC_COMPILER_C_ODF_NAME_MARKER
;
455 /* % */ t
[37] = SC_COMPILER_C_VALUE
;
456 /* & */ t
[38] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
457 /* ' */ t
[39] = SC_COMPILER_C_NAME_SEP
;
458 /* ( */ t
[40] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
459 /* ) */ t
[41] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
460 /* * */ t
[42] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
461 /* + */ t
[43] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_EXP
| SC_COMPILER_C_VALUE_SIGN
;
462 /* , */ t
[44] = SC_COMPILER_C_CHAR_VALUE
| SC_COMPILER_C_VALUE
;
463 /* - */ t
[45] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_EXP
| SC_COMPILER_C_VALUE_SIGN
;
464 /* . */ t
[46] = SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_VALUE
| SC_COMPILER_C_VALUE
| SC_COMPILER_C_IDENT
;
465 /* / */ t
[47] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
467 for (i
= 48; i
< 58; i
++)
468 /* 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
;
470 /* : */ t
[58] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD
;
471 /* ; */ t
[59] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
472 /* < */ t
[60] = SC_COMPILER_C_CHAR_BOOL
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
473 /* = */ t
[61] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_BOOL
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
474 /* > */ t
[62] = SC_COMPILER_C_CHAR_BOOL
| SC_COMPILER_C_BOOL
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
475 /* ? */ t
[63] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
;
478 for (i
= 65; i
< 91; i
++)
479 /* A-Z */ t
[i
] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_IDENT
| SC_COMPILER_C_IDENT
;
481 if (FormulaGrammar::CONV_ODF
== meConv
)
483 /* [ */ t
[91] = SC_COMPILER_C_ODF_LBRACKET
;
485 /* ] */ t
[93] = SC_COMPILER_C_ODF_RBRACKET
;
493 /* ^ */ t
[94] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
494 /* _ */ t
[95] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_IDENT
| SC_COMPILER_C_IDENT
;
497 for (i
= 97; i
< 123; i
++)
498 /* a-z */ t
[i
] = SC_COMPILER_C_CHAR_WORD
| SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_IDENT
| SC_COMPILER_C_IDENT
;
500 /* { */ t
[123] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
; // array open
501 /* | */ t
[124] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
; // array row sep (Should be OOo specific)
502 /* } */ t
[125] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
; // array close
503 /* ~ */ t
[126] = SC_COMPILER_C_CHAR
; // OOo specific
506 if( FormulaGrammar::CONV_XL_A1
== meConv
|| FormulaGrammar::CONV_XL_R1C1
== meConv
|| FormulaGrammar::CONV_XL_OOX
== meConv
)
508 /* */ t
[32] |= SC_COMPILER_C_WORD
;
509 /* ! */ t
[33] |= SC_COMPILER_C_IDENT
| SC_COMPILER_C_WORD
;
510 /* " */ t
[34] |= SC_COMPILER_C_WORD
;
511 /* # */ t
[35] &= (~SC_COMPILER_C_WORD_SEP
);
512 /* # */ t
[35] |= SC_COMPILER_C_WORD
;
513 /* % */ t
[37] |= SC_COMPILER_C_WORD
;
514 /* ' */ t
[39] |= SC_COMPILER_C_WORD
;
516 /* % */ t
[37] |= SC_COMPILER_C_WORD
;
517 /* & */ t
[38] |= SC_COMPILER_C_WORD
;
518 /* ' */ t
[39] |= SC_COMPILER_C_WORD
;
519 /* ( */ t
[40] |= SC_COMPILER_C_WORD
;
520 /* ) */ t
[41] |= SC_COMPILER_C_WORD
;
521 /* * */ t
[42] |= SC_COMPILER_C_WORD
;
522 /* + */ t
[43] |= SC_COMPILER_C_WORD
;
523 #if 0 /* this really needs to be locale specific. */
524 /* , */ t
[44] = SC_COMPILER_C_CHAR
| SC_COMPILER_C_WORD_SEP
| SC_COMPILER_C_VALUE_SEP
;
526 /* , */ t
[44] |= SC_COMPILER_C_WORD
;
528 /* - */ t
[45] |= SC_COMPILER_C_WORD
;
530 /* ; */ t
[59] |= SC_COMPILER_C_WORD
;
531 /* < */ t
[60] |= SC_COMPILER_C_WORD
;
532 /* = */ t
[61] |= SC_COMPILER_C_WORD
;
533 /* > */ t
[62] |= SC_COMPILER_C_WORD
;
534 /* ? */ // question really is not permitted in sheet name
535 /* @ */ t
[64] |= SC_COMPILER_C_WORD
;
536 /* [ */ t
[91] |= SC_COMPILER_C_WORD
;
537 /* ] */ t
[93] |= SC_COMPILER_C_WORD
;
538 /* { */ t
[123]|= SC_COMPILER_C_WORD
;
539 /* | */ t
[124]|= SC_COMPILER_C_WORD
;
540 /* } */ t
[125]|= SC_COMPILER_C_WORD
;
541 /* ~ */ t
[126]|= SC_COMPILER_C_WORD
;
543 if( FormulaGrammar::CONV_XL_R1C1
== meConv
)
545 /* - */ t
[45] |= SC_COMPILER_C_IDENT
;
546 /* [ */ t
[91] |= SC_COMPILER_C_IDENT
;
547 /* ] */ t
[93] |= SC_COMPILER_C_IDENT
;
549 if( FormulaGrammar::CONV_XL_OOX
== meConv
)
551 /* [ */ t
[91] |= SC_COMPILER_C_CHAR_IDENT
;
552 /* ] */ t
[93] |= SC_COMPILER_C_IDENT
;
557 //-----------------------------------------------------------------------------
559 static bool lcl_isValidQuotedText( const String
& rFormula
, xub_StrLen nSrcPos
, ParseResult
& rRes
)
561 // Tokens that start at ' can have anything in them until a final '
562 // but '' marks an escaped '
563 // We've earlier guaranteed that a string containing '' will be
565 if (rFormula
.GetChar(nSrcPos
) == '\'')
567 xub_StrLen nPos
= nSrcPos
+1;
568 while (nPos
< rFormula
.Len())
570 if (rFormula
.GetChar(nPos
) == '\'')
572 if ( (nPos
+1 == rFormula
.Len()) || (rFormula
.GetChar(nPos
+1) != '\'') )
574 rRes
.TokenType
= KParseType::SINGLE_QUOTE_NAME
;
575 rRes
.EndPos
= nPos
+1;
587 static bool lcl_parseExternalName(
588 const String
& rSymbol
,
591 const sal_Unicode cSep
,
592 const ScDocument
* pDoc
= NULL
,
593 const uno::Sequence
< const sheet::ExternalLinkInfo
> * pExternalLinks
= NULL
)
595 /* TODO: future versions will have to support sheet-local names too, thus
596 * return a possible sheet name as well. */
597 const sal_Unicode
* const pStart
= rSymbol
.GetBuffer();
598 const sal_Unicode
* p
= pStart
;
599 xub_StrLen nLen
= rSymbol
.Len();
600 sal_Unicode cPrev
= 0;
601 String aTmpFile
, aTmpName
;
603 bool bInName
= false;
606 // For XL use existing parser that resolves bracketed and quoted and
607 // indexed external document names.
609 String aStartTabName
, aEndTabName
;
611 p
= aRange
.Parse_XL_Header( p
, pDoc
, aTmpFile
, aStartTabName
,
612 aEndTabName
, nFlags
, true, pExternalLinks
);
613 if (!p
|| p
== pStart
)
615 i
= xub_StrLen(p
- pStart
);
618 for ( ; i
< nLen
; ++i
, ++p
)
623 if (c
== '.' || c
== cSep
)
628 // Move to the next chart and loop until the second single
632 for (xub_StrLen j
= i
; j
< nLen
; ++j
, ++p
)
639 // empty quote e.g. (=''!Name)
645 // two consecutive quotes equals a single
646 // quote in the file name.
656 if (cPrev
== '\'' && j
!= i
)
658 // this is not a quote but the previous one
659 // is. This ends the parsing of the quoted
672 // premature ending of the quoted segment.
678 // only the separator is allowed after the closing quote.
691 // A second separator ? Not a valid external name.
706 if (CharClass::isAsciiAlphaNumeric(c
))
711 // non-ASCII character is allowed.
720 // these special characters are allowed.
738 // No name found - most likely the symbol has no '!'s.
747 static String
lcl_makeExternalNameStr( const String
& rFile
, const String
& rName
,
748 const sal_Unicode cSep
, bool bODF
)
750 String
aFile( rFile
), aName( rName
), aEscQuote( RTL_CONSTASCII_USTRINGPARAM("''"));
751 aFile
.SearchAndReplaceAllAscii( "'", aEscQuote
);
753 aName
.SearchAndReplaceAllAscii( "'", aEscQuote
);
754 rtl::OUStringBuffer
aBuf( aFile
.Len() + aName
.Len() + 9);
756 aBuf
.append( sal_Unicode( '['));
757 aBuf
.append( sal_Unicode( '\''));
759 aBuf
.append( sal_Unicode( '\''));
762 aBuf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "$$'"));
765 aBuf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "']"));
766 return String( aBuf
.makeStringAndClear());
769 static bool lcl_getLastTabName( String
& rTabName2
, const String
& rTabName1
,
770 const vector
<String
>& rTabNames
, const ScComplexRefData
& rRef
)
772 SCsTAB nTabSpan
= rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
;
775 size_t nCount
= rTabNames
.size();
776 vector
<String
>::const_iterator itrBeg
= rTabNames
.begin(), itrEnd
= rTabNames
.end();
777 vector
<String
>::const_iterator itr
= ::std::find(itrBeg
, itrEnd
, rTabName1
);
778 if (itr
== rTabNames
.end())
780 rTabName2
= ScGlobal::GetRscString(STR_NO_REF_TABLE
);
784 size_t nDist
= ::std::distance(itrBeg
, itr
);
785 if (nDist
+ static_cast<size_t>(nTabSpan
) >= nCount
)
787 rTabName2
= ScGlobal::GetRscString(STR_NO_REF_TABLE
);
791 rTabName2
= rTabNames
[nDist
+nTabSpan
];
794 rTabName2
= rTabName1
;
799 struct Convention_A1
: public ScCompiler::Convention
801 Convention_A1( FormulaGrammar::AddressConvention eConv
) : ScCompiler::Convention( eConv
) { }
802 static void MakeColStr( rtl::OUStringBuffer
& rBuffer
, SCCOL nCol
);
803 static void MakeRowStr( rtl::OUStringBuffer
& rBuffer
, SCROW nRow
);
805 ParseResult
parseAnyToken( const String
& rFormula
,
807 const CharClass
* pCharClass
) const
810 if ( lcl_isValidQuotedText(rFormula
, nSrcPos
, aRet
) )
813 static const sal_Int32 nStartFlags
= KParseTokens::ANY_LETTER_OR_NUMBER
|
814 KParseTokens::ASC_UNDERSCORE
| KParseTokens::ASC_DOLLAR
;
815 static const sal_Int32 nContFlags
= nStartFlags
| KParseTokens::ASC_DOT
;
816 // '?' allowed in range names because of Xcl :-/
817 static const String
aAddAllowed(String::CreateFromAscii("?#"));
818 return pCharClass
->parseAnyToken( rFormula
,
819 nSrcPos
, nStartFlags
, aAddAllowed
, nContFlags
, aAddAllowed
);
823 void Convention_A1::MakeColStr( rtl::OUStringBuffer
& rBuffer
, SCCOL nCol
)
825 if ( !ValidCol( nCol
) )
826 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
828 ::ScColToAlpha( rBuffer
, nCol
);
831 void Convention_A1::MakeRowStr( rtl::OUStringBuffer
& rBuffer
, SCROW nRow
)
833 if ( !ValidRow(nRow
) )
834 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
836 rBuffer
.append(sal_Int32(nRow
+ 1));
839 //-----------------------------------------------------------------------------
841 struct ConventionOOO_A1
: public Convention_A1
843 ConventionOOO_A1() : Convention_A1 (FormulaGrammar::CONV_OOO
) { }
844 ConventionOOO_A1( FormulaGrammar::AddressConvention eConv
) : Convention_A1 (eConv
) { }
845 static String
MakeTabStr( const ScCompiler
& rComp
, SCTAB nTab
, String
& aDoc
)
848 if (!rComp
.GetDoc()->GetName( nTab
, aString
))
849 aString
= ScGlobal::GetRscString(STR_NO_REF_TABLE
);
852 if ( aString
.GetChar(0) == '\'' )
854 xub_StrLen nPos
= ScGlobal::FindUnquoted( aString
, SC_COMPILER_FILE_TAB_SEP
);
855 if (nPos
!= STRING_NOTFOUND
&& nPos
> 0 && aString
.GetChar(nPos
-1) == '\'')
857 aDoc
= aString
.Copy( 0, nPos
+ 1 );
858 aString
.Erase( 0, nPos
+ 1 );
859 aDoc
= INetURLObject::decode( aDoc
, INET_HEX_ESCAPE
,
860 INetURLObject::DECODE_UNAMBIGUOUS
);
867 ScCompiler::CheckTabQuotes( aString
, FormulaGrammar::CONV_OOO
);
873 void MakeRefStrImpl( rtl::OUStringBuffer
& rBuffer
,
874 const ScCompiler
& rComp
,
875 const ScComplexRefData
& rRef
,
880 rBuffer
.append(sal_Unicode('['));
881 ScComplexRefData
aRef( rRef
);
882 // In case absolute/relative positions weren't separately available:
883 // transform relative to absolute!
884 // AdjustReference( aRef.Ref1 );
886 // AdjustReference( aRef.Ref2 );
887 aRef
.Ref1
.CalcAbsIfRel( rComp
.GetPos() );
889 aRef
.Ref2
.CalcAbsIfRel( rComp
.GetPos() );
890 if( aRef
.Ref1
.IsFlag3D() )
892 if (aRef
.Ref1
.IsTabDeleted())
894 if (!aRef
.Ref1
.IsTabRel())
895 rBuffer
.append(sal_Unicode('$'));
896 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
897 rBuffer
.append(sal_Unicode('.'));
902 String
aRefStr( MakeTabStr( rComp
, aRef
.Ref1
.nTab
, aDoc
) );
903 rBuffer
.append(aDoc
);
904 if (!aRef
.Ref1
.IsTabRel()) rBuffer
.append(sal_Unicode('$'));
905 rBuffer
.append(aRefStr
);
909 rBuffer
.append(sal_Unicode('.'));
910 if (!aRef
.Ref1
.IsColRel())
911 rBuffer
.append(sal_Unicode('$'));
912 if ( aRef
.Ref1
.IsColDeleted() )
913 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
915 MakeColStr(rBuffer
, aRef
.Ref1
.nCol
);
916 if (!aRef
.Ref1
.IsRowRel())
917 rBuffer
.append(sal_Unicode('$'));
918 if ( aRef
.Ref1
.IsRowDeleted() )
919 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
921 MakeRowStr( rBuffer
, aRef
.Ref1
.nRow
);
924 rBuffer
.append(sal_Unicode(':'));
925 if (aRef
.Ref2
.IsFlag3D() || aRef
.Ref2
.nTab
!= aRef
.Ref1
.nTab
)
927 if (aRef
.Ref2
.IsTabDeleted())
929 if (!aRef
.Ref2
.IsTabRel())
930 rBuffer
.append(sal_Unicode('$'));
931 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
932 rBuffer
.append(sal_Unicode('.'));
937 String
aRefStr( MakeTabStr( rComp
, aRef
.Ref2
.nTab
, aDoc
) );
938 rBuffer
.append(aDoc
);
939 if (!aRef
.Ref2
.IsTabRel()) rBuffer
.append(sal_Unicode('$'));
940 rBuffer
.append(aRefStr
);
944 rBuffer
.append(sal_Unicode('.'));
945 if (!aRef
.Ref2
.IsColRel())
946 rBuffer
.append(sal_Unicode('$'));
947 if ( aRef
.Ref2
.IsColDeleted() )
948 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
950 MakeColStr( rBuffer
, aRef
.Ref2
.nCol
);
951 if (!aRef
.Ref2
.IsRowRel())
952 rBuffer
.append(sal_Unicode('$'));
953 if ( aRef
.Ref2
.IsRowDeleted() )
954 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
956 MakeRowStr( rBuffer
, aRef
.Ref2
.nRow
);
959 rBuffer
.append(sal_Unicode(']'));
962 void MakeRefStr( rtl::OUStringBuffer
& rBuffer
,
963 const ScCompiler
& rComp
,
964 const ScComplexRefData
& rRef
,
965 BOOL bSingleRef
) const
967 MakeRefStrImpl( rBuffer
, rComp
, rRef
, bSingleRef
, false);
970 virtual sal_Unicode
getSpecialSymbol( SpecialSymbolType eSymType
) const
974 case ScCompiler::Convention::ABS_SHEET_PREFIX
:
976 case ScCompiler::Convention::SHEET_SEPARATOR
:
980 return sal_Unicode(0);
983 virtual bool parseExternalName( const String
& rSymbol
, String
& rFile
, String
& rName
,
984 const ScDocument
* pDoc
,
985 const ::com::sun::star::uno::Sequence
<
986 const ::com::sun::star::sheet::ExternalLinkInfo
> * pExternalLinks
) const
988 return lcl_parseExternalName(rSymbol
, rFile
, rName
, sal_Unicode('#'), pDoc
, pExternalLinks
);
991 virtual String
makeExternalNameStr( const String
& rFile
, const String
& rName
) const
993 return lcl_makeExternalNameStr( rFile
, rName
, sal_Unicode('#'), false);
996 bool makeExternalSingleRefStr( ::rtl::OUStringBuffer
& rBuffer
, sal_uInt16 nFileId
,
997 const String
& rTabName
, const ScSingleRefData
& rRef
,
998 ScExternalRefManager
* pRefMgr
, bool bDisplayTabName
) const
1000 if (bDisplayTabName
)
1003 const String
* p
= pRefMgr
->getExternalFileName(nFileId
);
1005 aFile
= INetURLObject::decode(*p
, INET_HEX_ESCAPE
, INetURLObject::DECODE_UNAMBIGUOUS
);
1006 aFile
.SearchAndReplaceAllAscii("'", String::CreateFromAscii("''"));
1008 rBuffer
.append(sal_Unicode('\''));
1009 rBuffer
.append(aFile
);
1010 rBuffer
.append(sal_Unicode('\''));
1011 rBuffer
.append(sal_Unicode('#'));
1013 if (!rRef
.IsTabRel())
1014 rBuffer
.append(sal_Unicode('$'));
1015 ScRangeStringConverter::AppendTableName(rBuffer
, rTabName
);
1017 rBuffer
.append(sal_Unicode('.'));
1020 if (!rRef
.IsColRel())
1021 rBuffer
.append(sal_Unicode('$'));
1022 MakeColStr( rBuffer
, rRef
.nCol
);
1023 if (!rRef
.IsRowRel())
1024 rBuffer
.append(sal_Unicode('$'));
1025 MakeRowStr( rBuffer
, rRef
.nRow
);
1030 void makeExternalRefStrImpl( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1031 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1032 ScExternalRefManager
* pRefMgr
, bool bODF
) const
1034 ScSingleRefData
aRef(rRef
);
1035 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1038 rBuffer
.append( sal_Unicode('['));
1039 makeExternalSingleRefStr(rBuffer
, nFileId
, rTabName
, aRef
, pRefMgr
, true);
1041 rBuffer
.append( sal_Unicode(']'));
1044 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1045 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1046 ScExternalRefManager
* pRefMgr
) const
1048 makeExternalRefStrImpl( rBuffer
, rCompiler
, nFileId
, rTabName
, rRef
, pRefMgr
, false);
1051 void makeExternalRefStrImpl( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1052 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1053 ScExternalRefManager
* pRefMgr
, bool bODF
) const
1055 ScComplexRefData
aRef(rRef
);
1056 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1059 rBuffer
.append( sal_Unicode('['));
1060 // Ensure that there's always a closing bracket, no premature returns.
1063 if (!makeExternalSingleRefStr(rBuffer
, nFileId
, rTabName
, aRef
.Ref1
, pRefMgr
, true))
1066 rBuffer
.append(sal_Unicode(':'));
1068 String aLastTabName
;
1069 bool bDisplayTabName
= (aRef
.Ref1
.nTab
!= aRef
.Ref2
.nTab
);
1070 if (bDisplayTabName
)
1072 // Get the name of the last table.
1073 vector
<String
> aTabNames
;
1074 pRefMgr
->getAllCachedTableNames(nFileId
, aTabNames
);
1075 if (aTabNames
.empty())
1077 DBG_ERROR1( "ConventionOOO_A1::makeExternalRefStrImpl: no sheet names for document ID %s", nFileId
);
1080 if (!lcl_getLastTabName(aLastTabName
, rTabName
, aTabNames
, aRef
))
1082 DBG_ERROR( "ConventionOOO_A1::makeExternalRefStrImpl: sheet name not found");
1083 // aLastTabName contains #REF!, proceed.
1087 rBuffer
.append( sal_Unicode('.')); // need at least the sheet separator in ODF
1088 makeExternalSingleRefStr( rBuffer
, nFileId
, aLastTabName
,
1089 aRef
.Ref2
, pRefMgr
, bDisplayTabName
);
1092 rBuffer
.append( sal_Unicode(']'));
1095 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1096 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1097 ScExternalRefManager
* pRefMgr
) const
1099 makeExternalRefStrImpl( rBuffer
, rCompiler
, nFileId
, rTabName
, rRef
, pRefMgr
, false);
1104 static const ConventionOOO_A1 ConvOOO_A1
;
1105 const ScCompiler::Convention
* const ScCompiler::pConvOOO_A1
= &ConvOOO_A1
;
1107 //-----------------------------------------------------------------------------
1109 struct ConventionOOO_A1_ODF
: public ConventionOOO_A1
1111 ConventionOOO_A1_ODF() : ConventionOOO_A1 (FormulaGrammar::CONV_ODF
) { }
1112 void MakeRefStr( rtl::OUStringBuffer
& rBuffer
,
1113 const ScCompiler
& rComp
,
1114 const ScComplexRefData
& rRef
,
1115 BOOL bSingleRef
) const
1117 MakeRefStrImpl( rBuffer
, rComp
, rRef
, bSingleRef
, true);
1120 virtual String
makeExternalNameStr( const String
& rFile
, const String
& rName
) const
1122 return lcl_makeExternalNameStr( rFile
, rName
, sal_Unicode('#'), true);
1125 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1126 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1127 ScExternalRefManager
* pRefMgr
) const
1129 makeExternalRefStrImpl( rBuffer
, rCompiler
, nFileId
, rTabName
, rRef
, pRefMgr
, true);
1132 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1133 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1134 ScExternalRefManager
* pRefMgr
) const
1136 makeExternalRefStrImpl( rBuffer
, rCompiler
, nFileId
, rTabName
, rRef
, pRefMgr
, true);
1140 static const ConventionOOO_A1_ODF ConvOOO_A1_ODF
;
1141 const ScCompiler::Convention
* const ScCompiler::pConvOOO_A1_ODF
= &ConvOOO_A1_ODF
;
1143 //-----------------------------------------------------------------------------
1147 static bool GetDocAndTab( const ScCompiler
& rComp
,
1148 const ScSingleRefData
& rRef
,
1152 bool bHasDoc
= false;
1155 if (rRef
.IsTabDeleted() ||
1156 !rComp
.GetDoc()->GetName( rRef
.nTab
, rTabName
))
1158 rTabName
= ScGlobal::GetRscString( STR_NO_REF_TABLE
);
1162 // Cheesy hack to unparse the OOO style "'Doc'#Tab"
1163 if ( rTabName
.GetChar(0) == '\'' )
1165 xub_StrLen nPos
= ScGlobal::FindUnquoted( rTabName
, SC_COMPILER_FILE_TAB_SEP
);
1166 if (nPos
!= STRING_NOTFOUND
&& nPos
> 0 && rTabName
.GetChar(nPos
-1) == '\'')
1168 rDocName
= rTabName
.Copy( 0, nPos
);
1169 // TODO : More research into how XL escapes the doc path
1170 rDocName
= INetURLObject::decode( rDocName
, INET_HEX_ESCAPE
,
1171 INetURLObject::DECODE_UNAMBIGUOUS
);
1172 rTabName
.Erase( 0, nPos
+ 1 );
1177 // XL uses the same sheet name quoting conventions in both modes
1178 // it is safe to use A1 here
1179 ScCompiler::CheckTabQuotes( rTabName
, FormulaGrammar::CONV_XL_A1
);
1183 static void MakeDocStr( rtl::OUStringBuffer
& rBuf
,
1184 const ScCompiler
& rComp
,
1185 const ScComplexRefData
& rRef
,
1188 if( rRef
.Ref1
.IsFlag3D() )
1190 String aStartTabName
, aStartDocName
, aEndTabName
, aEndDocName
;
1191 bool bStartHasDoc
= false, bEndHasDoc
= false;
1193 bStartHasDoc
= GetDocAndTab( rComp
, rRef
.Ref1
,
1194 aStartDocName
, aStartTabName
);
1196 if( !bSingleRef
&& rRef
.Ref2
.IsFlag3D() )
1198 bEndHasDoc
= GetDocAndTab( rComp
, rRef
.Ref2
,
1199 aEndDocName
, aEndTabName
);
1202 bEndHasDoc
= bStartHasDoc
;
1206 // A ref across multipled workbooks ?
1210 rBuf
.append( sal_Unicode( '[' ) );
1211 rBuf
.append( aStartDocName
);
1212 rBuf
.append( sal_Unicode( ']' ) );
1215 rBuf
.append( aStartTabName
);
1216 if( !bSingleRef
&& rRef
.Ref2
.IsFlag3D() && aStartTabName
!= aEndTabName
)
1218 rBuf
.append( sal_Unicode( ':' ) );
1219 rBuf
.append( aEndTabName
);
1222 rBuf
.append( sal_Unicode( '!' ) );
1226 static sal_Unicode
getSpecialSymbol( ScCompiler::Convention::SpecialSymbolType eSymType
)
1230 case ScCompiler::Convention::ABS_SHEET_PREFIX
:
1231 return sal_Unicode(0);
1232 case ScCompiler::Convention::SHEET_SEPARATOR
:
1235 return sal_Unicode(0);
1238 static bool parseExternalName( const String
& rSymbol
, String
& rFile
, String
& rName
,
1239 const ScDocument
* pDoc
,
1240 const ::com::sun::star::uno::Sequence
<
1241 const ::com::sun::star::sheet::ExternalLinkInfo
> * pExternalLinks
)
1243 return lcl_parseExternalName( rSymbol
, rFile
, rName
, sal_Unicode('!'), pDoc
, pExternalLinks
);
1246 static String
makeExternalNameStr( const String
& rFile
, const String
& rName
)
1248 return lcl_makeExternalNameStr( rFile
, rName
, sal_Unicode('!'), false);
1251 static void makeExternalDocStr( ::rtl::OUStringBuffer
& rBuffer
, const String
& rFullName
)
1253 // Format that is easier to deal with inside OOo, because we use file
1254 // URL, and all characetrs are allowed. Check if it makes sense to do
1255 // it the way Gnumeric does it. Gnumeric doesn't use the URL form
1256 // and allows relative file path.
1258 // ['file:///path/to/source/filename.xls']
1260 rBuffer
.append(sal_Unicode('['));
1261 rBuffer
.append(sal_Unicode('\''));
1262 String aFullName
= INetURLObject::decode(rFullName
, INET_HEX_ESCAPE
, INetURLObject::DECODE_UNAMBIGUOUS
);
1263 const sal_Unicode
* pBuf
= aFullName
.GetBuffer();
1264 xub_StrLen nLen
= aFullName
.Len();
1265 for (xub_StrLen i
= 0; i
< nLen
; ++i
)
1267 const sal_Unicode c
= pBuf
[i
];
1268 if (c
== sal_Unicode('\''))
1272 rBuffer
.append(sal_Unicode('\''));
1273 rBuffer
.append(sal_Unicode(']'));
1276 static void makeExternalTabNameRange( ::rtl::OUStringBuffer
& rBuf
, const String
& rTabName
,
1277 const vector
<String
>& rTabNames
,
1278 const ScComplexRefData
& rRef
)
1280 String aLastTabName
;
1281 if (!lcl_getLastTabName(aLastTabName
, rTabName
, rTabNames
, rRef
))
1283 ScRangeStringConverter::AppendTableName(rBuf
, aLastTabName
);
1287 ScRangeStringConverter::AppendTableName(rBuf
, rTabName
);
1288 if (rTabName
!= aLastTabName
)
1290 rBuf
.append(sal_Unicode(':'));
1291 ScRangeStringConverter::AppendTableName(rBuf
, rTabName
);
1295 static void parseExternalDocName( const String
& rFormula
, xub_StrLen
& rSrcPos
)
1297 xub_StrLen nLen
= rFormula
.Len();
1298 const sal_Unicode
* p
= rFormula
.GetBuffer();
1299 sal_Unicode cPrev
= 0;
1300 for (xub_StrLen i
= rSrcPos
; i
< nLen
; ++i
)
1302 sal_Unicode c
= p
[i
];
1305 // first character must be '['.
1309 else if (i
== rSrcPos
+ 1)
1311 // second character must be a single quote.
1318 // two successive single quote is treated as a single
1326 // valid source document path found. Increment the
1327 // current position to skip the source path.
1329 if (rSrcPos
>= nLen
)
1338 // any other character
1339 if (i
> rSrcPos
+ 2 && cPrev
== '\'')
1340 // unless it's the 3rd character, a normal character
1341 // following immediately a single quote is invalid.
1349 struct ConventionXL_A1
: public Convention_A1
, public ConventionXL
1351 ConventionXL_A1() : Convention_A1( FormulaGrammar::CONV_XL_A1
) { }
1352 ConventionXL_A1( FormulaGrammar::AddressConvention eConv
) : Convention_A1( eConv
) { }
1354 void makeSingleCellStr( ::rtl::OUStringBuffer
& rBuf
, const ScSingleRefData
& rRef
) const
1356 if (!rRef
.IsColRel())
1357 rBuf
.append(sal_Unicode('$'));
1358 MakeColStr(rBuf
, rRef
.nCol
);
1359 if (!rRef
.IsRowRel())
1360 rBuf
.append(sal_Unicode('$'));
1361 MakeRowStr(rBuf
, rRef
.nRow
);
1364 void MakeRefStr( rtl::OUStringBuffer
& rBuf
,
1365 const ScCompiler
& rComp
,
1366 const ScComplexRefData
& rRef
,
1367 BOOL bSingleRef
) const
1369 ScComplexRefData
aRef( rRef
);
1371 // Play fast and loose with invalid refs. There is not much point in producing
1372 // Foo!A1:#REF! versus #REF! at this point
1373 aRef
.Ref1
.CalcAbsIfRel( rComp
.GetPos() );
1375 MakeDocStr( rBuf
, rComp
, aRef
, bSingleRef
);
1377 if( aRef
.Ref1
.IsColDeleted() || aRef
.Ref1
.IsRowDeleted() )
1379 rBuf
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1385 aRef
.Ref2
.CalcAbsIfRel( rComp
.GetPos() );
1386 if( aRef
.Ref2
.IsColDeleted() || aRef
.Ref2
.IsRowDeleted() )
1388 rBuf
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1392 if( aRef
.Ref1
.nCol
== 0 && aRef
.Ref2
.nCol
>= MAXCOL
)
1394 if (!aRef
.Ref1
.IsRowRel())
1395 rBuf
.append(sal_Unicode( '$' ));
1396 MakeRowStr( rBuf
, aRef
.Ref1
.nRow
);
1397 rBuf
.append(sal_Unicode( ':' ));
1398 if (!aRef
.Ref2
.IsRowRel())
1399 rBuf
.append(sal_Unicode( '$' ));
1400 MakeRowStr( rBuf
, aRef
.Ref2
.nRow
);
1404 if( aRef
.Ref1
.nRow
== 0 && aRef
.Ref2
.nRow
>= MAXROW
)
1406 if (!aRef
.Ref1
.IsColRel())
1407 rBuf
.append(sal_Unicode( '$' ));
1408 MakeColStr(rBuf
, aRef
.Ref1
.nCol
);
1409 rBuf
.append(sal_Unicode( ':' ));
1410 if (!aRef
.Ref2
.IsColRel())
1411 rBuf
.append(sal_Unicode( '$' ));
1412 MakeColStr(rBuf
, aRef
.Ref2
.nCol
);
1417 makeSingleCellStr(rBuf
, aRef
.Ref1
);
1420 rBuf
.append(sal_Unicode( ':' ));
1421 makeSingleCellStr(rBuf
, aRef
.Ref2
);
1425 virtual ParseResult
parseAnyToken( const String
& rFormula
,
1427 const CharClass
* pCharClass
) const
1430 if ( lcl_isValidQuotedText(rFormula
, nSrcPos
, aRet
) )
1433 static const sal_Int32 nStartFlags
= KParseTokens::ANY_LETTER_OR_NUMBER
|
1434 KParseTokens::ASC_UNDERSCORE
| KParseTokens::ASC_DOLLAR
;
1435 static const sal_Int32 nContFlags
= nStartFlags
| KParseTokens::ASC_DOT
;
1436 // '?' allowed in range names
1437 static const String aAddAllowed
= String::CreateFromAscii("?!");
1438 return pCharClass
->parseAnyToken( rFormula
,
1439 nSrcPos
, nStartFlags
, aAddAllowed
, nContFlags
, aAddAllowed
);
1442 virtual sal_Unicode
getSpecialSymbol( SpecialSymbolType eSymType
) const
1444 return ConventionXL::getSpecialSymbol(eSymType
);
1447 virtual bool parseExternalName( const String
& rSymbol
, String
& rFile
, String
& rName
,
1448 const ScDocument
* pDoc
,
1449 const ::com::sun::star::uno::Sequence
<
1450 const ::com::sun::star::sheet::ExternalLinkInfo
> * pExternalLinks
) const
1452 return ConventionXL::parseExternalName( rSymbol
, rFile
, rName
, pDoc
, pExternalLinks
);
1455 virtual String
makeExternalNameStr( const String
& rFile
, const String
& rName
) const
1457 return ConventionXL::makeExternalNameStr(rFile
, rName
);
1460 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1461 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1462 ScExternalRefManager
* pRefMgr
) const
1464 // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
1465 // This is a little different from the format Excel uses, as Excel
1466 // puts [] only around the file name. But we need to enclose the
1467 // whole file path with [] because the file name can contain any
1470 const String
* pFullName
= pRefMgr
->getExternalFileName(nFileId
);
1474 ScSingleRefData
aRef(rRef
);
1475 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1477 ConventionXL::makeExternalDocStr(rBuffer
, *pFullName
);
1478 ScRangeStringConverter::AppendTableName(rBuffer
, rTabName
);
1479 rBuffer
.append(sal_Unicode('!'));
1481 makeSingleCellStr(rBuffer
, aRef
);
1484 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1485 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1486 ScExternalRefManager
* pRefMgr
) const
1488 const String
* pFullName
= pRefMgr
->getExternalFileName(nFileId
);
1492 vector
<String
> aTabNames
;
1493 pRefMgr
->getAllCachedTableNames(nFileId
, aTabNames
);
1494 if (aTabNames
.empty())
1497 ScComplexRefData
aRef(rRef
);
1498 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1500 ConventionXL::makeExternalDocStr(rBuffer
, *pFullName
);
1501 ConventionXL::makeExternalTabNameRange(rBuffer
, rTabName
, aTabNames
, aRef
);
1502 rBuffer
.append(sal_Unicode('!'));
1504 makeSingleCellStr(rBuffer
, aRef
.Ref1
);
1505 if (aRef
.Ref1
!= aRef
.Ref2
)
1507 rBuffer
.append(sal_Unicode(':'));
1508 makeSingleCellStr(rBuffer
, aRef
.Ref2
);
1513 static const ConventionXL_A1 ConvXL_A1
;
1514 const ScCompiler::Convention
* const ScCompiler::pConvXL_A1
= &ConvXL_A1
;
1517 struct ConventionXL_OOX
: public ConventionXL_A1
1519 ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX
) { }
1522 static const ConventionXL_OOX ConvXL_OOX
;
1523 const ScCompiler::Convention
* const ScCompiler::pConvXL_OOX
= &ConvXL_OOX
;
1526 //-----------------------------------------------------------------------------
1529 r1c1_add_col( rtl::OUStringBuffer
&rBuf
, const ScSingleRefData
& rRef
)
1531 rBuf
.append( sal_Unicode( 'C' ) );
1532 if( rRef
.IsColRel() )
1534 if (rRef
.nRelCol
!= 0)
1536 rBuf
.append( sal_Unicode( '[' ) );
1537 rBuf
.append( String::CreateFromInt32( rRef
.nRelCol
) );
1538 rBuf
.append( sal_Unicode( ']' ) );
1542 rBuf
.append( String::CreateFromInt32( rRef
.nCol
+ 1 ) );
1545 r1c1_add_row( rtl::OUStringBuffer
&rBuf
, const ScSingleRefData
& rRef
)
1547 rBuf
.append( sal_Unicode( 'R' ) );
1548 if( rRef
.IsRowRel() )
1550 if (rRef
.nRelRow
!= 0)
1552 rBuf
.append( sal_Unicode( '[' ) );
1553 rBuf
.append( String::CreateFromInt32( rRef
.nRelRow
) );
1554 rBuf
.append( sal_Unicode( ']' ) );
1558 rBuf
.append( String::CreateFromInt32( rRef
.nRow
+ 1 ) );
1561 struct ConventionXL_R1C1
: public ScCompiler::Convention
, public ConventionXL
1563 ConventionXL_R1C1() : ScCompiler::Convention( FormulaGrammar::CONV_XL_R1C1
) { }
1564 void MakeRefStr( rtl::OUStringBuffer
& rBuf
,
1565 const ScCompiler
& rComp
,
1566 const ScComplexRefData
& rRef
,
1567 BOOL bSingleRef
) const
1569 ScComplexRefData
aRef( rRef
);
1571 MakeDocStr( rBuf
, rComp
, aRef
, bSingleRef
);
1573 // Play fast and loose with invalid refs. There is not much point in producing
1574 // Foo!A1:#REF! versus #REF! at this point
1575 aRef
.Ref1
.CalcAbsIfRel( rComp
.GetPos() );
1576 if( aRef
.Ref1
.IsColDeleted() || aRef
.Ref1
.IsRowDeleted() )
1578 rBuf
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1584 aRef
.Ref2
.CalcAbsIfRel( rComp
.GetPos() );
1585 if( aRef
.Ref2
.IsColDeleted() || aRef
.Ref2
.IsRowDeleted() )
1587 rBuf
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1591 if( aRef
.Ref1
.nCol
== 0 && aRef
.Ref2
.nCol
>= MAXCOL
)
1593 r1c1_add_row( rBuf
, rRef
.Ref1
);
1594 if( rRef
.Ref1
.nRow
!= rRef
.Ref2
.nRow
||
1595 rRef
.Ref1
.IsRowRel() != rRef
.Ref2
.IsRowRel() ) {
1596 rBuf
.append (sal_Unicode ( ':' ) );
1597 r1c1_add_row( rBuf
, rRef
.Ref2
);
1603 if( aRef
.Ref1
.nRow
== 0 && aRef
.Ref2
.nRow
>= MAXROW
)
1605 r1c1_add_col( rBuf
, rRef
.Ref1
);
1606 if( rRef
.Ref1
.nCol
!= rRef
.Ref2
.nCol
||
1607 rRef
.Ref1
.IsColRel() != rRef
.Ref2
.IsColRel() )
1609 rBuf
.append (sal_Unicode ( ':' ) );
1610 r1c1_add_col( rBuf
, rRef
.Ref2
);
1616 r1c1_add_row( rBuf
, rRef
.Ref1
);
1617 r1c1_add_col( rBuf
, rRef
.Ref1
);
1620 rBuf
.append (sal_Unicode ( ':' ) );
1621 r1c1_add_row( rBuf
, rRef
.Ref2
);
1622 r1c1_add_col( rBuf
, rRef
.Ref2
);
1626 ParseResult
parseAnyToken( const String
& rFormula
,
1628 const CharClass
* pCharClass
) const
1630 ConventionXL::parseExternalDocName(rFormula
, nSrcPos
);
1633 if ( lcl_isValidQuotedText(rFormula
, nSrcPos
, aRet
) )
1636 static const sal_Int32 nStartFlags
= KParseTokens::ANY_LETTER_OR_NUMBER
|
1637 KParseTokens::ASC_UNDERSCORE
;
1638 static const sal_Int32 nContFlags
= nStartFlags
| KParseTokens::ASC_DOT
;
1639 // '?' allowed in range names
1640 static const String aAddAllowed
= String::CreateFromAscii( "?-[]!" );
1642 return pCharClass
->parseAnyToken( rFormula
,
1643 nSrcPos
, nStartFlags
, aAddAllowed
, nContFlags
, aAddAllowed
);
1646 virtual sal_Unicode
getSpecialSymbol( SpecialSymbolType eSymType
) const
1648 return ConventionXL::getSpecialSymbol(eSymType
);
1651 virtual bool parseExternalName( const String
& rSymbol
, String
& rFile
, String
& rName
,
1652 const ScDocument
* pDoc
,
1653 const ::com::sun::star::uno::Sequence
<
1654 const ::com::sun::star::sheet::ExternalLinkInfo
> * pExternalLinks
) const
1656 return ConventionXL::parseExternalName( rSymbol
, rFile
, rName
, pDoc
, pExternalLinks
);
1659 virtual String
makeExternalNameStr( const String
& rFile
, const String
& rName
) const
1661 return ConventionXL::makeExternalNameStr(rFile
, rName
);
1664 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1665 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
1666 ScExternalRefManager
* pRefMgr
) const
1668 // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
1669 // This is a little different from the format Excel uses, as Excel
1670 // puts [] only around the file name. But we need to enclose the
1671 // whole file path with [] because the file name can contain any
1674 const String
* pFullName
= pRefMgr
->getExternalFileName(nFileId
);
1678 ScSingleRefData
aRef(rRef
);
1679 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1681 ConventionXL::makeExternalDocStr(rBuffer
, *pFullName
);
1682 ScRangeStringConverter::AppendTableName(rBuffer
, rTabName
);
1683 rBuffer
.append(sal_Unicode('!'));
1685 r1c1_add_row(rBuffer
, aRef
);
1686 r1c1_add_col(rBuffer
, aRef
);
1689 virtual void makeExternalRefStr( ::rtl::OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
1690 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
1691 ScExternalRefManager
* pRefMgr
) const
1693 const String
* pFullName
= pRefMgr
->getExternalFileName(nFileId
);
1697 vector
<String
> aTabNames
;
1698 pRefMgr
->getAllCachedTableNames(nFileId
, aTabNames
);
1699 if (aTabNames
.empty())
1702 ScComplexRefData
aRef(rRef
);
1703 aRef
.CalcAbsIfRel(rCompiler
.GetPos());
1705 ConventionXL::makeExternalDocStr(rBuffer
, *pFullName
);
1706 ConventionXL::makeExternalTabNameRange(rBuffer
, rTabName
, aTabNames
, aRef
);
1707 rBuffer
.append(sal_Unicode('!'));
1709 if (aRef
.Ref2
.IsColDeleted() || aRef
.Ref2
.IsRowDeleted())
1711 rBuffer
.append(ScGlobal::GetRscString(STR_NO_REF_TABLE
));
1715 if (aRef
.Ref1
.nCol
== 0 && aRef
.Ref2
.nCol
>= MAXCOL
)
1717 r1c1_add_row(rBuffer
, rRef
.Ref1
);
1718 if (rRef
.Ref1
.nRow
!= rRef
.Ref2
.nRow
|| rRef
.Ref1
.IsRowRel() != rRef
.Ref2
.IsRowRel())
1720 rBuffer
.append (sal_Unicode(':'));
1721 r1c1_add_row(rBuffer
, rRef
.Ref2
);
1726 if (aRef
.Ref1
.nRow
== 0 && aRef
.Ref2
.nRow
>= MAXROW
)
1728 r1c1_add_col(rBuffer
, aRef
.Ref1
);
1729 if (aRef
.Ref1
.nCol
!= aRef
.Ref2
.nCol
|| aRef
.Ref1
.IsColRel() != aRef
.Ref2
.IsColRel())
1731 rBuffer
.append (sal_Unicode(':'));
1732 r1c1_add_col(rBuffer
, aRef
.Ref2
);
1737 r1c1_add_row(rBuffer
, aRef
.Ref1
);
1738 r1c1_add_col(rBuffer
, aRef
.Ref1
);
1739 rBuffer
.append (sal_Unicode (':'));
1740 r1c1_add_row(rBuffer
, aRef
.Ref2
);
1741 r1c1_add_col(rBuffer
, aRef
.Ref2
);
1745 static const ConventionXL_R1C1 ConvXL_R1C1
;
1746 const ScCompiler::Convention
* const ScCompiler::pConvXL_R1C1
= &ConvXL_R1C1
;
1748 //-----------------------------------------------------------------------------
1749 ScCompiler::ScCompiler( ScDocument
* pDocument
, const ScAddress
& rPos
,ScTokenArray
& rArr
)
1750 : FormulaCompiler(rArr
),
1753 pCharClass( ScGlobal::pCharClass
),
1754 mnPredetectedReference(0),
1755 mnRangeOpPosInSymbol(-1),
1756 pConv( pConvOOO_A1
),
1757 mbCloseBrackets( true ),
1758 mbExtendedErrorDetection( false ),
1761 nMaxTab
= pDoc
? pDoc
->GetTableCount() - 1 : 0;
1764 ScCompiler::ScCompiler( ScDocument
* pDocument
, const ScAddress
& rPos
)
1768 pCharClass( ScGlobal::pCharClass
),
1769 mnPredetectedReference(0),
1770 mnRangeOpPosInSymbol(-1),
1771 pConv( pConvOOO_A1
),
1772 mbCloseBrackets( true ),
1773 mbExtendedErrorDetection( false ),
1776 nMaxTab
= pDoc
? pDoc
->GetTableCount() - 1 : 0;
1779 void ScCompiler::CheckTabQuotes( String
& rString
,
1780 const FormulaGrammar::AddressConvention eConv
)
1782 using namespace ::com::sun::star::i18n
;
1783 sal_Int32 nStartFlags
= KParseTokens::ANY_LETTER_OR_NUMBER
| KParseTokens::ASC_UNDERSCORE
;
1784 sal_Int32 nContFlags
= nStartFlags
;
1785 ParseResult aRes
= ScGlobal::pCharClass
->parsePredefinedToken(
1786 KParseType::IDENTNAME
, rString
, 0, nStartFlags
, EMPTY_STRING
, nContFlags
, EMPTY_STRING
);
1787 bool bNeedsQuote
= !((aRes
.TokenType
& KParseType::IDENTNAME
) && aRes
.EndPos
== rString
.Len());
1792 case FormulaGrammar::CONV_UNSPECIFIED
:
1794 case FormulaGrammar::CONV_OOO
:
1795 case FormulaGrammar::CONV_XL_A1
:
1796 case FormulaGrammar::CONV_XL_R1C1
:
1797 case FormulaGrammar::CONV_XL_OOX
:
1800 static const String one_quote
= static_cast<sal_Unicode
>( '\'' );
1801 static const String two_quote
= String::CreateFromAscii( "''" );
1802 // escape embedded quotes
1803 rString
.SearchAndReplaceAll( one_quote
, two_quote
);
1808 if ( !bNeedsQuote
&& CharClass::isAsciiNumeric( rString
) )
1810 // Prevent any possible confusion resulting from pure numeric sheet names.
1816 rString
.Insert( '\'', 0 );
1821 //---------------------------------------------------------------------------
1823 void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv
)
1826 case FormulaGrammar::CONV_UNSPECIFIED
:
1829 case FormulaGrammar::CONV_OOO
: SetRefConvention( pConvOOO_A1
); break;
1830 case FormulaGrammar::CONV_ODF
: SetRefConvention( pConvOOO_A1_ODF
); break;
1831 case FormulaGrammar::CONV_XL_A1
: SetRefConvention( pConvXL_A1
); break;
1832 case FormulaGrammar::CONV_XL_R1C1
: SetRefConvention( pConvXL_R1C1
); break;
1833 case FormulaGrammar::CONV_XL_OOX
: SetRefConvention( pConvXL_OOX
); break;
1837 void ScCompiler::SetRefConvention( const ScCompiler::Convention
*pConvP
)
1840 meGrammar
= FormulaGrammar::mergeToGrammar( meGrammar
, pConv
->meConv
);
1841 DBG_ASSERT( FormulaGrammar::isSupported( meGrammar
),
1842 "ScCompiler::SetRefConvention: unsupported grammar resulting");
1845 void ScCompiler::SetError(USHORT nError
)
1847 if( !pArr
->GetCodeError() )
1848 pArr
->SetCodeError( nError
);
1852 sal_Unicode
* lcl_UnicodeStrNCpy( sal_Unicode
* pDst
, const sal_Unicode
* pSrc
, xub_StrLen nMax
)
1854 const sal_Unicode
* const pStop
= pDst
+ nMax
;
1855 while ( *pSrc
&& pDst
< pStop
)
1864 //---------------------------------------------------------------------------
1866 //---------------------------------------------------------------------------
1867 // Zerlegt die Formel in einzelne Symbole fuer die weitere
1868 // Verarbeitung (Turing-Maschine).
1869 //---------------------------------------------------------------------------
1870 // Ausgangs Zustand = GetChar
1871 //---------------+-------------------+-----------------------+---------------
1872 // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
1873 //---------------+-------------------+-----------------------+---------------
1874 // GetChar | ;()+-*/^=& | Symbol=Zeichen | Stop
1875 // | <> | Symbol=Zeichen | GetBool
1876 // | $ Buchstabe | Symbol=Zeichen | GetWord
1877 // | Ziffer | Symbol=Zeichen | GetValue
1878 // | " | Keine | GetString
1879 // | Sonst | Keine | GetChar
1880 //---------------+-------------------+-----------------------+---------------
1881 // GetBool | => | Symbol=Symbol+Zeichen | Stop
1882 // | Sonst | Dec(CharPos) | Stop
1883 //---------------+-------------------+-----------------------+---------------
1884 // GetWord | SepSymbol | Dec(CharPos) | Stop
1885 // | ()+-*/^=<>&~ | |
1886 // | Leerzeichen | Dec(CharPos) | Stop
1888 // | Buchstabe,Ziffer | Symbol=Symbol+Zeichen | GetWord
1889 // | Sonst | Fehler | Stop
1890 //---------------|-------------------+-----------------------+---------------
1891 // GetValue | ;()*/^=<>& | |
1892 // | Leerzeichen | Dec(CharPos) | Stop
1893 // | Ziffer E+-%,. | Symbol=Symbol+Zeichen | GetValue
1894 // | Sonst | Fehler | Stop
1895 //---------------+-------------------+-----------------------+---------------
1896 // GetString | " | Keine | Stop
1897 // | Sonst | Symbol=Symbol+Zeichen | GetString
1898 //---------------+-------------------+-----------------------+---------------
1900 xub_StrLen
ScCompiler::NextSymbol(bool bInArray
)
1902 cSymbol
[MAXSTRLEN
-1] = 0; // Stopper
1903 sal_Unicode
* pSym
= cSymbol
;
1904 const sal_Unicode
* const pStart
= aFormula
.GetBuffer();
1905 const sal_Unicode
* pSrc
= pStart
+ nSrcPos
;
1907 sal_Unicode c
= *pSrc
;
1908 sal_Unicode cLast
= 0;
1909 bool bQuote
= false;
1910 mnRangeOpPosInSymbol
= -1;
1911 ScanState eState
= ssGetChar
;
1912 xub_StrLen nSpaces
= 0;
1913 sal_Unicode cSep
= mxSymbols
->getSymbol( ocSep
).GetChar(0);
1914 sal_Unicode cArrayColSep
= mxSymbols
->getSymbol( ocArrayColSep
).GetChar(0);
1915 sal_Unicode cArrayRowSep
= mxSymbols
->getSymbol( ocArrayRowSep
).GetChar(0);
1916 sal_Unicode cDecSep
= (mxSymbols
->isEnglish() ? '.' :
1917 ScGlobal::pLocaleData
->getNumDecimalSep().GetChar(0));
1919 // special symbols specific to address convention used
1920 sal_Unicode cSheetPrefix
= pConv
->getSpecialSymbol(ScCompiler::Convention::ABS_SHEET_PREFIX
);
1921 sal_Unicode cSheetSep
= pConv
->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR
);
1924 bool bAutoIntersection
= false;
1926 mnPredetectedReference
= 0;
1927 // try to parse simple tokens before calling i18n parser
1928 while ((c
!= 0) && (eState
!= ssStop
) )
1931 ULONG nMask
= GetCharTableFlags( c
);
1932 // The parameter separator and the array column and row separators end
1933 // things unconditionally if not in string or reference.
1934 if (c
== cSep
|| (bInArray
&& (c
== cArrayColSep
|| c
== cArrayRowSep
)))
1938 // these are to be continued
1941 case ssGetReference
:
1942 case ssSkipReference
:
1945 if (eState
== ssGetChar
)
1952 Label_MaskStateMachine
:
1957 // Order is important!
1958 if( nMask
& SC_COMPILER_C_ODF_LABEL_OP
)
1960 // '!!' automatic intersection
1961 if (GetCharTableFlags( pSrc
[0] ) & SC_COMPILER_C_ODF_LABEL_OP
)
1963 /* TODO: For now the UI "space operator" is used, this
1964 * could be enhanced using a specialized OpCode to get
1965 * rid of the space ambiguity, which would need some
1966 * places to be adapted though. And we would still need
1967 * to support the ambiguous space operator for UI
1968 * purposes anyway. However, we then could check for
1969 * invalid usage of '!!', which currently isn't
1971 if (!bAutoIntersection
)
1974 nSpaces
+= 2; // must match the character count
1975 bAutoIntersection
= true;
1985 nMask
&= ~SC_COMPILER_C_ODF_LABEL_OP
;
1986 goto Label_MaskStateMachine
;
1989 else if( nMask
& SC_COMPILER_C_ODF_NAME_MARKER
)
1991 // '$$' defined name marker
1992 if (GetCharTableFlags( pSrc
[0] ) & SC_COMPILER_C_ODF_NAME_MARKER
)
1994 // both eaten, not added to pSym
1999 nMask
&= ~SC_COMPILER_C_ODF_NAME_MARKER
;
2000 goto Label_MaskStateMachine
;
2003 else if( nMask
& SC_COMPILER_C_CHAR
)
2008 else if( nMask
& SC_COMPILER_C_ODF_LBRACKET
)
2010 // eaten, not added to pSym
2011 eState
= ssGetReference
;
2012 mnPredetectedReference
= 1;
2014 else if( nMask
& SC_COMPILER_C_CHAR_BOOL
)
2019 else if( nMask
& SC_COMPILER_C_CHAR_VALUE
)
2022 eState
= ssGetValue
;
2024 else if( nMask
& SC_COMPILER_C_CHAR_STRING
)
2027 eState
= ssGetString
;
2029 else if( nMask
& SC_COMPILER_C_CHAR_DONTCARE
)
2033 else if( nMask
& SC_COMPILER_C_CHAR_IDENT
)
2034 { // try to get a simple ASCII identifier before calling
2035 // i18n, to gain performance during import
2037 eState
= ssGetIdent
;
2048 if ( nMask
& SC_COMPILER_C_IDENT
)
2049 { // This catches also $Sheet1.A$1, for example.
2050 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2052 SetError(errStringOverflow
);
2058 else if (c
== ':' && mnRangeOpPosInSymbol
< 0)
2060 // One range operator may form Sheet1.A:A, which we need to
2061 // pass as one entity to IsReference().
2062 mnRangeOpPosInSymbol
= pSym
- &cSymbol
[0];
2063 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2065 SetError(errStringOverflow
);
2071 else if ( 128 <= c
|| '\'' == c
)
2072 { // High values need reparsing with i18n,
2073 // single quoted $'sheet' names too (otherwise we'd had to
2074 // implement everything twice).
2087 if( nMask
& SC_COMPILER_C_BOOL
)
2101 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2103 SetError(errStringOverflow
);
2106 else if (c
== cDecSep
)
2110 // reparse with i18n, may be numeric sheet name as well
2117 else if( nMask
& SC_COMPILER_C_VALUE
)
2119 else if( nMask
& SC_COMPILER_C_VALUE_SEP
)
2124 else if (c
== 'E' || c
== 'e')
2126 if (GetCharTableFlags( pSrc
[0] ) & SC_COMPILER_C_VALUE_EXP
)
2130 // reparse with i18n
2135 else if( nMask
& SC_COMPILER_C_VALUE_SIGN
)
2137 if (((cLast
== 'E') || (cLast
== 'e')) &&
2138 (GetCharTableFlags( pSrc
[0] ) & SC_COMPILER_C_VALUE_VALUE
))
2150 // reparse with i18n
2158 if( nMask
& SC_COMPILER_C_STRING_SEP
)
2163 bQuote
= true; // "" => literal "
2172 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2174 SetError(errStringOverflow
);
2175 eState
= ssSkipString
;
2183 if( nMask
& SC_COMPILER_C_STRING_SEP
)
2186 case ssGetReference
:
2187 if( pSym
== &cSymbol
[ MAXSTRLEN
-1 ] )
2189 SetError( errStringOverflow
);
2190 eState
= ssSkipReference
;
2192 // fall through and follow logic
2193 case ssSkipReference
:
2194 // ODF reference: ['External'#$'Sheet'.A1:.B2] with dots being
2195 // mandatory also if no sheet name. 'External'# is optional,
2196 // sheet name is optional, quotes around sheet name are
2197 // optional if no quote contained.
2198 // 2nd usage: ['Sheet'.$$'DefinedName']
2199 // 3rd usage: ['External'#$$'DefinedName']
2200 // 4th usage: ['External'#$'Sheet'.$$'DefinedName']
2201 // Also for all these names quotes are optional if no quote
2205 // nRefInName: 0 := not in sheet name yet. 'External'
2206 // is parsed as if it was a sheet name and nRefInName
2207 // is reset when # is encountered immediately after closing
2208 // quote. Same with 'DefinedName', nRefInName is cleared
2209 // when : is encountered.
2211 // Encountered leading $ before sheet name.
2212 static const int kDollar
= (1 << 1);
2213 // Encountered ' opening quote, which may be after $ or
2215 static const int kOpen
= (1 << 2);
2216 // Somewhere in name.
2217 static const int kName
= (1 << 3);
2218 // Encountered ' in name, will be cleared if double or
2219 // transformed to kClose if not, in which case kOpen is
2221 static const int kQuote
= (1 << 4);
2222 // Past ' closing quote.
2223 static const int kClose
= (1 << 5);
2224 // Past . sheet name separator.
2225 static const int kPast
= (1 << 6);
2226 // Marked name $$ follows sheet name separator, detected
2227 // while we're still on the separator. Will be cleared when
2228 // entering the name.
2229 static const int kMarkAhead
= (1 << 7);
2230 // In marked defined name.
2231 static const int kDefName
= (1 << 8);
2233 bool bAddToSymbol
= true;
2234 if ((nMask
& SC_COMPILER_C_ODF_RBRACKET
) && !(nRefInName
& kOpen
))
2236 DBG_ASSERT( nRefInName
& (kPast
| kDefName
),
2237 "ScCompiler::NextSymbol: reference: "
2238 "closing bracket ']' without prior sheet name separator '.' violates ODF spec");
2239 // eaten, not added to pSym
2240 bAddToSymbol
= false;
2243 else if (cSheetSep
== c
&& nRefInName
== 0)
2245 // eat it, no sheet name [.A1]
2246 bAddToSymbol
= false;
2247 nRefInName
|= kPast
;
2248 if ('$' == pSrc
[0] && '$' == pSrc
[1])
2249 nRefInName
|= kMarkAhead
;
2251 else if (!(nRefInName
& kPast
) || (nRefInName
& (kMarkAhead
| kDefName
)))
2253 // Not in col/row yet.
2255 if ('$' == c
&& '$' == pSrc
[0] && !(nRefInName
& kOpen
))
2257 nRefInName
&= ~kMarkAhead
;
2258 if (!(nRefInName
& kDefName
))
2260 // eaten, not added to pSym (2 chars)
2261 bAddToSymbol
= false;
2263 nRefInName
&= kPast
;
2264 nRefInName
|= kDefName
;
2268 // ScAddress::Parse() will recognize this as
2270 if (eState
!= ssSkipReference
)
2275 bAddToSymbol
= false;
2278 else if (cSheetPrefix
== c
&& nRefInName
== 0)
2279 nRefInName
|= kDollar
;
2282 // TODO: The conventions' parseExternalName()
2283 // should handle quoted names, but as long as they
2284 // don't remove non-embedded quotes here.
2285 if (!(nRefInName
& kName
))
2287 nRefInName
|= (kOpen
| kName
);
2288 bAddToSymbol
= !(nRefInName
& kDefName
);
2290 else if (!(nRefInName
& kOpen
))
2292 DBG_ERRORFILE("ScCompiler::NextSymbol: reference: "
2293 "a ''' without the name being enclosed in '...' violates ODF spec");
2295 else if (nRefInName
& kQuote
)
2297 // escaped embedded quote
2298 nRefInName
&= ~kQuote
;
2302 if ('\'' == pSrc
[0])
2304 // escapes embedded quote
2305 nRefInName
|= kQuote
;
2309 // quote not followed by quote => close
2310 nRefInName
|= kClose
;
2311 nRefInName
&= ~kOpen
;
2313 bAddToSymbol
= !(nRefInName
& kDefName
);
2316 else if (cSheetSep
== c
&& !(nRefInName
& kOpen
))
2318 // unquoted sheet name separator
2319 nRefInName
|= kPast
;
2320 if ('$' == pSrc
[0] && '$' == pSrc
[1])
2321 nRefInName
|= kMarkAhead
;
2323 else if (':' == c
&& !(nRefInName
& kOpen
))
2325 DBG_ERRORFILE("ScCompiler::NextSymbol: reference: "
2326 "range operator ':' without prior sheet name separator '.' violates ODF spec");
2328 ++mnPredetectedReference
;
2330 else if (!(nRefInName
& kName
))
2332 // start unquoted name
2333 nRefInName
|= kName
;
2340 ++mnPredetectedReference
;
2342 if (bAddToSymbol
&& eState
!= ssSkipReference
)
2343 *pSym
++ = c
; // everything is part of reference
2347 ; // nothing, prevent warning
2355 nSrcPos
= sal::static_int_cast
<xub_StrLen
>( nSrcPos
+ nSpaces
);
2357 mnRangeOpPosInSymbol
= -1;
2362 // special case (e.g. $'sheetname' in OOO A1)
2363 if ( pStart
[nSrcPos
] == cSheetPrefix
&& pStart
[nSrcPos
+1] == '\'' )
2364 aSymbol
+= pStart
[nSrcPos
++];
2366 ParseResult aRes
= pConv
->parseAnyToken( aFormula
, nSrcPos
, pCharClass
);
2368 if ( !aRes
.TokenType
)
2369 SetError( nErr
= errIllegalChar
); // parsed chars as string
2370 if ( aRes
.EndPos
<= nSrcPos
)
2372 SetError( nErr
= errIllegalChar
);
2373 nSrcPos
= aFormula
.Len();
2378 aSymbol
.Append( pStart
+ nSrcPos
, (xub_StrLen
)aRes
.EndPos
- nSrcPos
);
2379 nSrcPos
= (xub_StrLen
) aRes
.EndPos
;
2380 c
= pStart
[nSrcPos
];
2381 if ( aRes
.TokenType
& KParseType::SINGLE_QUOTE_NAME
)
2382 { // special cases (e.g. 'sheetname'. or 'filename'# in OOO A1)
2383 bi18n
= (c
== cSheetSep
|| c
== SC_COMPILER_FILE_TAB_SEP
);
2385 // One range operator restarts parsing for second reference.
2386 if (c
== ':' && mnRangeOpPosInSymbol
< 0)
2388 mnRangeOpPosInSymbol
= aSymbol
.Len();
2392 aSymbol
+= pStart
[nSrcPos
++];
2394 } while ( bi18n
&& !nErr
);
2395 xub_StrLen nLen
= aSymbol
.Len();
2396 if ( nLen
>= MAXSTRLEN
)
2398 SetError( errStringOverflow
);
2401 lcl_UnicodeStrNCpy( cSymbol
, aSymbol
.GetBuffer(), nLen
);
2405 nSrcPos
= sal::static_int_cast
<xub_StrLen
>( pSrc
- pStart
);
2408 if (mnRangeOpPosInSymbol
>= 0 && mnRangeOpPosInSymbol
== (pSym
-1) - &cSymbol
[0])
2410 // This is a trailing range operator, which is nonsense. Will be caught
2412 mnRangeOpPosInSymbol
= -1;
2417 aCorrectedSymbol
= cSymbol
;
2418 if (bAutoIntersection
&& nSpaces
> 1)
2419 --nSpaces
; // replace '!!' with only one space
2423 //---------------------------------------------------------------------------
2424 // Convert symbol to token
2425 //---------------------------------------------------------------------------
2427 BOOL
ScCompiler::IsOpCode( const String
& rName
, bool bInArray
)
2429 OpCodeHashMap::const_iterator
iLook( mxSymbols
->getHashMap()->find( rName
));
2430 BOOL bFound
= (iLook
!= mxSymbols
->getHashMap()->end());
2434 OpCode eOp
= iLook
->second
;
2437 if (rName
.Equals(mxSymbols
->getSymbol(ocArrayColSep
)))
2438 eOp
= ocArrayColSep
;
2439 else if (rName
.Equals(mxSymbols
->getSymbol(ocArrayRowSep
)))
2440 eOp
= ocArrayRowSep
;
2442 aToken
.SetOpCode(eOp
);
2443 pRawToken
= aToken
.Clone();
2448 if (mxSymbols
->hasExternals())
2450 // If symbols are set by filters get mapping to exact name.
2451 ExternalHashMap::const_iterator
iExt(
2452 mxSymbols
->getExternalHashMap()->find( rName
));
2453 if (iExt
!= mxSymbols
->getExternalHashMap()->end())
2455 if (ScGlobal::GetAddInCollection()->GetFuncData( (*iExt
).second
))
2456 aIntName
= (*iExt
).second
;
2458 if (!aIntName
.Len())
2460 // If that isn't found we might continue with rName lookup as a
2461 // last resort by just falling through to FindFunction(), but
2462 // it shouldn't happen if the map was setup correctly. Don't
2463 // waste time and bail out.
2467 if (!aIntName
.Len())
2469 // Old (deprecated) addins first for legacy.
2471 bFound
= ScGlobal::GetFuncCollection()->SearchFunc( cSymbol
, nIndex
);
2475 aToken
.SetExternal( cSymbol
);
2476 pRawToken
= aToken
.Clone();
2479 // bLocalFirst=FALSE for (English) upper full original name
2480 // (service.function)
2481 aIntName
= ScGlobal::GetAddInCollection()->FindFunction(
2482 rName
, !mxSymbols
->isEnglish());
2487 aToken
.SetExternal( aIntName
.GetBuffer() ); // international name
2488 pRawToken
= aToken
.Clone();
2493 if (bFound
&& ((eOp
= pRawToken
->GetOpCode()) == ocSub
|| eOp
== ocNegSub
))
2495 bool bShouldBeNegSub
=
2496 (eLastOp
== ocOpen
|| eLastOp
== ocSep
|| eLastOp
== ocNegSub
||
2497 (SC_OPCODE_START_BIN_OP
<= eLastOp
&& eLastOp
< SC_OPCODE_STOP_BIN_OP
) ||
2498 eLastOp
== ocArrayOpen
||
2499 eLastOp
== ocArrayColSep
|| eLastOp
== ocArrayRowSep
);
2500 if (bShouldBeNegSub
&& eOp
== ocSub
)
2501 pRawToken
->NewOpCode( ocNegSub
);
2502 //! if ocNegSub had ForceArray we'd have to set it here
2503 else if (!bShouldBeNegSub
&& eOp
== ocNegSub
)
2504 pRawToken
->NewOpCode( ocSub
);
2509 BOOL
ScCompiler::IsOpCode2( const String
& rName
)
2511 BOOL bFound
= FALSE
;
2514 for( i
= ocInternalBegin
; i
<= ocInternalEnd
&& !bFound
; i
++ )
2515 bFound
= rName
.EqualsAscii( pInternal
[ i
-ocInternalBegin
] );
2520 aToken
.SetOpCode( (OpCode
) --i
);
2521 pRawToken
= aToken
.Clone();
2526 BOOL
ScCompiler::IsValue( const String
& rSym
)
2529 sal_uInt32 nIndex
= ( mxSymbols
->isEnglish() ?
2530 pDoc
->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US
) : 0 );
2531 // ULONG nIndex = 0;
2532 //// ULONG nIndex = pDoc->GetFormatTable()->GetStandardIndex(ScGlobal::eLnge);
2533 if (pDoc
->GetFormatTable()->IsNumberFormat( rSym
, nIndex
, fVal
) )
2535 USHORT nType
= pDoc
->GetFormatTable()->GetType(nIndex
);
2537 // Don't accept 3:3 as time, it is a reference to entire row 3 instead.
2538 // Dates should never be entered directly and automatically converted
2539 // to serial, because the serial would be wrong if null-date changed.
2540 // Usually it wouldn't be accepted anyway because the date separator
2541 // clashed with other separators or operators.
2542 if (nType
& (NUMBERFORMAT_TIME
| NUMBERFORMAT_DATE
))
2545 if (nType
== NUMBERFORMAT_LOGICAL
)
2547 const sal_Unicode
* p
= aFormula
.GetBuffer() + nSrcPos
;
2551 return FALSE
; // Boolean function instead.
2554 if( aFormula
.GetChar(nSrcPos
) == '.' )
2555 // numerical sheet name?
2558 if( nType
== NUMBERFORMAT_TEXT
)
2559 // HACK: number too big!
2560 SetError( errIllegalArgument
);
2562 aToken
.SetDouble( fVal
);
2563 pRawToken
= aToken
.Clone();
2570 BOOL
ScCompiler::IsString()
2572 register const sal_Unicode
* p
= cSymbol
;
2575 xub_StrLen nLen
= sal::static_int_cast
<xub_StrLen
>( p
- cSymbol
- 1 );
2576 BOOL bQuote
= ((cSymbol
[0] == '"') && (cSymbol
[nLen
] == '"'));
2577 if ((bQuote
? nLen
-2 : nLen
) > MAXSTRLEN
-1)
2579 SetError(errStringOverflow
);
2584 cSymbol
[nLen
] = '\0';
2586 aToken
.SetString( cSymbol
+1 );
2587 pRawToken
= aToken
.Clone();
2594 BOOL
ScCompiler::IsPredetectedReference( const String
& rName
)
2596 // Speedup documents with lots of broken references, e.g. sheet deleted.
2597 xub_StrLen nPos
= rName
.SearchAscii( "#REF!");
2598 if (nPos
!= STRING_NOTFOUND
)
2600 /* TODO: this may be enhanced by reusing scan information from
2601 * NextSymbol(), the positions of quotes and special characters found
2602 * there for $'sheet'.A1:... could be stored in a vector. We don't
2603 * fully rescan here whether found positions are within single quotes
2604 * for performance reasons. This code does not check for possible
2605 * occurrences of insane "valid" sheet names like
2606 * 'haha.#REF!1fooledyou' and will generate an error on such. */
2608 return false; // #REF!.AB42 or #REF!42 or #REF!#REF!
2609 sal_Unicode c
= rName
.GetChar(nPos
-1); // before #REF!
2613 return false; // $#REF!.AB42 or $#REF!42 or $#REF!#REF!
2614 c
= rName
.GetChar(nPos
-2); // before $#REF!
2616 sal_Unicode c2
= rName
.GetChar(nPos
+5); // after #REF!
2620 if ('$' == c2
|| '#' == c2
|| ('0' <= c2
&& c2
<= '9'))
2621 return false; // sheet.#REF!42 or sheet.#REF!#REF!
2624 if (mnPredetectedReference
> 1 &&
2625 ('.' == c2
|| '$' == c2
|| '#' == c2
||
2626 ('0' <= c2
&& c2
<= '9')))
2627 return false; // :#REF!.AB42 or :#REF!42 or :#REF!#REF!
2630 if ((('A' <= c
&& c
<= 'Z') || ('a' <= c
&& c
<= 'z')) &&
2631 ((mnPredetectedReference
> 1 && ':' == c2
) || 0 == c2
))
2632 return false; // AB#REF!: or AB#REF!
2635 switch (mnPredetectedReference
)
2638 return IsSingleReference( rName
);
2640 return IsDoubleReference( rName
);
2646 BOOL
ScCompiler::IsDoubleReference( const String
& rName
)
2648 ScRange
aRange( aPos
, aPos
);
2649 const ScAddress::Details
aDetails( pConv
->meConv
, aPos
);
2650 ScAddress::ExternalInfo aExtInfo
;
2651 USHORT nFlags
= aRange
.Parse( rName
, pDoc
, aDetails
, &aExtInfo
, &maExternalLinks
);
2652 if( nFlags
& SCA_VALID
)
2655 ScComplexRefData aRef
;
2656 aRef
.InitRange( aRange
);
2657 aRef
.Ref1
.SetColRel( (nFlags
& SCA_COL_ABSOLUTE
) == 0 );
2658 aRef
.Ref1
.SetRowRel( (nFlags
& SCA_ROW_ABSOLUTE
) == 0 );
2659 aRef
.Ref1
.SetTabRel( (nFlags
& SCA_TAB_ABSOLUTE
) == 0 );
2660 if ( !(nFlags
& SCA_VALID_TAB
) )
2661 aRef
.Ref1
.SetTabDeleted( TRUE
); // #REF!
2662 aRef
.Ref1
.SetFlag3D( ( nFlags
& SCA_TAB_3D
) != 0 );
2663 aRef
.Ref2
.SetColRel( (nFlags
& SCA_COL2_ABSOLUTE
) == 0 );
2664 aRef
.Ref2
.SetRowRel( (nFlags
& SCA_ROW2_ABSOLUTE
) == 0 );
2665 aRef
.Ref2
.SetTabRel( (nFlags
& SCA_TAB2_ABSOLUTE
) == 0 );
2666 if ( !(nFlags
& SCA_VALID_TAB2
) )
2667 aRef
.Ref2
.SetTabDeleted( TRUE
); // #REF!
2668 aRef
.Ref2
.SetFlag3D( ( nFlags
& SCA_TAB2_3D
) != 0 );
2669 aRef
.CalcRelFromAbs( aPos
);
2670 if (aExtInfo
.mbExternal
)
2672 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
2673 const String
* pRealTab
= pRefMgr
->getRealTableName(aExtInfo
.mnFileId
, aExtInfo
.maTabName
);
2674 aToken
.SetExternalDoubleRef(
2675 aExtInfo
.mnFileId
, pRealTab
? *pRealTab
: aExtInfo
.maTabName
, aRef
);
2679 aToken
.SetDoubleReference(aRef
);
2681 pRawToken
= aToken
.Clone();
2684 return ( nFlags
& SCA_VALID
) != 0;
2688 BOOL
ScCompiler::IsSingleReference( const String
& rName
)
2690 ScAddress
aAddr( aPos
);
2691 const ScAddress::Details
aDetails( pConv
->meConv
, aPos
);
2692 ScAddress::ExternalInfo aExtInfo
;
2693 USHORT nFlags
= aAddr
.Parse( rName
, pDoc
, aDetails
, &aExtInfo
, &maExternalLinks
);
2694 // Something must be valid in order to recognize Sheet1.blah or blah.a1
2695 // as a (wrong) reference.
2696 if( nFlags
& ( SCA_VALID_COL
|SCA_VALID_ROW
|SCA_VALID_TAB
) )
2699 ScSingleRefData aRef
;
2700 aRef
.InitAddress( aAddr
);
2701 aRef
.SetColRel( (nFlags
& SCA_COL_ABSOLUTE
) == 0 );
2702 aRef
.SetRowRel( (nFlags
& SCA_ROW_ABSOLUTE
) == 0 );
2703 aRef
.SetTabRel( (nFlags
& SCA_TAB_ABSOLUTE
) == 0 );
2704 aRef
.SetFlag3D( ( nFlags
& SCA_TAB_3D
) != 0 );
2705 // the reference is really invalid
2706 if( !( nFlags
& SCA_VALID
) )
2708 if( !( nFlags
& SCA_VALID_COL
) )
2709 aRef
.nCol
= MAXCOL
+1;
2710 if( !( nFlags
& SCA_VALID_ROW
) )
2711 aRef
.nRow
= MAXROW
+1;
2712 if( !( nFlags
& SCA_VALID_TAB
) )
2713 aRef
.nTab
= MAXTAB
+3;
2714 nFlags
|= SCA_VALID
;
2716 aRef
.CalcRelFromAbs( aPos
);
2718 if (aExtInfo
.mbExternal
)
2720 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
2721 const String
* pRealTab
= pRefMgr
->getRealTableName(aExtInfo
.mnFileId
, aExtInfo
.maTabName
);
2722 aToken
.SetExternalSingleRef(
2723 aExtInfo
.mnFileId
, pRealTab
? *pRealTab
: aExtInfo
.maTabName
, aRef
);
2726 aToken
.SetSingleReference(aRef
);
2727 pRawToken
= aToken
.Clone();
2730 return ( nFlags
& SCA_VALID
) != 0;
2734 BOOL
ScCompiler::IsReference( const String
& rName
)
2736 // Has to be called before IsValue
2737 sal_Unicode ch1
= rName
.GetChar(0);
2738 sal_Unicode cDecSep
= ( mxSymbols
->isEnglish() ? '.' :
2739 ScGlobal::pLocaleData
->getNumDecimalSep().GetChar(0) );
2740 if ( ch1
== cDecSep
)
2742 // Who was that imbecile introducing '.' as the sheet name separator!?!
2743 if ( CharClass::isAsciiNumeric( ch1
) )
2745 // Numerical sheet name is valid.
2746 // But English 1.E2 or 1.E+2 is value 100, 1.E-2 is 0.01
2747 // Don't create a #REF! of values. But also do not bail out on
2748 // something like 3:3, meaning entire row 3.
2751 const xub_StrLen nPos
= ScGlobal::FindUnquoted( rName
, '.');
2752 if ( nPos
== STRING_NOTFOUND
)
2754 if (ScGlobal::FindUnquoted( rName
, ':') != STRING_NOTFOUND
)
2755 break; // may be 3:3, continue as usual
2758 sal_Unicode
const * const pTabSep
= rName
.GetBuffer() + nPos
;
2759 sal_Unicode ch2
= pTabSep
[1]; // maybe a column identifier
2760 if ( !(ch2
== '$' || CharClass::isAsciiAlpha( ch2
)) )
2762 if ( cDecSep
== '.' && (ch2
== 'E' || ch2
== 'e') // E + - digit
2763 && (GetCharTableFlags( pTabSep
[2] ) & SC_COMPILER_C_VALUE_EXP
) )
2765 // If it is an 1.E2 expression check if "1" is an existent sheet
2766 // name. If so, a desired value 1.E2 would have to be entered as
2767 // 1E2 or 1.0E2 or 1.E+2, sorry. Another possibility would be to
2768 // require numerical sheet names always being entered quoted, which
2769 // is not desirable (too many 1999, 2000, 2001 sheets in use).
2770 // Furthermore, XML files created with versions prior to SRC640e
2771 // wouldn't contain the quotes added by MakeTabStr()/CheckTabQuotes()
2772 // and would produce wrong formulas if the conditions here are met.
2773 // If you can live with these restrictions you may remove the
2774 // check and return an unconditional FALSE.
2775 String
aTabName( rName
.Copy( 0, nPos
) );
2777 if ( !pDoc
->GetTable( aTabName
, nTab
) )
2779 // If sheet "1" exists and the expression is 1.E+2 continue as
2780 // usual, the ScRange/ScAddress parser will take care of it.
2785 if (IsSingleReference( rName
))
2788 // Though the range operator is handled explicitly, when encountering
2789 // something like Sheet1.A:A we will have to treat it as one entity if it
2790 // doesn't pass as single cell reference.
2791 if (mnRangeOpPosInSymbol
> 0) // ":foo" would be nonsense
2793 if (IsDoubleReference( rName
))
2795 // Now try with a symbol up to the range operator, rewind source
2797 sal_Int32 nLen
= mnRangeOpPosInSymbol
;
2798 while (cSymbol
[++nLen
])
2800 cSymbol
[mnRangeOpPosInSymbol
] = 0;
2801 nSrcPos
-= static_cast<xub_StrLen
>(nLen
- mnRangeOpPosInSymbol
);
2802 mnRangeOpPosInSymbol
= -1;
2804 return true; // end all checks
2809 BOOL
ScCompiler::IsMacro( const String
& rName
)
2811 StarBASIC
* pObj
= 0;
2812 SfxObjectShell
* pDocSh
= pDoc
->GetDocumentShell();
2814 SfxApplication
* pSfxApp
= SFX_APP();
2815 pSfxApp
->EnterBasicCall(); // initialize document's BASIC
2818 pObj
= pDocSh
->GetBasic();
2820 pObj
= pSfxApp
->GetBasic();
2822 SbxMethod
* pMeth
= (SbxMethod
*) pObj
->Find( rName
, SbxCLASS_METHOD
);
2825 pSfxApp
->LeaveBasicCall();
2828 // It really should be a BASIC function!
2829 if( pMeth
->GetType() == SbxVOID
2830 || ( pMeth
->IsFixed() && pMeth
->GetType() == SbxEMPTY
)
2831 || !pMeth
->ISA(SbMethod
) )
2833 pSfxApp
->LeaveBasicCall();
2837 aToken
.SetExternal( rName
.GetBuffer() );
2838 aToken
.eOp
= ocMacro
;
2839 pRawToken
= aToken
.Clone();
2840 pSfxApp
->LeaveBasicCall();
2844 BOOL
ScCompiler::IsNamedRange( const String
& rUpperName
)
2846 // IsNamedRange is called only from NextNewToken, with an upper-case string
2849 ScRangeName
* pRangeName
= pDoc
->GetRangeName();
2850 if (pRangeName
->SearchNameUpper( rUpperName
, n
) )
2852 ScRangeData
* pData
= (*pRangeName
)[n
];
2854 aToken
.SetName( pData
->GetIndex() );
2855 pRawToken
= aToken
.Clone();
2862 bool ScCompiler::IsExternalNamedRange( const String
& rSymbol
)
2864 /* FIXME: This code currently (2008-12-02T15:41+0100 in CWS mooxlsc)
2865 * correctly parses external named references in OOo, as required per RFE
2866 * #i3740#, just that we can't store them in ODF yet. We will need an OASIS
2867 * spec first. Until then don't pretend to support external names that
2868 * wouldn't survive a save and reload cycle, return false instead. */
2874 String aFile
, aName
;
2875 if (!pConv
->parseExternalName( rSymbol
, aFile
, aName
, pDoc
, &maExternalLinks
))
2879 if (aFile
.Len() > MAXSTRLEN
|| aName
.Len() > MAXSTRLEN
)
2882 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
2883 pRefMgr
->convertToAbsName(aFile
);
2884 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId(aFile
);
2885 if (!pRefMgr
->getRangeNameTokens(nFileId
, aName
).get())
2886 // range name doesn't exist in the source document.
2889 const String
* pRealName
= pRefMgr
->getRealRangeName(nFileId
, aName
);
2890 aToken
.SetExternalName(nFileId
, pRealName
? *pRealName
: aName
);
2891 pRawToken
= aToken
.Clone();
2899 BOOL
ScCompiler::IsDBRange( const String
& rName
)
2902 ScDBCollection
* pDBColl
= pDoc
->GetDBCollection();
2903 if (pDBColl
->SearchName( rName
, n
) )
2905 ScDBData
* pData
= (*pDBColl
)[n
];
2907 aToken
.SetName( pData
->GetIndex() );
2908 aToken
.eOp
= ocDBArea
;
2909 pRawToken
= aToken
.Clone();
2916 BOOL
ScCompiler::IsColRowName( const String
& rName
)
2918 BOOL bInList
= FALSE
;
2919 BOOL bFound
= FALSE
;
2920 ScSingleRefData aRef
;
2921 String
aName( rName
);
2923 SCTAB nThisTab
= aPos
.Tab();
2924 for ( short jThisTab
= 1; jThisTab
>= 0 && !bInList
; jThisTab
-- )
2925 { // #50300# first check ranges on this sheet, in case of duplicated names
2926 for ( short jRow
=0; jRow
<2 && !bInList
; jRow
++ )
2928 ScRangePairList
* pRL
;
2930 pRL
= pDoc
->GetColNameRanges();
2932 pRL
= pDoc
->GetRowNameRanges();
2933 for ( ScRangePair
* pR
= pRL
->First(); pR
&& !bInList
; pR
= pRL
->Next() )
2935 const ScRange
& rNameRange
= pR
->GetRange(0);
2936 if ( jThisTab
&& !(rNameRange
.aStart
.Tab() <= nThisTab
&&
2937 nThisTab
<= rNameRange
.aEnd
.Tab()) )
2939 ScCellIterator
aIter( pDoc
, rNameRange
);
2940 for ( ScBaseCell
* pCell
= aIter
.GetFirst(); pCell
&& !bInList
;
2941 pCell
= aIter
.GetNext() )
2943 // Don't crash if cell (via CompileNameFormula) encounters
2944 // a formula cell without code and
2945 // HasStringData/Interpret/Compile is executed and all that
2947 // Furthermore, *this* cell won't be touched, since no RPN exists yet.
2948 CellType eType
= pCell
->GetCellType();
2949 BOOL bOk
= sal::static_int_cast
<BOOL
>( (eType
== CELLTYPE_FORMULA
?
2950 ((ScFormulaCell
*)pCell
)->GetCode()->GetCodeLen() > 0
2951 && ((ScFormulaCell
*)pCell
)->aPos
!= aPos
// noIter
2953 if ( bOk
&& pCell
->HasStringData() )
2958 case CELLTYPE_STRING
:
2959 ((ScStringCell
*)pCell
)->GetString( aStr
);
2961 case CELLTYPE_FORMULA
:
2962 ((ScFormulaCell
*)pCell
)->GetString( aStr
);
2965 ((ScEditCell
*)pCell
)->GetString( aStr
);
2968 case CELLTYPE_VALUE
:
2970 case CELLTYPE_SYMBOLS
:
2972 case CELLTYPE_DESTROYED
:
2974 ; // nothing, prevent compiler warning
2977 if ( ScGlobal::pTransliteration
->isEqual( aStr
, aName
) )
2980 aRef
.nCol
= aIter
.GetCol();
2981 aRef
.nRow
= aIter
.GetRow();
2982 aRef
.nTab
= aIter
.GetTab();
2984 aRef
.SetColRel( TRUE
); // ColName
2986 aRef
.SetRowRel( TRUE
); // RowName
2987 aRef
.CalcRelFromAbs( aPos
);
2988 bInList
= bFound
= TRUE
;
2995 if ( !bInList
&& pDoc
->GetDocOptions().IsLookUpColRowNames() )
2996 { // search in current sheet
2997 long nDistance
= 0, nMax
= 0;
2998 long nMyCol
= (long) aPos
.Col();
2999 long nMyRow
= (long) aPos
.Row();
3001 ScAddress
aOne( 0, 0, aPos
.Tab() );
3002 ScAddress
aTwo( MAXCOL
, MAXROW
, aPos
.Tab() );
3004 ScAutoNameCache
* pNameCache
= pDoc
->GetAutoNameCache();
3007 // #b6355215# use GetNameOccurences to collect all positions of aName on the sheet
3008 // (only once), similar to the outer part of the loop in the "else" branch.
3010 const ScAutoNameAddresses
& rAddresses
= pNameCache
->GetNameOccurences( aName
, aPos
.Tab() );
3012 // Loop through the found positions, similar to the inner part of the loop in the "else" branch.
3013 // The order of addresses in the vector is the same as from ScCellIterator.
3015 ScAutoNameAddresses::const_iterator
aEnd(rAddresses
.end());
3016 for ( ScAutoNameAddresses::const_iterator
aAdrIter(rAddresses
.begin()); aAdrIter
!= aEnd
; ++aAdrIter
)
3018 ScAddress
aAddress( *aAdrIter
); // cell address with an equal string
3021 { // stop if everything else is further away
3022 if ( nMax
< (long)aAddress
.Col() )
3025 if ( aAddress
!= aPos
)
3027 // same treatment as in isEqual case below
3029 SCCOL nCol
= aAddress
.Col();
3030 SCROW nRow
= aAddress
.Row();
3031 long nC
= nMyCol
- nCol
;
3032 long nR
= nMyRow
- nRow
;
3035 long nD
= nC
* nC
+ nR
* nR
;
3036 if ( nD
< nDistance
)
3038 if ( nC
< 0 || nR
< 0 )
3041 aTwo
.Set( nCol
, nRow
, aAddress
.Tab() );
3042 nMax
= Max( nMyCol
+ Abs( nC
), nMyRow
+ Abs( nR
) );
3045 else if ( !(nRow
< aOne
.Row() && nMyRow
>= (long)aOne
.Row()) )
3047 // upper left, only if not further up than the
3048 // current entry and nMyRow is below (CellIter
3049 // runs column-wise)
3051 aOne
.Set( nCol
, nRow
, aAddress
.Tab() );
3052 nMax
= Max( nMyCol
+ nC
, nMyRow
+ nR
);
3059 aOne
.Set( nCol
, nRow
, aAddress
.Tab() );
3060 nDistance
= nC
* nC
+ nR
* nR
;
3061 nMax
= Max( nMyCol
+ Abs( nC
), nMyRow
+ Abs( nR
) );
3069 ScCellIterator
aIter( pDoc
, ScRange( aOne
, aTwo
) );
3070 for ( ScBaseCell
* pCell
= aIter
.GetFirst(); pCell
; pCell
= aIter
.GetNext() )
3073 { // stop if everything else is further away
3074 if ( nMax
< (long)aIter
.GetCol() )
3077 CellType eType
= pCell
->GetCellType();
3078 BOOL bOk
= sal::static_int_cast
<BOOL
>( (eType
== CELLTYPE_FORMULA
?
3079 ((ScFormulaCell
*)pCell
)->GetCode()->GetCodeLen() > 0
3080 && ((ScFormulaCell
*)pCell
)->aPos
!= aPos
// noIter
3082 if ( bOk
&& pCell
->HasStringData() )
3087 case CELLTYPE_STRING
:
3088 ((ScStringCell
*)pCell
)->GetString( aStr
);
3090 case CELLTYPE_FORMULA
:
3091 ((ScFormulaCell
*)pCell
)->GetString( aStr
);
3094 ((ScEditCell
*)pCell
)->GetString( aStr
);
3097 case CELLTYPE_VALUE
:
3099 case CELLTYPE_SYMBOLS
:
3101 case CELLTYPE_DESTROYED
:
3103 ; // nothing, prevent compiler warning
3106 if ( ScGlobal::pTransliteration
->isEqual( aStr
, aName
) )
3108 SCCOL nCol
= aIter
.GetCol();
3109 SCROW nRow
= aIter
.GetRow();
3110 long nC
= nMyCol
- nCol
;
3111 long nR
= nMyRow
- nRow
;
3114 long nD
= nC
* nC
+ nR
* nR
;
3115 if ( nD
< nDistance
)
3117 if ( nC
< 0 || nR
< 0 )
3120 aTwo
.Set( nCol
, nRow
, aIter
.GetTab() );
3121 nMax
= Max( nMyCol
+ Abs( nC
), nMyRow
+ Abs( nR
) );
3124 else if ( !(nRow
< aOne
.Row() && nMyRow
>= (long)aOne
.Row()) )
3126 // upper left, only if not further up than the
3127 // current entry and nMyRow is below (CellIter
3128 // runs column-wise)
3130 aOne
.Set( nCol
, nRow
, aIter
.GetTab() );
3131 nMax
= Max( nMyCol
+ nC
, nMyRow
+ nR
);
3138 aOne
.Set( nCol
, nRow
, aIter
.GetTab() );
3139 nDistance
= nC
* nC
+ nR
* nR
;
3140 nMax
= Max( nMyCol
+ Abs( nC
), nMyRow
+ Abs( nR
) );
3153 if ( nMyCol
>= (long)aOne
.Col() && nMyRow
>= (long)aOne
.Row() )
3154 aAdr
= aOne
; // upper left takes precedence
3157 if ( nMyCol
< (long)aOne
.Col() )
3158 { // two to the right
3159 if ( nMyRow
>= (long)aTwo
.Row() )
3160 aAdr
= aTwo
; // directly right
3165 { // two below or below and right, take the nearest
3166 long nC1
= nMyCol
- aOne
.Col();
3167 long nR1
= nMyRow
- aOne
.Row();
3168 long nC2
= nMyCol
- aTwo
.Col();
3169 long nR2
= nMyRow
- aTwo
.Row();
3170 if ( nC1
* nC1
+ nR1
* nR1
<= nC2
* nC2
+ nR2
* nR2
)
3179 aRef
.InitAddress( aAdr
);
3180 if ( (aRef
.nRow
!= MAXROW
&& pDoc
->HasStringData(
3181 aRef
.nCol
, aRef
.nRow
+ 1, aRef
.nTab
))
3182 || (aRef
.nRow
!= 0 && pDoc
->HasStringData(
3183 aRef
.nCol
, aRef
.nRow
- 1, aRef
.nTab
)) )
3184 aRef
.SetRowRel( TRUE
); // RowName
3186 aRef
.SetColRel( TRUE
); // ColName
3187 aRef
.CalcRelFromAbs( aPos
);
3193 aToken
.SetSingleReference( aRef
);
3194 aToken
.eOp
= ocColRowName
;
3195 pRawToken
= aToken
.Clone();
3202 BOOL
ScCompiler::IsBoolean( const String
& rName
)
3204 OpCodeHashMap::const_iterator
iLook( mxSymbols
->getHashMap()->find( rName
) );
3205 if( iLook
!= mxSymbols
->getHashMap()->end() &&
3206 ((*iLook
).second
== ocTrue
||
3207 (*iLook
).second
== ocFalse
) )
3210 aToken
.SetOpCode( (*iLook
).second
);
3211 pRawToken
= aToken
.Clone();
3218 //---------------------------------------------------------------------------
3220 void ScCompiler::AutoCorrectParsedSymbol()
3222 xub_StrLen nPos
= aCorrectedSymbol
.Len();
3226 const sal_Unicode cQuote
= '\"';
3227 const sal_Unicode cx
= 'x';
3228 const sal_Unicode cX
= 'X';
3229 sal_Unicode c1
= aCorrectedSymbol
.GetChar( 0 );
3230 sal_Unicode c2
= aCorrectedSymbol
.GetChar( nPos
);
3231 if ( c1
== cQuote
&& c2
!= cQuote
)
3233 // What's not a word doesn't belong to it.
3234 // Don't be pedantic: c < 128 should be sufficient here.
3235 while ( nPos
&& ((aCorrectedSymbol
.GetChar(nPos
) < 128) &&
3236 ((GetCharTableFlags( aCorrectedSymbol
.GetChar(nPos
) ) &
3237 (SC_COMPILER_C_WORD
| SC_COMPILER_C_CHAR_DONTCARE
)) == 0)) )
3239 if ( nPos
== MAXSTRLEN
- 2 )
3240 aCorrectedSymbol
.SetChar( nPos
, cQuote
); // '"' the 255th character
3242 aCorrectedSymbol
.Insert( cQuote
, nPos
+ 1 );
3245 else if ( c1
!= cQuote
&& c2
== cQuote
)
3247 aCorrectedSymbol
.Insert( cQuote
, 0 );
3250 else if ( nPos
== 0 && (c1
== cx
|| c1
== cX
) )
3252 aCorrectedSymbol
= mxSymbols
->getSymbol(ocMul
);
3255 else if ( (GetCharTableFlags( c1
) & SC_COMPILER_C_CHAR_VALUE
)
3256 && (GetCharTableFlags( c2
) & SC_COMPILER_C_CHAR_VALUE
) )
3259 if ( (nXcount
= aCorrectedSymbol
.GetTokenCount( cx
)) > 1 )
3261 xub_StrLen nIndex
= 0;
3262 sal_Unicode c
= mxSymbols
->getSymbol(ocMul
).GetChar(0);
3263 while ( (nIndex
= aCorrectedSymbol
.SearchAndReplace(
3264 cx
, c
, nIndex
)) != STRING_NOTFOUND
)
3268 if ( (nXcount
= aCorrectedSymbol
.GetTokenCount( cX
)) > 1 )
3270 xub_StrLen nIndex
= 0;
3271 sal_Unicode c
= mxSymbols
->getSymbol(ocMul
).GetChar(0);
3272 while ( (nIndex
= aCorrectedSymbol
.SearchAndReplace(
3273 cX
, c
, nIndex
)) != STRING_NOTFOUND
)
3280 String
aSymbol( aCorrectedSymbol
);
3282 xub_StrLen nPosition
;
3283 if ( aSymbol
.GetChar(0) == '\''
3284 && ((nPosition
= aSymbol
.SearchAscii( "'#" )) != STRING_NOTFOUND
) )
3285 { // Split off 'Doc'#, may be d:\... or whatever
3286 aDoc
= aSymbol
.Copy( 0, nPosition
+ 2 );
3287 aSymbol
.Erase( 0, nPosition
+ 2 );
3289 xub_StrLen nRefs
= aSymbol
.GetTokenCount( ':' );
3292 { // duplicated or too many ':'? B:2::C10 => B2:C10
3294 xub_StrLen nIndex
= 0;
3295 String
aTmp1( aSymbol
.GetToken( 0, ':', nIndex
) );
3296 xub_StrLen nLen1
= aTmp1
.Len();
3298 BOOL bLastAlp
, bNextNum
;
3299 bLastAlp
= bNextNum
= TRUE
;
3300 xub_StrLen nStrip
= 0;
3301 xub_StrLen nCount
= nRefs
;
3302 for ( xub_StrLen j
=1; j
<nCount
; j
++ )
3304 aTmp2
= aSymbol
.GetToken( 0, ':', nIndex
);
3305 xub_StrLen nLen2
= aTmp2
.Len();
3306 if ( nLen1
|| nLen2
)
3311 bLastAlp
= CharClass::isAsciiAlpha( aTmp1
);
3315 bNextNum
= CharClass::isAsciiNumeric( aTmp2
);
3316 if ( bLastAlp
== bNextNum
&& nStrip
< 1 )
3318 // Must be alternating number/string, only
3319 // strip within a reference.
3325 xub_StrLen nSymLen
= aSym
.Len();
3327 && (aSym
.GetChar( nSymLen
- 1 ) != ':') )
3331 bLastAlp
= !bNextNum
;
3337 { // B10::C10 ? append ':' on next round
3338 if ( !bLastAlp
&& !CharClass::isAsciiNumeric( aTmp1
) )
3341 bNextNum
= !bLastAlp
;
3354 if ( nRefs
&& nRefs
<= 2 )
3355 { // reference twisted? 4A => A4 etc.
3356 String aTab
[2], aRef
[2];
3357 const ScAddress::Details
aDetails( pConv
->meConv
, aPos
);
3360 aRef
[0] = aSymbol
.GetToken( 0, ':' );
3361 aRef
[1] = aSymbol
.GetToken( 1, ':' );
3366 BOOL bChanged
= FALSE
;
3368 USHORT nMask
= SCA_VALID
| SCA_VALID_COL
| SCA_VALID_ROW
;
3369 for ( int j
=0; j
<nRefs
; j
++ )
3371 xub_StrLen nTmp
= 0;
3372 xub_StrLen nDotPos
= STRING_NOTFOUND
;
3373 while ( (nTmp
= aRef
[j
].Search( '.', nTmp
)) != STRING_NOTFOUND
)
3374 nDotPos
= nTmp
++; // the last one counts
3375 if ( nDotPos
!= STRING_NOTFOUND
)
3377 aTab
[j
] = aRef
[j
].Copy( 0, nDotPos
+ 1 ); // with '.'
3378 aRef
[j
].Erase( 0, nDotPos
+ 1 );
3380 String
aOld( aRef
[j
] );
3382 const sal_Unicode
* p
= aRef
[j
].GetBuffer();
3383 while ( *p
&& CharClass::isAsciiNumeric( *p
) )
3385 aRef
[j
] = String( p
);
3387 if ( bColons
|| aRef
[j
] != aOld
)
3391 bOk
&= ((aAdr
.Parse( aRef
[j
], pDoc
, aDetails
) & nMask
) == nMask
);
3394 if ( bChanged
&& bOk
)
3396 aCorrectedSymbol
= aDoc
;
3397 aCorrectedSymbol
+= aTab
[0];
3398 aCorrectedSymbol
+= aRef
[0];
3401 aCorrectedSymbol
+= ':';
3402 aCorrectedSymbol
+= aTab
[1];
3403 aCorrectedSymbol
+= aRef
[1];
3412 inline bool lcl_UpperAsciiOrI18n( String
& rUpper
, const String
& rOrg
, FormulaGrammar::Grammar eGrammar
)
3414 if (FormulaGrammar::isODFF( eGrammar
))
3416 // ODFF has a defined set of English function names, avoid i18n
3419 rUpper
.ToUpperAscii();
3424 rUpper
= ScGlobal::pCharClass
->upper( rOrg
);
3429 BOOL
ScCompiler::NextNewToken( bool bInArray
)
3431 bool bAllowBooleans
= bInArray
;
3432 xub_StrLen nSpaces
= NextSymbol(bInArray
);
3435 fprintf( stderr
, "NextNewToken '%s' (spaces = %d)\n",
3436 rtl::OUStringToOString( cSymbol
, RTL_TEXTENCODING_UTF8
).getStr(), nSpaces
);
3445 aToken
.SetOpCode( ocSpaces
);
3446 aToken
.sbyte
.cByte
= (BYTE
) ( nSpaces
> 255 ? 255 : nSpaces
);
3447 if( !static_cast<ScTokenArray
*>(pArr
)->AddRawToken( aToken
) )
3449 SetError(errCodeOverflow
);
3454 // Short cut for references when reading ODF to speedup things.
3455 if (mnPredetectedReference
)
3457 String
aStr( cSymbol
);
3458 if (!IsPredetectedReference( aStr
) && !IsExternalNamedRange( aStr
))
3460 /* TODO: it would be nice to generate a #REF! error here, which
3461 * would need an ocBad token with additional error value.
3462 * FormulaErrorToken wouldn't do because we want to preserve the
3463 * original string containing partial valid address
3466 aToken
.SetString( aStr
.GetBuffer() );
3467 aToken
.NewOpCode( ocBad
);
3468 pRawToken
= aToken
.Clone();
3473 if ( (cSymbol
[0] == '#' || cSymbol
[0] == '$') && cSymbol
[1] == 0 &&
3475 { // #101100# special case to speed up broken [$]#REF documents
3476 /* FIXME: ISERROR(#REF!) would be valid and TRUE and the formula to
3477 * be processed as usual. That would need some special treatment,
3478 * also in NextSymbol() because of possible combinations of
3479 * #REF!.#REF!#REF! parts. In case of reading ODF that is all
3480 * handled by IsPredetectedReference(), this case here remains for
3481 * manual/API input. */
3482 String
aBad( aFormula
.Copy( nSrcPos
-1 ) );
3483 eLastOp
= pArr
->AddBad( aBad
)->GetOpCode();
3490 bool bMayBeFuncName
;
3491 bool bAsciiNonAlnum
; // operators, separators, ...
3492 if ( cSymbol
[0] < 128 )
3494 bMayBeFuncName
= CharClass::isAsciiAlpha( cSymbol
[0] );
3495 bAsciiNonAlnum
= !bMayBeFuncName
&& !CharClass::isAsciiDigit( cSymbol
[0] );
3499 String
aTmpStr( cSymbol
[0] );
3500 bMayBeFuncName
= ScGlobal::pCharClass
->isLetter( aTmpStr
, 0 );
3501 bAsciiNonAlnum
= false;
3503 if ( bMayBeFuncName
)
3505 // a function name must be followed by a parenthesis
3506 const sal_Unicode
* p
= aFormula
.GetBuffer() + nSrcPos
;
3509 bMayBeFuncName
= ( *p
== '(' );
3513 fprintf( stderr
, "Token '%s'\n",
3514 rtl::OUStringToOString( aUpper
, RTL_TEXTENCODING_UTF8
).getStr() );
3517 // #42016# Italian ARCTAN.2 resulted in #REF! => IsOpcode() before
3525 const String
aOrg( cSymbol
);
3527 if (bAsciiNonAlnum
&& IsOpCode( aOrg
, bInArray
))
3531 bool bAsciiUpper
= false;
3534 bAsciiUpper
= lcl_UpperAsciiOrI18n( aUpper
, aOrg
, meGrammar
);
3535 if (IsOpCode( aUpper
, bInArray
))
3539 // Column 'DM' ("Deutsche Mark", German currency) couldn't be
3540 // referred => IsReference() before IsValue().
3541 // Preserve case of file names in external references.
3542 if (IsReference( aOrg
))
3544 if (mbRewind
) // Range operator, but no direct reference.
3545 continue; // do; up to range operator.
3550 bAsciiUpper
= lcl_UpperAsciiOrI18n( aUpper
, aOrg
, meGrammar
);
3552 // IsBoolean() before IsValue() to catch inline bools without the kludge
3553 // for inline arrays.
3554 if (bAllowBooleans
&& IsBoolean( aUpper
))
3557 if (IsValue( aUpper
))
3560 // User defined names and such do need i18n upper also in ODF.
3562 aUpper
= ScGlobal::pCharClass
->upper( aOrg
);
3564 if (IsNamedRange( aUpper
))
3566 // Preserve case of file names in external references.
3567 if (IsExternalNamedRange( aOrg
))
3569 if (IsDBRange( aUpper
))
3571 if (IsColRowName( aUpper
))
3573 if (bMayBeFuncName
&& IsMacro( aUpper
))
3575 if (bMayBeFuncName
&& IsOpCode2( aUpper
))
3580 if ( mbExtendedErrorDetection
)
3582 // set an error and end compilation
3583 SetError( errNoName
);
3587 // Provide single token information and continue. Do not set an error, that
3588 // would prematurely end compilation. Simple unknown names are handled by
3590 ScGlobal::pCharClass
->toLower( aUpper
);
3592 aToken
.SetString( aUpper
.GetBuffer() );
3593 aToken
.NewOpCode( ocBad
);
3594 pRawToken
= aToken
.Clone();
3596 AutoCorrectParsedSymbol();
3600 void ScCompiler::CreateStringFromXMLTokenArray( String
& rFormula
, String
& rFormulaNmsp
)
3602 bool bExternal
= GetGrammar() == FormulaGrammar::GRAM_EXTERNAL
;
3603 USHORT nExpectedCount
= bExternal
? 2 : 1;
3604 DBG_ASSERT( pArr
->GetLen() == nExpectedCount
, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" );
3605 if( pArr
->GetLen() == nExpectedCount
)
3607 FormulaToken
** ppTokens
= pArr
->GetArray();
3608 // string tokens expected, GetString() will assert if token type is wrong
3609 rFormula
= ppTokens
[ 0 ]->GetString();
3611 rFormulaNmsp
= ppTokens
[ 1 ]->GetString();
3615 ScTokenArray
* ScCompiler::CompileString( const String
& rFormula
)
3618 fprintf( stderr
, "CompileString '%s'\n",
3619 rtl::OUStringToOString( rFormula
, RTL_TEXTENCODING_UTF8
).getStr() );
3622 OSL_ENSURE( meGrammar
!= FormulaGrammar::GRAM_EXTERNAL
, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" );
3623 if( meGrammar
== FormulaGrammar::GRAM_EXTERNAL
)
3624 SetGrammar( FormulaGrammar::GRAM_PODF
);
3628 aFormula
= rFormula
;
3630 aFormula
.EraseLeadingChars();
3631 aFormula
.EraseTrailingChars();
3636 aCorrectedFormula
.Erase();
3637 aCorrectedSymbol
.Erase();
3639 BYTE nForced
= 0; // ==formula forces recalc even if cell is not visible
3640 if( aFormula
.GetChar(nSrcPos
) == '=' )
3645 aCorrectedFormula
+= '=';
3647 if( aFormula
.GetChar(nSrcPos
) == '=' )
3652 aCorrectedFormula
+= '=';
3654 struct FunctionStack
3659 // FunctionStack only used if PODF!
3660 bool bPODF
= FormulaGrammar::isPODF( meGrammar
);
3661 const size_t nAlloc
= 512;
3662 FunctionStack aFuncs
[ nAlloc
];
3663 FunctionStack
* pFunctionStack
= (bPODF
&& rFormula
.Len() > nAlloc
?
3664 new FunctionStack
[ rFormula
.Len() ] : &aFuncs
[0]);
3665 pFunctionStack
[0].eOp
= ocNone
;
3666 pFunctionStack
[0].nPar
= 0;
3667 size_t nFunction
= 0;
3668 short nBrackets
= 0;
3669 bool bInArray
= false;
3671 while( NextNewToken( bInArray
) )
3673 const OpCode eOp
= pRawToken
->GetOpCode();
3682 pFunctionStack
[ nFunction
].eOp
= eLastOp
;
3683 pFunctionStack
[ nFunction
].nPar
= 0;
3691 SetError( errPairExpected
);
3695 aCorrectedSymbol
.Erase();
3700 if (bPODF
&& nFunction
)
3707 ++pFunctionStack
[ nFunction
].nPar
;
3713 SetError( errNestedArray
);
3716 // Don't count following column separator as parameter separator.
3720 pFunctionStack
[ nFunction
].eOp
= eOp
;
3721 pFunctionStack
[ nFunction
].nPar
= 0;
3733 SetError( errPairExpected
);
3737 aCorrectedSymbol
.Erase();
3740 if (bPODF
&& nFunction
)
3746 if( (eLastOp
== ocSep
||
3747 eLastOp
== ocArrayRowSep
||
3748 eLastOp
== ocArrayColSep
||
3749 eLastOp
== ocArrayOpen
) &&
3751 eOp
== ocArrayRowSep
||
3752 eOp
== ocArrayColSep
||
3753 eOp
== ocArrayClose
) )
3755 // FIXME: should we check for known functions with optional empty
3756 // args so the correction dialog can do better?
3757 if ( !static_cast<ScTokenArray
*>(pArr
)->Add( new FormulaMissingToken
) )
3759 SetError(errCodeOverflow
); break;
3764 /* TODO: for now this is the only PODF adapter. If there were more,
3765 * factor this out. */
3766 // Insert ADDRESS() new empty parameter 4 if there is a 4th, now to be 5th.
3768 pFunctionStack
[ nFunction
].eOp
== ocAddress
&&
3769 pFunctionStack
[ nFunction
].nPar
== 3)
3771 if (!static_cast<ScTokenArray
*>(pArr
)->Add( new FormulaToken( svSep
,ocSep
)) ||
3772 !static_cast<ScTokenArray
*>(pArr
)->Add( new FormulaDoubleToken( 1.0)))
3774 SetError(errCodeOverflow
); break;
3776 ++pFunctionStack
[ nFunction
].nPar
;
3779 FormulaToken
* pNewToken
= static_cast<ScTokenArray
*>(pArr
)->Add( pRawToken
->CreateToken());
3782 SetError(errCodeOverflow
); break;
3784 else if (eLastOp
== ocRange
&& pNewToken
->GetOpCode() == ocPush
&&
3785 pNewToken
->GetType() == svSingleRef
)
3786 static_cast<ScTokenArray
*>(pArr
)->MergeRangeReference( aPos
);
3787 eLastOp
= pRawToken
->GetOpCode();
3789 aCorrectedFormula
+= aCorrectedSymbol
;
3791 if ( mbCloseBrackets
)
3795 FormulaByteToken
aToken( ocArrayClose
);
3796 if( !pArr
->AddToken( aToken
) )
3798 SetError(errCodeOverflow
);
3800 else if ( bAutoCorrect
)
3801 aCorrectedFormula
+= mxSymbols
->getSymbol(ocArrayClose
);
3804 FormulaByteToken
aToken( ocClose
);
3805 while( nBrackets
-- )
3807 if( !pArr
->AddToken( aToken
) )
3809 SetError(errCodeOverflow
); break;
3812 aCorrectedFormula
+= mxSymbols
->getSymbol(ocClose
);
3816 pArr
->SetRecalcModeForced();
3818 if (pFunctionStack
!= &aFuncs
[0])
3819 delete [] pFunctionStack
;
3821 // remember pArr, in case a subsequent CompileTokenArray() is executed.
3822 ScTokenArray
* pNew
= new ScTokenArray( aArr
);
3828 ScTokenArray
* ScCompiler::CompileString( const String
& rFormula
, const String
& rFormulaNmsp
)
3830 DBG_ASSERT( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL
) || (rFormulaNmsp
.Len() == 0),
3831 "ScCompiler::CompileString - unexpected formula namespace for internal grammar" );
3832 if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL
) try
3834 ScFormulaParserPool
& rParserPool
= pDoc
->GetFormulaParserPool();
3835 uno::Reference
< sheet::XFormulaParser
> xParser( rParserPool
.getFormulaParser( rFormulaNmsp
), uno::UNO_SET_THROW
);
3836 table::CellAddress aReferencePos
;
3837 ScUnoConversion::FillApiAddress( aReferencePos
, aPos
);
3838 uno::Sequence
< sheet::FormulaToken
> aTokenSeq
= xParser
->parseFormula( rFormula
, aReferencePos
);
3839 ScTokenArray aTokenArray
;
3840 if( ScTokenConversion::ConvertToTokenArray( *pDoc
, aTokenArray
, aTokenSeq
) )
3842 // remember pArr, in case a subsequent CompileTokenArray() is executed.
3843 ScTokenArray
* pNew
= new ScTokenArray( aTokenArray
);
3848 catch( uno::Exception
& )
3851 // no success - fallback to some internal grammar and hope the best
3852 return CompileString( rFormula
);
3856 BOOL
ScCompiler::HandleRange()
3858 ScRangeData
* pRangeData
= pDoc
->GetRangeName()->FindIndex( pToken
->GetIndex() );
3861 USHORT nErr
= pRangeData
->GetErrCode();
3863 SetError( errNoName
);
3864 else if ( !bCompileForFAP
)
3867 // #35168# put named formula into parentheses.
3868 // #37680# But only if there aren't any yet, parenthetical
3869 // ocSep doesn't work, e.g. SUM((...;...))
3870 // or if not directly between ocSep/parenthesis,
3871 // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes,
3872 // in short: if it isn't a self-contained expression.
3873 FormulaToken
* p1
= pArr
->PeekPrevNoSpaces();
3874 FormulaToken
* p2
= pArr
->PeekNextNoSpaces();
3875 OpCode eOp1
= (p1
? p1
->GetOpCode() : static_cast<OpCode
>( ocSep
) );
3876 OpCode eOp2
= (p2
? p2
->GetOpCode() : static_cast<OpCode
>( ocSep
) );
3877 BOOL bBorder1
= (eOp1
== ocSep
|| eOp1
== ocOpen
);
3878 BOOL bBorder2
= (eOp2
== ocSep
|| eOp2
== ocClose
);
3879 BOOL bAddPair
= !(bBorder1
&& bBorder2
);
3882 pNew
= new ScTokenArray();
3883 pNew
->AddOpCode( ocClose
);
3884 PushTokenArray( pNew
, TRUE
);
3887 pNew
= pRangeData
->GetCode()->Clone();
3888 PushTokenArray( pNew
, TRUE
);
3889 if( pRangeData
->HasReferences() )
3891 SetRelNameReference();
3892 MoveRelWrap(pRangeData
->GetMaxCol(), pRangeData
->GetMaxRow());
3897 pNew
= new ScTokenArray();
3898 pNew
->AddOpCode( ocOpen
);
3899 PushTokenArray( pNew
, TRUE
);
3906 SetError(errNoName
);
3909 // -----------------------------------------------------------------------------
3910 BOOL
ScCompiler::HandleExternalReference(const FormulaToken
& _aToken
)
3912 // Handle external range names.
3913 switch (_aToken
.GetType())
3915 case svExternalSingleRef
:
3916 case svExternalDoubleRef
:
3917 pArr
->IncrementRefs();
3919 case svExternalName
:
3921 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
3922 const String
* pFile
= pRefMgr
->getExternalFileName(_aToken
.GetIndex());
3925 SetError(errNoName
);
3929 const String
& rName
= _aToken
.GetString();
3930 ScExternalRefCache::TokenArrayRef xNew
= pRefMgr
->getRangeNameTokens(
3931 _aToken
.GetIndex(), rName
, &aPos
);
3935 SetError(errNoName
);
3939 ScTokenArray
* pNew
= xNew
->Clone();
3940 PushTokenArray( pNew
, true);
3941 if (pNew
->GetNextReference() != NULL
)
3943 SetRelNameReference();
3944 MoveRelWrap(MAXCOL
, MAXROW
);
3950 DBG_ERROR("Wrong type for external reference!");
3957 //---------------------------------------------------------------------------
3960 //---------------------------------------------------------------------------
3961 // Append token to RPN code
3962 //---------------------------------------------------------------------------
3965 //-----------------------------------------------------------------------------
3967 //---------------------------------------------------------------------------
3968 // RPN creation by recursion
3969 //---------------------------------------------------------------------------
3973 //-----------------------------------------------------------------------------
3975 BOOL
ScCompiler::HasModifiedRange()
3978 for ( FormulaToken
* t
= pArr
->Next(); t
; t
= pArr
->Next() )
3980 OpCode eOpCode
= t
->GetOpCode();
3981 if ( eOpCode
== ocName
)
3983 ScRangeData
* pRangeData
= pDoc
->GetRangeName()->FindIndex(t
->GetIndex());
3985 if (pRangeData
&& pRangeData
->IsModified())
3988 else if ( eOpCode
== ocDBArea
)
3990 ScDBData
* pDBData
= pDoc
->GetDBCollection()->FindIndex(t
->GetIndex());
3992 if (pDBData
&& pDBData
->IsModified())
4000 //---------------------------------------------------------------------------
4002 template< typename T
, typename S
>
4003 S
lcl_adjval( S
& n
, T pos
, T max
, BOOL bRel
)
4007 n
= sal::static_int_cast
<S
>( n
+ pos
);
4009 n
= sal::static_int_cast
<S
>( n
+ max
);
4011 n
= sal::static_int_cast
<S
>( n
- max
);
4013 n
= sal::static_int_cast
<S
>( n
- pos
);
4017 // reference of named range with relative references
4019 void ScCompiler::SetRelNameReference()
4022 for( ScToken
* t
= static_cast<ScToken
*>(pArr
->GetNextReference()); t
;
4023 t
= static_cast<ScToken
*>(pArr
->GetNextReference()) )
4025 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4026 if ( rRef1
.IsColRel() || rRef1
.IsRowRel() || rRef1
.IsTabRel() )
4027 rRef1
.SetRelName( TRUE
);
4028 if ( t
->GetType() == svDoubleRef
)
4030 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4031 if ( rRef2
.IsColRel() || rRef2
.IsRowRel() || rRef2
.IsTabRel() )
4032 rRef2
.SetRelName( TRUE
);
4037 // Wrap-adjust relative references of a RangeName to current position,
4038 // don't call for other token arrays!
4039 void ScCompiler::MoveRelWrap( SCCOL nMaxCol
, SCROW nMaxRow
)
4042 for( ScToken
* t
= static_cast<ScToken
*>(pArr
->GetNextReference()); t
;
4043 t
= static_cast<ScToken
*>(pArr
->GetNextReference()) )
4045 if ( t
->GetType() == svSingleRef
|| t
->GetType() == svExternalSingleRef
)
4046 ScRefUpdate::MoveRelWrap( pDoc
, aPos
, nMaxCol
, nMaxRow
, SingleDoubleRefModifier( t
->GetSingleRef() ).Ref() );
4048 ScRefUpdate::MoveRelWrap( pDoc
, aPos
, nMaxCol
, nMaxRow
, t
->GetDoubleRef() );
4053 // Wrap-adjust relative references of a RangeName to current position,
4054 // don't call for other token arrays!
4055 void ScCompiler::MoveRelWrap( ScTokenArray
& rArr
, ScDocument
* pDoc
, const ScAddress
& rPos
,
4056 SCCOL nMaxCol
, SCROW nMaxRow
)
4059 for( ScToken
* t
= static_cast<ScToken
*>(rArr
.GetNextReference()); t
;
4060 t
= static_cast<ScToken
*>(rArr
.GetNextReference()) )
4062 if ( t
->GetType() == svSingleRef
|| t
->GetType() == svExternalSingleRef
)
4063 ScRefUpdate::MoveRelWrap( pDoc
, rPos
, nMaxCol
, nMaxRow
, SingleDoubleRefModifier( t
->GetSingleRef() ).Ref() );
4065 ScRefUpdate::MoveRelWrap( pDoc
, rPos
, nMaxCol
, nMaxRow
, t
->GetDoubleRef() );
4069 ScRangeData
* ScCompiler::UpdateReference(UpdateRefMode eUpdateRefMode
,
4070 const ScAddress
& rOldPos
, const ScRange
& r
,
4071 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
4072 BOOL
& rChanged
, BOOL
& rRefSizeChanged
)
4074 rChanged
= rRefSizeChanged
= FALSE
;
4075 if ( eUpdateRefMode
== URM_COPY
)
4076 { // Normally nothing has to be done here since RelRefs are used, also
4077 // SharedFormulas don't need any special handling, except if they
4078 // wrapped around sheet borders.
4079 // #67383# But ColRowName tokens pointing to a ColRow header which was
4080 // copied along with this formula need to be updated to point to the
4081 // copied header instead of the old position's new intersection.
4084 while( (t
= static_cast<ScToken
*>(pArr
->GetNextColRowName())) != NULL
)
4086 ScSingleRefData
& rRef
= t
->GetSingleRef();
4087 rRef
.CalcAbsIfRel( rOldPos
);
4088 ScAddress
aNewRef( rRef
.nCol
+ nDx
, rRef
.nRow
+ nDy
, rRef
.nTab
+ nDz
);
4089 if ( r
.In( aNewRef
) )
4090 { // yes, this is URM_MOVE
4091 if ( ScRefUpdate::Update( pDoc
, URM_MOVE
, aPos
,
4093 SingleDoubleRefModifier( rRef
).Ref() )
4099 // Check for SharedFormulas.
4100 ScRangeData
* pRangeData
= NULL
;
4102 for( FormulaToken
* j
= pArr
->GetNextName(); j
&& !pRangeData
;
4103 j
= pArr
->GetNextName() )
4105 if( j
->GetOpCode() == ocName
)
4107 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex( j
->GetIndex() );
4108 if (pName
&& pName
->HasType(RT_SHARED
))
4112 // Check SharedFormulas for wraps.
4115 ScRangeData
* pName
= pRangeData
;
4118 for( t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN()); t
&& !pRangeData
;
4119 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN()) )
4121 BOOL bRelName
= (t
->GetType() == svSingleRef
?
4122 t
->GetSingleRef().IsRelName() :
4123 (t
->GetDoubleRef().Ref1
.IsRelName() ||
4124 t
->GetDoubleRef().Ref2
.IsRelName()));
4127 t
->CalcAbsIfRel( rOldPos
);
4128 BOOL bValid
= (t
->GetType() == svSingleRef
?
4129 t
->GetSingleRef().Valid() :
4130 t
->GetDoubleRef().Valid());
4131 // If the reference isn't valid, copying the formula
4132 // wrapped it. Replace SharedFormula.
4146 * Set SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE to 1 if we wanted to preserve as
4147 * many shared formulas as possible instead of replacing them with direct code.
4148 * Note that this may produce shared formula usage Excel doesn't understand,
4149 * which would have to be adapted for in the export filter. Advisable as a long
4150 * term goal, since it could decrease memory footprint.
4152 #define SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE 0
4153 ScRangeData
* pRangeData
= NULL
;
4156 while( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName())) != NULL
)
4158 if( t
->GetOpCode() == ocName
)
4160 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex( t
->GetIndex() );
4161 if (pName
&& pName
->HasType(RT_SHAREDMOD
))
4163 pRangeData
= pName
; // maybe need a replacement of shared with own code
4164 #if ! SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4169 else if( t
->GetType() != svIndex
) // it may be a DB area!!!
4171 t
->CalcAbsIfRel( rOldPos
);
4172 switch (t
->GetType())
4174 case svExternalSingleRef
:
4175 case svExternalDoubleRef
:
4176 // External references never change their positioning
4177 // nor point to parts that will be removed or expanded.
4178 // In fact, calling ScRefUpdate::Update() for URM_MOVE
4179 // may have negative side effects. Simply adapt
4180 // relative references to the new position.
4181 t
->CalcRelFromAbs( aPos
);
4185 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
4186 aPos
, r
, nDx
, nDy
, nDz
,
4187 SingleDoubleRefModifier(
4188 t
->GetSingleRef()).Ref())
4195 ScComplexRefData
& rRef
= t
->GetDoubleRef();
4196 SCCOL nCols
= rRef
.Ref2
.nCol
- rRef
.Ref1
.nCol
;
4197 SCROW nRows
= rRef
.Ref2
.nRow
- rRef
.Ref1
.nRow
;
4198 SCTAB nTabs
= rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
;
4199 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
4200 aPos
, r
, nDx
, nDy
, nDz
,
4201 t
->GetDoubleRef()) != UR_NOTHING
)
4204 if (rRef
.Ref2
.nCol
- rRef
.Ref1
.nCol
!= nCols
||
4205 rRef
.Ref2
.nRow
- rRef
.Ref1
.nRow
!= nRows
||
4206 rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
!= nTabs
)
4207 rRefSizeChanged
= TRUE
;
4213 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4214 BOOL bEasyShared
, bPosInRange
;
4216 bEasyShared
= bPosInRange
= FALSE
;
4220 bPosInRange
= r
.In( eUpdateRefMode
== URM_MOVE
? aPos
: rOldPos
);
4224 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN())) != NULL
)
4226 if ( t
->GetRef() != 1 )
4228 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4229 bEasyShared
= FALSE
;
4233 { // if nRefCnt>1 it's already updated in token code
4234 if ( t
->GetType() == svSingleRef
)
4236 ScSingleRefData
& rRef
= t
->GetSingleRef();
4237 SingleDoubleRefModifier
aMod( rRef
);
4238 if ( rRef
.IsRelName() )
4240 ScRefUpdate::MoveRelWrap( pDoc
, aPos
, MAXCOL
, MAXROW
, aMod
.Ref() );
4245 aMod
.Ref().CalcAbsIfRel( rOldPos
);
4246 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
, aPos
,
4247 r
, nDx
, nDy
, nDz
, aMod
.Ref() )
4252 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4255 const ScSingleRefData
& rSRD
= aMod
.Ref().Ref1
;
4256 ScAddress
aRef( rSRD
.nCol
, rSRD
.nRow
, rSRD
.nTab
);
4257 if ( r
.In( aRef
) != bPosInRange
)
4258 bEasyShared
= FALSE
;
4264 ScComplexRefData
& rRef
= t
->GetDoubleRef();
4265 SCCOL nCols
= rRef
.Ref2
.nCol
- rRef
.Ref1
.nCol
;
4266 SCROW nRows
= rRef
.Ref2
.nRow
- rRef
.Ref1
.nRow
;
4267 SCTAB nTabs
= rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
;
4268 if ( rRef
.Ref1
.IsRelName() || rRef
.Ref2
.IsRelName() )
4270 ScRefUpdate::MoveRelWrap( pDoc
, aPos
, MAXCOL
, MAXROW
, rRef
);
4275 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
, aPos
,
4276 r
, nDx
, nDy
, nDz
, rRef
)
4281 if (rRef
.Ref2
.nCol
- rRef
.Ref1
.nCol
!= nCols
||
4282 rRef
.Ref2
.nRow
- rRef
.Ref1
.nRow
!= nRows
||
4283 rRef
.Ref2
.nTab
- rRef
.Ref1
.nTab
!= nTabs
)
4285 rRefSizeChanged
= TRUE
;
4286 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4287 bEasyShared
= FALSE
;
4292 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4295 ScRange
aRef( rRef
.Ref1
.nCol
, rRef
.Ref1
.nRow
,
4296 rRef
.Ref1
.nTab
, rRef
.Ref2
.nCol
, rRef
.Ref2
.nRow
,
4298 if ( r
.In( aRef
) != bPosInRange
)
4299 bEasyShared
= FALSE
;
4305 #if SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4314 #undef SC_PRESERVE_SHARED_FORMULAS_IF_POSSIBLE
4319 BOOL
ScCompiler::UpdateNameReference(UpdateRefMode eUpdateRefMode
,
4321 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
4322 BOOL
& rChanged
, BOOL bSharedFormula
)
4324 BOOL bRelRef
= FALSE
; // set if relative reference
4328 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReference())) != NULL
)
4330 SingleDoubleRefModifier
aMod( *t
);
4331 ScComplexRefData
& rRef
= aMod
.Ref();
4332 bRelRef
= rRef
.Ref1
.IsColRel() || rRef
.Ref1
.IsRowRel() ||
4333 rRef
.Ref1
.IsTabRel();
4334 if (!bRelRef
&& t
->GetType() == svDoubleRef
)
4335 bRelRef
= rRef
.Ref2
.IsColRel() || rRef
.Ref2
.IsRowRel() ||
4336 rRef
.Ref2
.IsTabRel();
4337 bool bUpdate
= !rRef
.Ref1
.IsColRel() || !rRef
.Ref1
.IsRowRel() ||
4338 !rRef
.Ref1
.IsTabRel();
4339 if (!bUpdate
&& t
->GetType() == svDoubleRef
)
4340 bUpdate
= !rRef
.Ref2
.IsColRel() || !rRef
.Ref2
.IsRowRel() ||
4341 !rRef
.Ref2
.IsTabRel();
4342 if (!bSharedFormula
)
4344 // We cannot update names with sheet-relative references, they may
4345 // be used on other sheets as well and the resulting reference
4346 // would be wrong. This is a dilemma if col/row would need to be
4347 // updated for the current usage.
4348 // TODO: seems the only way out of this would be to not allow
4349 // relative sheet references and have sheet-local names that can be
4350 // copied along with sheets.
4351 bUpdate
= bUpdate
&& !rRef
.Ref1
.IsTabRel() && !rRef
.Ref2
.IsTabRel();
4355 rRef
.CalcAbsIfRel( aPos
);
4356 if (ScRefUpdate::Update( pDoc
, eUpdateRefMode
, aPos
, r
,
4357 nDx
, nDy
, nDz
, rRef
, ScRefUpdate::ABSOLUTE
)
4366 void ScCompiler::UpdateSharedFormulaReference( UpdateRefMode eUpdateRefMode
,
4367 const ScAddress
& rOldPos
, const ScRange
& r
,
4368 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
4370 if ( eUpdateRefMode
== URM_COPY
)
4376 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReference())) != NULL
)
4378 if( t
->GetType() != svIndex
) // it may be a DB area!!!
4380 t
->CalcAbsIfRel( rOldPos
);
4381 // Absolute references have been already adjusted in the named
4382 // shared formula itself prior to breaking the shared formula
4383 // and calling this function. Don't readjust them again.
4384 SingleDoubleRefModifier
aMod( *t
);
4385 ScComplexRefData
& rRef
= aMod
.Ref();
4386 ScComplexRefData aBkp
= rRef
;
4387 ScRefUpdate::Update( pDoc
, eUpdateRefMode
, aPos
,
4388 r
, nDx
, nDy
, nDz
, rRef
);
4389 // restore absolute parts
4390 if ( !aBkp
.Ref1
.IsColRel() )
4392 rRef
.Ref1
.nCol
= aBkp
.Ref1
.nCol
;
4393 rRef
.Ref1
.nRelCol
= aBkp
.Ref1
.nRelCol
;
4394 rRef
.Ref1
.SetColDeleted( aBkp
.Ref1
.IsColDeleted() );
4396 if ( !aBkp
.Ref1
.IsRowRel() )
4398 rRef
.Ref1
.nRow
= aBkp
.Ref1
.nRow
;
4399 rRef
.Ref1
.nRelRow
= aBkp
.Ref1
.nRelRow
;
4400 rRef
.Ref1
.SetRowDeleted( aBkp
.Ref1
.IsRowDeleted() );
4402 if ( !aBkp
.Ref1
.IsTabRel() )
4404 rRef
.Ref1
.nTab
= aBkp
.Ref1
.nTab
;
4405 rRef
.Ref1
.nRelTab
= aBkp
.Ref1
.nRelTab
;
4406 rRef
.Ref1
.SetTabDeleted( aBkp
.Ref1
.IsTabDeleted() );
4408 if ( t
->GetType() == svDoubleRef
)
4410 if ( !aBkp
.Ref2
.IsColRel() )
4412 rRef
.Ref2
.nCol
= aBkp
.Ref2
.nCol
;
4413 rRef
.Ref2
.nRelCol
= aBkp
.Ref2
.nRelCol
;
4414 rRef
.Ref2
.SetColDeleted( aBkp
.Ref2
.IsColDeleted() );
4416 if ( !aBkp
.Ref2
.IsRowRel() )
4418 rRef
.Ref2
.nRow
= aBkp
.Ref2
.nRow
;
4419 rRef
.Ref2
.nRelRow
= aBkp
.Ref2
.nRelRow
;
4420 rRef
.Ref2
.SetRowDeleted( aBkp
.Ref2
.IsRowDeleted() );
4422 if ( !aBkp
.Ref2
.IsTabRel() )
4424 rRef
.Ref2
.nTab
= aBkp
.Ref2
.nTab
;
4425 rRef
.Ref2
.nRelTab
= aBkp
.Ref2
.nRelTab
;
4426 rRef
.Ref2
.SetTabDeleted( aBkp
.Ref2
.IsTabDeleted() );
4435 ScRangeData
* ScCompiler::UpdateInsertTab( SCTAB nTable
, BOOL bIsName
)
4437 ScRangeData
* pRangeData
= NULL
;
4438 SCTAB nPosTab
= aPos
.Tab(); // _after_ incremented!
4439 SCTAB nOldPosTab
= ((nPosTab
> nTable
) ? (nPosTab
- 1) : nPosTab
);
4440 BOOL bIsRel
= FALSE
;
4444 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4446 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4449 if( t
->GetOpCode() == ocName
)
4453 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex(t
->GetIndex());
4454 if (pName
&& pName
->HasType(RT_SHAREDMOD
))
4458 else if( t
->GetType() != svIndex
) // it may be a DB area!!!
4460 if ( !(bIsName
&& t
->GetSingleRef().IsTabRel()) )
4461 { // of names only adjust absolute references
4462 ScSingleRefData
& rRef
= t
->GetSingleRef();
4463 if ( rRef
.IsTabRel() )
4465 rRef
.nTab
= rRef
.nRelTab
+ nOldPosTab
;
4466 if ( rRef
.nTab
< 0 )
4467 rRef
.nTab
= sal::static_int_cast
<SCsTAB
>( rRef
.nTab
+ pDoc
->GetTableCount() ); // was a wrap
4469 if (nTable
<= rRef
.nTab
)
4471 rRef
.nRelTab
= rRef
.nTab
- nPosTab
;
4475 if ( t
->GetType() == svDoubleRef
)
4477 if ( !(bIsName
&& t
->GetDoubleRef().Ref2
.IsTabRel()) )
4478 { // of names only adjust absolute references
4479 ScSingleRefData
& rRef
= t
->GetDoubleRef().Ref2
;
4480 if ( rRef
.IsTabRel() )
4482 rRef
.nTab
= rRef
.nRelTab
+ nOldPosTab
;
4483 if ( rRef
.nTab
< 0 )
4484 rRef
.nTab
= sal::static_int_cast
<SCsTAB
>( rRef
.nTab
+ pDoc
->GetTableCount() ); // was a wrap
4486 if (nTable
<= rRef
.nTab
)
4488 rRef
.nRelTab
= rRef
.nTab
- nPosTab
;
4493 if ( bIsName
&& bIsRel
)
4494 pRangeData
= (ScRangeData
*) this; // not dereferenced in rangenam
4497 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4499 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4504 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN())) != NULL
)
4506 if ( t
->GetRef() == 1 )
4508 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4509 if ( !(rRef1
.IsRelName() && rRef1
.IsTabRel()) )
4510 { // of names only adjust absolute references
4511 if ( rRef1
.IsTabRel() )
4513 rRef1
.nTab
= rRef1
.nRelTab
+ nOldPosTab
;
4514 if ( rRef1
.nTab
< 0 )
4515 rRef1
.nTab
= sal::static_int_cast
<SCsTAB
>( rRef1
.nTab
+ pDoc
->GetTableCount() ); // was a wrap
4517 if (nTable
<= rRef1
.nTab
)
4519 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4521 if ( t
->GetType() == svDoubleRef
)
4523 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4524 if ( !(rRef2
.IsRelName() && rRef2
.IsTabRel()) )
4525 { // of names only adjust absolute references
4526 if ( rRef2
.IsTabRel() )
4528 rRef2
.nTab
= rRef2
.nRelTab
+ nOldPosTab
;
4529 if ( rRef2
.nTab
< 0 )
4530 rRef2
.nTab
= sal::static_int_cast
<SCsTAB
>( rRef2
.nTab
+ pDoc
->GetTableCount() ); // was a wrap
4532 if (nTable
<= rRef2
.nTab
)
4534 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4543 ScRangeData
* ScCompiler::UpdateDeleteTab(SCTAB nTable
, BOOL
/* bIsMove */, BOOL bIsName
,
4546 ScRangeData
* pRangeData
= NULL
;
4548 SCTAB nPosTab
= aPos
.Tab(); // _after_ decremented!
4549 SCTAB nOldPosTab
= ((nPosTab
>= nTable
) ? (nPosTab
+ 1) : nPosTab
);
4551 BOOL bIsRel
= FALSE
;
4555 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4557 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4560 if( t
->GetOpCode() == ocName
)
4564 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex(t
->GetIndex());
4565 if (pName
&& pName
->HasType(RT_SHAREDMOD
))
4570 else if( t
->GetType() != svIndex
) // it may be a DB area!!!
4572 if ( !(bIsName
&& t
->GetSingleRef().IsTabRel()) )
4573 { // of names only adjust absolute references
4574 ScSingleRefData
& rRef
= t
->GetSingleRef();
4575 if ( rRef
.IsTabRel() )
4576 nTab
= rRef
.nTab
= rRef
.nRelTab
+ nOldPosTab
;
4579 if ( nTable
< nTab
)
4581 rRef
.nTab
= nTab
- 1;
4584 else if ( nTable
== nTab
)
4586 if ( t
->GetType() == svDoubleRef
)
4588 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4589 if ( rRef2
.IsTabRel() )
4590 nTab2
= rRef2
.nRelTab
+ nOldPosTab
;
4594 || (nTab
+1) >= pDoc
->GetTableCount() )
4596 rRef
.nTab
= MAXTAB
+1;
4597 rRef
.SetTabDeleted( TRUE
);
4599 // else: nTab later points to what's nTable+1 now
4604 rRef
.nTab
= MAXTAB
+1;
4605 rRef
.SetTabDeleted( TRUE
);
4609 rRef
.nRelTab
= rRef
.nTab
- nPosTab
;
4613 if ( t
->GetType() == svDoubleRef
)
4615 if ( !(bIsName
&& t
->GetDoubleRef().Ref2
.IsTabRel()) )
4616 { // of names only adjust absolute references
4617 ScSingleRefData
& rRef
= t
->GetDoubleRef().Ref2
;
4618 if ( rRef
.IsTabRel() )
4619 nTab
= rRef
.nTab
= rRef
.nRelTab
+ nOldPosTab
;
4622 if ( nTable
< nTab
)
4624 rRef
.nTab
= nTab
- 1;
4627 else if ( nTable
== nTab
)
4629 if ( !t
->GetDoubleRef().Ref1
.IsTabDeleted() )
4630 rRef
.nTab
= nTab
- 1; // shrink area
4633 rRef
.nTab
= MAXTAB
+1;
4634 rRef
.SetTabDeleted( TRUE
);
4638 rRef
.nRelTab
= rRef
.nTab
- nPosTab
;
4643 if ( bIsName
&& bIsRel
)
4644 pRangeData
= (ScRangeData
*) this; // not dereferenced in rangenam
4647 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4649 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4654 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN())) != NULL
)
4656 if ( t
->GetRef() == 1 )
4658 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4659 if ( !(rRef1
.IsRelName() && rRef1
.IsTabRel()) )
4660 { // of names only adjust absolute references
4661 if ( rRef1
.IsTabRel() )
4662 nTab
= rRef1
.nTab
= rRef1
.nRelTab
+ nOldPosTab
;
4665 if ( nTable
< nTab
)
4667 rRef1
.nTab
= nTab
- 1;
4670 else if ( nTable
== nTab
)
4672 if ( t
->GetType() == svDoubleRef
)
4674 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4675 if ( rRef2
.IsTabRel() )
4676 nTab2
= rRef2
.nRelTab
+ nOldPosTab
;
4680 || (nTab
+1) >= pDoc
->GetTableCount() )
4682 rRef1
.nTab
= MAXTAB
+1;
4683 rRef1
.SetTabDeleted( TRUE
);
4685 // else: nTab later points to what's nTable+1 now
4690 rRef1
.nTab
= MAXTAB
+1;
4691 rRef1
.SetTabDeleted( TRUE
);
4695 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4697 if ( t
->GetType() == svDoubleRef
)
4699 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4700 if ( !(rRef2
.IsRelName() && rRef2
.IsTabRel()) )
4701 { // of names only adjust absolute references
4702 if ( rRef2
.IsTabRel() )
4703 nTab
= rRef2
.nTab
= rRef2
.nRelTab
+ nOldPosTab
;
4706 if ( nTable
< nTab
)
4708 rRef2
.nTab
= nTab
- 1;
4711 else if ( nTable
== nTab
)
4713 if ( !rRef1
.IsTabDeleted() )
4714 rRef2
.nTab
= nTab
- 1; // shrink area
4717 rRef2
.nTab
= MAXTAB
+1;
4718 rRef2
.SetTabDeleted( TRUE
);
4722 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4731 // aPos.Tab() must be already adjusted!
4732 ScRangeData
* ScCompiler::UpdateMoveTab( SCTAB nOldTab
, SCTAB nNewTab
,
4735 ScRangeData
* pRangeData
= NULL
;
4739 short nDir
; // direction in which others move
4740 if ( nOldTab
< nNewTab
)
4752 SCTAB nPosTab
= aPos
.Tab(); // current sheet
4753 SCTAB nOldPosTab
; // previously it was this one
4754 if ( nPosTab
== nNewTab
)
4755 nOldPosTab
= nOldTab
; // look, it's me!
4756 else if ( nPosTab
< nStart
|| nEnd
< nPosTab
)
4757 nOldPosTab
= nPosTab
; // wasn't moved
4759 nOldPosTab
= nPosTab
- nDir
; // moved by one
4761 BOOL bIsRel
= FALSE
;
4765 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4767 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4770 if( t
->GetOpCode() == ocName
)
4774 ScRangeData
* pName
= pDoc
->GetRangeName()->FindIndex(t
->GetIndex());
4775 if (pName
&& pName
->HasType(RT_SHAREDMOD
))
4779 else if( t
->GetType() != svIndex
) // it may be a DB area!!!
4781 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4782 if ( !(bIsName
&& rRef1
.IsTabRel()) )
4783 { // of names only adjust absolute references
4784 if ( rRef1
.IsTabRel() )
4785 nTab
= rRef1
.nRelTab
+ nOldPosTab
;
4788 if ( nTab
== nOldTab
)
4789 rRef1
.nTab
= nNewTab
;
4790 else if ( nStart
<= nTab
&& nTab
<= nEnd
)
4791 rRef1
.nTab
= nTab
+ nDir
;
4792 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4796 if ( t
->GetType() == svDoubleRef
)
4798 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4799 if ( !(bIsName
&& rRef2
.IsTabRel()) )
4800 { // of names only adjust absolute references
4801 if ( rRef2
.IsTabRel() )
4802 nTab
= rRef2
.nRelTab
+ nOldPosTab
;
4805 if ( nTab
== nOldTab
)
4806 rRef2
.nTab
= nNewTab
;
4807 else if ( nStart
<= nTab
&& nTab
<= nEnd
)
4808 rRef2
.nTab
= nTab
+ nDir
;
4809 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4813 SCsTAB nTab1
, nTab2
;
4814 if ( rRef1
.IsTabRel() )
4815 nTab1
= rRef1
.nRelTab
+ nPosTab
;
4818 if ( rRef2
.IsTabRel() )
4819 nTab2
= rRef2
.nRelTab
+ nPosTab
;
4822 if ( nTab2
< nTab1
)
4826 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4827 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4830 if ( bIsName
&& bIsRel
)
4831 pRangeData
= (ScRangeData
*) this; // not dereferenced in rangenam
4834 t
= static_cast<ScToken
*>(pArr
->GetNextReference());
4836 t
= static_cast<ScToken
*>(pArr
->GetNextReferenceOrName());
4840 SCsTAB nMaxTabMod
= (SCsTAB
) pDoc
->GetTableCount();
4842 while ( (t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN())) != NULL
)
4844 if ( t
->GetRef() == 1 )
4846 ScSingleRefData
& rRef1
= t
->GetSingleRef();
4847 if ( rRef1
.IsRelName() && rRef1
.IsTabRel() )
4848 { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx
4849 nTab
= rRef1
.nRelTab
+ nPosTab
;
4851 nTab
= sal::static_int_cast
<SCsTAB
>( nTab
+ nMaxTabMod
);
4852 else if ( nTab
> nMaxTab
)
4853 nTab
= sal::static_int_cast
<SCsTAB
>( nTab
- nMaxTabMod
);
4854 rRef1
.nRelTab
= nTab
- nPosTab
;
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
;
4868 if( t
->GetType() == svDoubleRef
)
4870 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
4871 if ( rRef2
.IsRelName() && rRef2
.IsTabRel() )
4872 { // possibly wrap RelName, like lcl_MoveItWrap in refupdat.cxx
4873 nTab
= rRef2
.nRelTab
+ nPosTab
;
4875 nTab
= sal::static_int_cast
<SCsTAB
>( nTab
+ nMaxTabMod
);
4876 else if ( nTab
> nMaxTab
)
4877 nTab
= sal::static_int_cast
<SCsTAB
>( nTab
- nMaxTabMod
);
4878 rRef2
.nRelTab
= nTab
- nPosTab
;
4882 if ( rRef2
.IsTabRel() )
4883 nTab
= rRef2
.nRelTab
+ nOldPosTab
;
4886 if ( nTab
== nOldTab
)
4887 rRef2
.nTab
= nNewTab
;
4888 else if ( nStart
<= nTab
&& nTab
<= nEnd
)
4889 rRef2
.nTab
= nTab
+ nDir
;
4890 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4892 SCsTAB nTab1
, nTab2
;
4893 if ( rRef1
.IsTabRel() )
4894 nTab1
= rRef1
.nRelTab
+ nPosTab
;
4897 if ( rRef2
.IsTabRel() )
4898 nTab2
= rRef2
.nRelTab
+ nPosTab
;
4901 if ( nTab2
< nTab1
)
4905 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
4906 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
4916 void ScCompiler::CreateStringFromExternal(rtl::OUStringBuffer
& rBuffer
, FormulaToken
* pTokenP
)
4918 FormulaToken
* t
= pTokenP
;
4919 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
4920 switch (t
->GetType())
4922 case svExternalName
:
4924 const String
*pStr
= pRefMgr
->getExternalFileName(t
->GetIndex());
4925 String aFileName
= pStr
? *pStr
: ScGlobal::GetRscString(STR_NO_NAME_REF
);
4926 rBuffer
.append(pConv
->makeExternalNameStr( aFileName
, t
->GetString()));
4929 case svExternalSingleRef
:
4930 pConv
->makeExternalRefStr(
4931 rBuffer
, *this, t
->GetIndex(), t
->GetString(), static_cast<ScToken
*>(t
)->GetSingleRef(), pRefMgr
);
4933 case svExternalDoubleRef
:
4934 pConv
->makeExternalRefStr(
4935 rBuffer
, *this, t
->GetIndex(), t
->GetString(), static_cast<ScToken
*>(t
)->GetDoubleRef(), pRefMgr
);
4938 // warning, not error, otherwise we may end up with a never
4939 // ending message box loop if this was the cursor cell to be redrawn.
4940 DBG_WARNING("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef");
4944 void ScCompiler::CreateStringFromMatrix( rtl::OUStringBuffer
& rBuffer
,
4945 FormulaToken
* pTokenP
)
4947 const ScMatrix
* pMatrix
= static_cast<ScToken
*>(pTokenP
)->GetMatrix();
4948 SCSIZE nC
, nMaxC
, nR
, nMaxR
;
4950 pMatrix
->GetDimensions( nMaxC
, nMaxR
);
4952 rBuffer
.append( mxSymbols
->getSymbol(ocArrayOpen
) );
4953 for( nR
= 0 ; nR
< nMaxR
; nR
++)
4957 rBuffer
.append( mxSymbols
->getSymbol(ocArrayRowSep
) );
4960 for( nC
= 0 ; nC
< nMaxC
; nC
++)
4964 rBuffer
.append( mxSymbols
->getSymbol(ocArrayColSep
) );
4967 if( pMatrix
->IsValue( nC
, nR
) )
4970 const ScMatrixValue
* pVal
= pMatrix
->Get( nC
, nR
, nType
);
4972 if( nType
== SC_MATVAL_BOOLEAN
)
4973 AppendBoolean( rBuffer
, pVal
->GetBoolean() );
4976 USHORT nErr
= pVal
->GetError();
4978 rBuffer
.append( ScGlobal::GetErrorString( nErr
) );
4980 AppendDouble( rBuffer
, pVal
->fVal
);
4983 else if( pMatrix
->IsEmpty( nC
, nR
) )
4985 else if( pMatrix
->IsString( nC
, nR
) )
4986 AppendString( rBuffer
, pMatrix
->GetString( nC
, nR
) );
4989 rBuffer
.append( mxSymbols
->getSymbol(ocArrayClose
) );
4992 void ScCompiler::CreateStringFromSingleRef(rtl::OUStringBuffer
& rBuffer
,FormulaToken
* _pTokenP
)
4994 const OpCode eOp
= _pTokenP
->GetOpCode();
4995 ScSingleRefData
& rRef
= static_cast<ScToken
*>(_pTokenP
)->GetSingleRef();
4996 ScComplexRefData aRef
;
4997 aRef
.Ref1
= aRef
.Ref2
= rRef
;
4998 if ( eOp
== ocColRowName
)
5000 rRef
.CalcAbsIfRel( aPos
);
5001 if ( pDoc
->HasStringData( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
) )
5004 pDoc
->GetString( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
, aStr
);
5006 rBuffer
.append(aStr
);
5010 rBuffer
.append(ScGlobal::GetRscString(STR_NO_NAME_REF
));
5011 pConv
->MakeRefStr (rBuffer
, *this, aRef
, TRUE
);
5015 pConv
->MakeRefStr( rBuffer
, *this, aRef
, TRUE
);
5017 // -----------------------------------------------------------------------------
5018 void ScCompiler::CreateStringFromDoubleRef(rtl::OUStringBuffer
& rBuffer
,FormulaToken
* _pTokenP
)
5020 pConv
->MakeRefStr( rBuffer
, *this, static_cast<ScToken
*>(_pTokenP
)->GetDoubleRef(), FALSE
);
5022 // -----------------------------------------------------------------------------
5023 void ScCompiler::CreateStringFromIndex(rtl::OUStringBuffer
& rBuffer
,FormulaToken
* _pTokenP
)
5025 const OpCode eOp
= _pTokenP
->GetOpCode();
5026 rtl::OUStringBuffer aBuffer
;
5031 ScRangeData
* pData
= pDoc
->GetRangeName()->FindIndex(_pTokenP
->GetIndex());
5034 if (pData
->HasType(RT_SHARED
))
5035 pData
->UpdateSymbol( aBuffer
, aPos
, GetGrammar());
5037 aBuffer
.append(pData
->GetName());
5043 ScDBData
* pDBData
= pDoc
->GetDBCollection()->FindIndex(_pTokenP
->GetIndex());
5045 aBuffer
.append(pDBData
->GetName());
5051 if ( aBuffer
.getLength() )
5052 rBuffer
.append(aBuffer
);
5054 rBuffer
.append(ScGlobal::GetRscString(STR_NO_NAME_REF
));
5056 // -----------------------------------------------------------------------------
5057 void ScCompiler::LocalizeString( String
& rName
)
5059 ScGlobal::GetAddInCollection()->LocalizeString( rName
);
5061 // -----------------------------------------------------------------------------
5062 BOOL
ScCompiler::IsImportingXML() const
5064 return pDoc
->IsImportingXML();
5067 // Put quotes around string if non-alphanumeric characters are contained,
5068 // quote characters contained within are escaped by '\\'.
5069 BOOL
ScCompiler::EnQuote( String
& rStr
)
5071 sal_Int32 nType
= ScGlobal::pCharClass
->getStringType( rStr
, 0, rStr
.Len() );
5072 if ( !CharClass::isNumericType( nType
)
5073 && CharClass::isAlphaNumericType( nType
) )
5076 xub_StrLen nPos
= 0;
5077 while ( (nPos
= rStr
.Search( '\'', nPos
)) != STRING_NOTFOUND
)
5079 rStr
.Insert( '\\', nPos
);
5082 rStr
.Insert( '\'', 0 );
5087 sal_Unicode
ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eType
) const
5089 return pConv
->getSpecialSymbol(eType
);
5092 void ScCompiler::fillAddInToken(::std::vector
< ::com::sun::star::sheet::FormulaOpCodeMapEntry
>& _rVec
,bool _bIsEnglish
) const
5094 // All known AddIn functions.
5095 sheet::FormulaOpCodeMapEntry aEntry
;
5096 aEntry
.Token
.OpCode
= ocExternal
;
5098 ScUnoAddInCollection
* pColl
= ScGlobal::GetAddInCollection();
5099 const long nCount
= pColl
->GetFuncCount();
5100 for (long i
=0; i
< nCount
; ++i
)
5102 const ScUnoAddInFuncData
* pFuncData
= pColl
->GetFuncData(i
);
5108 if (pFuncData
->GetExcelName( LANGUAGE_ENGLISH_US
, aName
))
5109 aEntry
.Name
= aName
;
5111 aEntry
.Name
= pFuncData
->GetUpperName();
5114 aEntry
.Name
= pFuncData
->GetUpperLocal();
5115 aEntry
.Token
.Data
<<= ::rtl::OUString( pFuncData
->GetOriginalName());
5116 _rVec
.push_back( aEntry
);
5119 // FIXME: what about those old non-UNO AddIns?
5121 // -----------------------------------------------------------------------------
5122 BOOL
ScCompiler::HandleSingleRef()
5124 ScSingleRefData
& rRef
= static_cast<ScToken
*>((FormulaToken
*)pToken
)->GetSingleRef();
5125 rRef
.CalcAbsIfRel( aPos
);
5126 if ( !rRef
.Valid() )
5128 SetError( errNoRef
);
5131 SCCOL nCol
= rRef
.nCol
;
5132 SCROW nRow
= rRef
.nRow
;
5133 SCTAB nTab
= rRef
.nTab
;
5134 ScAddress
aLook( nCol
, nRow
, nTab
);
5135 BOOL bColName
= rRef
.IsColRel();
5136 SCCOL nMyCol
= aPos
.Col();
5137 SCROW nMyRow
= aPos
.Row();
5138 BOOL bInList
= FALSE
;
5139 BOOL bValidName
= FALSE
;
5140 ScRangePairList
* pRL
= (bColName
?
5141 pDoc
->GetColNameRanges() : pDoc
->GetRowNameRanges());
5143 for ( ScRangePair
* pR
= pRL
->First(); pR
; pR
= pRL
->Next() )
5145 if ( pR
->GetRange(0).In( aLook
) )
5147 bInList
= bValidName
= TRUE
;
5148 aRange
= pR
->GetRange(1);
5151 aRange
.aStart
.SetCol( nCol
);
5152 aRange
.aEnd
.SetCol( nCol
);
5156 aRange
.aStart
.SetRow( nRow
);
5157 aRange
.aEnd
.SetRow( nRow
);
5162 if ( !bInList
&& pDoc
->GetDocOptions().IsLookUpColRowNames() )
5163 { // automagically or created by copying and NamePos isn't in list
5164 BOOL bString
= pDoc
->HasStringData( nCol
, nRow
, nTab
);
5165 if ( !bString
&& !pDoc
->GetCell( aLook
) )
5166 bString
= TRUE
; // empty cell is ok
5168 { //! coresponds with ScInterpreter::ScColRowNameAuto()
5172 SCROW nStartRow
= nRow
+ 1;
5173 if ( nStartRow
> MAXROW
)
5175 SCROW nMaxRow
= MAXROW
;
5176 if ( nMyCol
== nCol
)
5177 { // formula cell in same column
5178 if ( nMyRow
== nStartRow
)
5179 { // take remainder under name cell
5181 if ( nStartRow
> MAXROW
)
5184 else if ( nMyRow
> nStartRow
)
5185 { // from name cell down to formula cell
5186 nMaxRow
= nMyRow
- 1;
5189 for ( ScRangePair
* pR
= pRL
->First(); pR
; pR
= pRL
->Next() )
5190 { // next defined ColNameRange below limits row
5191 const ScRange
& rRange
= pR
->GetRange(1);
5192 if ( rRange
.aStart
.Col() <= nCol
&& nCol
<= rRange
.aEnd
.Col() )
5193 { // identical column range
5194 SCROW nTmp
= rRange
.aStart
.Row();
5195 if ( nStartRow
< nTmp
&& nTmp
<= nMaxRow
)
5199 aRange
.aStart
.Set( nCol
, nStartRow
, nTab
);
5200 aRange
.aEnd
.Set( nCol
, nMaxRow
, nTab
);
5204 SCCOL nStartCol
= nCol
+ 1;
5205 if ( nStartCol
> MAXCOL
)
5207 SCCOL nMaxCol
= MAXCOL
;
5208 if ( nMyRow
== nRow
)
5209 { // formula cell in same row
5210 if ( nMyCol
== nStartCol
)
5211 { // take remainder right from name cell
5213 if ( nStartCol
> MAXCOL
)
5216 else if ( nMyCol
> nStartCol
)
5217 { // from name cell right to formula cell
5218 nMaxCol
= nMyCol
- 1;
5221 for ( ScRangePair
* pR
= pRL
->First(); pR
; pR
= pRL
->Next() )
5222 { // next defined RowNameRange to the right limits column
5223 const ScRange
& rRange
= pR
->GetRange(1);
5224 if ( rRange
.aStart
.Row() <= nRow
&& nRow
<= rRange
.aEnd
.Row() )
5225 { // identical row range
5226 SCCOL nTmp
= rRange
.aStart
.Col();
5227 if ( nStartCol
< nTmp
&& nTmp
<= nMaxCol
)
5231 aRange
.aStart
.Set( nStartCol
, nRow
, nTab
);
5232 aRange
.aEnd
.Set( nMaxCol
, nRow
, nTab
);
5238 // And now the magic to distinguish between a range and a single
5239 // cell thereof, which is picked position-dependent of the formula
5240 // cell. If a direct neighbor is a binary operator (ocAdd, ...) a
5241 // SingleRef matching the column/row of the formula cell is
5242 // generated. A ocColRowName or ocIntersect as a neighbor results
5243 // in a range. Special case: if label is valid for a single cell, a
5244 // position independent SingleRef is generated.
5245 BOOL bSingle
= (aRange
.aStart
== aRange
.aEnd
);
5251 FormulaToken
* p1
= pArr
->PeekPrevNoSpaces();
5252 FormulaToken
* p2
= pArr
->PeekNextNoSpaces();
5253 // begin/end of a formula => single
5254 OpCode eOp1
= p1
? p1
->GetOpCode() : static_cast<OpCode
>( ocAdd
);
5255 OpCode eOp2
= p2
? p2
->GetOpCode() : static_cast<OpCode
>( ocAdd
);
5256 if ( eOp1
!= ocColRowName
&& eOp1
!= ocIntersect
5257 && eOp2
!= ocColRowName
&& eOp2
!= ocIntersect
)
5259 if ( (SC_OPCODE_START_BIN_OP
<= eOp1
&& eOp1
< SC_OPCODE_STOP_BIN_OP
) ||
5260 (SC_OPCODE_START_BIN_OP
<= eOp2
&& eOp2
< SC_OPCODE_STOP_BIN_OP
))
5264 { // column and/or row must match range
5267 bFound
= (aRange
.aStart
.Row() <= nMyRow
5268 && nMyRow
<= aRange
.aEnd
.Row());
5270 aRange
.aStart
.SetRow( nMyRow
);
5274 bFound
= (aRange
.aStart
.Col() <= nMyCol
5275 && nMyCol
<= aRange
.aEnd
.Col());
5277 aRange
.aStart
.SetCol( nMyCol
);
5285 else if ( !bCompileForFAP
)
5287 ScTokenArray
* pNew
= new ScTokenArray();
5290 ScSingleRefData aRefData
;
5291 aRefData
.InitAddress( aRange
.aStart
);
5293 aRefData
.SetColRel( TRUE
);
5295 aRefData
.SetRowRel( TRUE
);
5296 aRefData
.CalcRelFromAbs( aPos
);
5297 pNew
->AddSingleReference( aRefData
);
5301 ScComplexRefData aRefData
;
5302 aRefData
.InitRange( aRange
);
5305 aRefData
.Ref1
.SetColRel( TRUE
);
5306 aRefData
.Ref2
.SetColRel( TRUE
);
5310 aRefData
.Ref1
.SetRowRel( TRUE
);
5311 aRefData
.Ref2
.SetRowRel( TRUE
);
5313 aRefData
.CalcRelFromAbs( aPos
);
5315 pNew
->AddDoubleReference( aRefData
);
5318 pNew
->Add( new ScDoubleRefToken( aRefData
, ocColRowNameAuto
) );
5321 PushTokenArray( pNew
, TRUE
);
5327 SetError(errNoName
);
5330 // -----------------------------------------------------------------------------
5331 BOOL
ScCompiler::HandleDbData()
5333 ScDBData
* pDBData
= pDoc
->GetDBCollection()->FindIndex( pToken
->GetIndex() );
5335 SetError(errNoName
);
5336 else if ( !bCompileForFAP
)
5338 ScComplexRefData aRefData
;
5339 aRefData
.InitFlags();
5340 pDBData
->GetArea( (SCTAB
&) aRefData
.Ref1
.nTab
,
5341 (SCCOL
&) aRefData
.Ref1
.nCol
,
5342 (SCROW
&) aRefData
.Ref1
.nRow
,
5343 (SCCOL
&) aRefData
.Ref2
.nCol
,
5344 (SCROW
&) aRefData
.Ref2
.nRow
);
5345 aRefData
.Ref2
.nTab
= aRefData
.Ref1
.nTab
;
5346 aRefData
.CalcRelFromAbs( aPos
);
5347 ScTokenArray
* pNew
= new ScTokenArray();
5348 pNew
->AddDoubleReference( aRefData
);
5349 PushTokenArray( pNew
, TRUE
);
5356 String
GetScCompilerNativeSymbol( OpCode eOp
)
5358 return ScCompiler::GetNativeSymbol( eOp
);
5360 // -----------------------------------------------------------------------------
5361 FormulaTokenRef
ScCompiler::ExtendRangeReference( FormulaToken
& rTok1
, FormulaToken
& rTok2
, bool bReuseDoubleRef
)
5363 return ScToken::ExtendRangeReference( rTok1
, rTok2
, aPos
,bReuseDoubleRef
);