1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef SC_COMPILER_HXX
21 #define SC_COMPILER_HXX
25 #include <tools/mempool.hxx>
28 #include "refdata.hxx"
29 #include "formula/token.hxx"
30 #include "formula/grammar.hxx"
31 #include <unotools/charclass.hxx>
32 #include <rtl/ustrbuf.hxx>
33 #include <com/sun/star/sheet/ExternalLinkInfo.hpp>
36 #include <formula/FormulaCompiler.hxx>
38 #include <boost/intrusive_ptr.hpp>
39 #include <boost/unordered_map.hpp>
41 //-----------------------------------------------
43 // constants and data types also for external modules (ScInterpreter et al)
45 #define MAXSTRLEN 1024 /* maximum length of input string of one symbol */
47 // flag values of CharTable
48 #define SC_COMPILER_C_ILLEGAL 0x00000000
49 #define SC_COMPILER_C_CHAR 0x00000001
50 #define SC_COMPILER_C_CHAR_BOOL 0x00000002
51 #define SC_COMPILER_C_CHAR_WORD 0x00000004
52 #define SC_COMPILER_C_CHAR_VALUE 0x00000008
53 #define SC_COMPILER_C_CHAR_STRING 0x00000010
54 #define SC_COMPILER_C_CHAR_DONTCARE 0x00000020
55 #define SC_COMPILER_C_BOOL 0x00000040
56 #define SC_COMPILER_C_WORD 0x00000080
57 #define SC_COMPILER_C_WORD_SEP 0x00000100
58 #define SC_COMPILER_C_VALUE 0x00000200
59 #define SC_COMPILER_C_VALUE_SEP 0x00000400
60 #define SC_COMPILER_C_VALUE_EXP 0x00000800
61 #define SC_COMPILER_C_VALUE_SIGN 0x00001000
62 #define SC_COMPILER_C_VALUE_VALUE 0x00002000
63 #define SC_COMPILER_C_STRING_SEP 0x00004000
64 #define SC_COMPILER_C_NAME_SEP 0x00008000 // there can be only one! '\''
65 #define SC_COMPILER_C_CHAR_IDENT 0x00010000 // identifier (built-in function) or reference start
66 #define SC_COMPILER_C_IDENT 0x00020000 // identifier or reference continuation
67 #define SC_COMPILER_C_ODF_LBRACKET 0x00040000 // ODF '[' reference bracket
68 #define SC_COMPILER_C_ODF_RBRACKET 0x00080000 // ODF ']' reference bracket
69 #define SC_COMPILER_C_ODF_LABEL_OP 0x00100000 // ODF '!!' automatic intersection of labels
70 #define SC_COMPILER_C_ODF_NAME_MARKER 0x00200000 // ODF '$$' marker that starts a defined (range) name
71 #define SC_COMPILER_C_CHAR_NAME 0x00400000 // start character of a defined name
72 #define SC_COMPILER_C_NAME 0x00800000 // continuation character of a defined name
73 #define SC_COMPILER_C_CHAR_ERRCONST 0x01000000 // start character of an error constant ('#')
75 #define SC_COMPILER_FILE_TAB_SEP '#' // 'Doc'#Tab
81 class ScExternalRefManager
;
84 // constants and data types internal to compiler
88 formula::StackVar eType; // type of data
89 sal_uInt16 nRefCnt; // reference count
90 bool bRaw; // not cloned yet and trimmed to real size
97 formula::StackVar eType
;
98 mutable sal_uInt16 nRefCnt
;
102 struct ScDoubleRawToken
: private ScRawTokenBase
106 { // union only to assure alignment identical to ScRawToken
113 DECL_FIXEDMEMPOOL_NEWDEL( ScDoubleRawToken
);
116 struct ScRawToken
: private ScRawTokenBase
118 friend class ScCompiler
;
119 // Friends that use a temporary ScRawToken on the stack (and therefor need
120 // the private dtor) and know what they're doing..
121 friend class ScTokenArray
;
122 static sal_uInt16
sbyteOffset();
130 ScComplexRefData aRef
;
133 sal_Unicode cTabName
[MAXSTRLEN
+1];
134 ScComplexRefData aRef
;
138 sal_Unicode cName
[MAXSTRLEN
+1];
146 sal_Unicode cStr
[ MAXSTRLEN
+1 ]; // string (up to 255 characters + 0)
147 short nJump
[ FORMULA_MAXJUMPCOUNT
+ 1 ]; // If/Chose token
150 //! other members not initialized
151 ScRawToken() { bRaw
= true; }
153 ~ScRawToken() {} //! only delete via Delete()
155 DECL_FIXEDMEMPOOL_NEWDEL( ScRawToken
);
156 formula::StackVar
GetType() const { return (formula::StackVar
) eType
; }
157 OpCode
GetOpCode() const { return (OpCode
) eOp
; }
158 void NewOpCode( OpCode e
) { eOp
= e
; }
159 void IncRef() { nRefCnt
++; }
160 void DecRef() { if( !--nRefCnt
) Delete(); }
161 sal_uInt16
GetRef() const { return nRefCnt
; }
162 SC_DLLPUBLIC
void Delete();
164 // Use these methods only on tokens that are not part of a token array,
165 // since the reference count is cleared!
166 void SetOpCode( OpCode eCode
);
167 void SetString( const sal_Unicode
* pStr
);
168 void SetSingleReference( const ScSingleRefData
& rRef
);
169 void SetDoubleReference( const ScComplexRefData
& rRef
);
170 void SetDouble( double fVal
);
171 void SetErrorConstant( sal_uInt16 nErr
);
173 // These methods are ok to use, reference count not cleared.
174 void SetName(bool bGlobal
, sal_uInt16 nIndex
);
175 void SetExternalSingleRef( sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
);
176 void SetExternalDoubleRef( sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
);
177 void SetExternalName( sal_uInt16 nFileId
, const String
& rName
);
178 void SetMatrix( ScMatrix
* p
);
179 void SetExternal(const sal_Unicode
* pStr
);
181 /** If the token is a non-external reference, determine if the reference is
182 valid. If the token is an external reference, return true. Else return
183 false. Used only in ScCompiler::NextNewToken() to preserve non-existing
184 sheet names in otherwise valid references.
186 bool IsValidReference() const;
188 ScRawToken
* Clone() const; // real copy!
189 formula::FormulaToken
* CreateToken() const; // create typified token
190 void Load( SvStream
&, sal_uInt16 nVer
);
192 static xub_StrLen
GetStrLen( const sal_Unicode
* pStr
); // as long as a "string" is an array
193 static size_t GetStrLenBytes( xub_StrLen nLen
)
194 { return nLen
* sizeof(sal_Unicode
); }
195 static size_t GetStrLenBytes( const sal_Unicode
* pStr
)
196 { return GetStrLenBytes( GetStrLen( pStr
) ); }
199 inline void intrusive_ptr_add_ref(ScRawToken
* p
)
204 inline void intrusive_ptr_release(ScRawToken
* p
)
209 typedef ::boost::intrusive_ptr
<ScRawToken
> ScRawTokenRef
;
211 class SC_DLLPUBLIC ScCompiler
: public formula::FormulaCompiler
222 enum ExtendedErrorDetection
224 EXTENDED_ERROR_DETECTION_NONE
= 0, // no error on unknown symbols, default (interpreter handles it)
225 EXTENDED_ERROR_DETECTION_NAME_BREAK
, // name error on unknown symbols and break, pCode incomplete
226 EXTENDED_ERROR_DETECTION_NAME_NO_BREAK
// name error on unknown symbols, don't break, continue
231 const formula::FormulaGrammar::AddressConvention meConv
;
233 Convention( formula::FormulaGrammar::AddressConvention eConvP
);
234 virtual ~Convention();
236 virtual void MakeRefStr( OUStringBuffer
& rBuffer
,
237 const ScCompiler
& rCompiler
,
238 const ScComplexRefData
& rRef
,
239 bool bSingleRef
) const = 0;
240 virtual ::com::sun::star::i18n::ParseResult
241 parseAnyToken( const String
& rFormula
,
243 const CharClass
* pCharClass
) const = 0;
246 * Parse the symbol string and pick up the file name and the external
249 * @return true on successful parse, or false otherwise.
251 virtual bool parseExternalName( const String
& rSymbol
, String
& rFile
, String
& rName
,
252 const ScDocument
* pDoc
,
253 const ::com::sun::star::uno::Sequence
<
254 const ::com::sun::star::sheet::ExternalLinkInfo
> * pExternalLinks
) const = 0;
256 virtual String
makeExternalNameStr( const String
& rFile
, const String
& rName
) const = 0;
258 virtual void makeExternalRefStr( OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
259 sal_uInt16 nFileId
, const String
& rTabName
, const ScSingleRefData
& rRef
,
260 ScExternalRefManager
* pRefMgr
) const = 0;
262 virtual void makeExternalRefStr( OUStringBuffer
& rBuffer
, const ScCompiler
& rCompiler
,
263 sal_uInt16 nFileId
, const String
& rTabName
, const ScComplexRefData
& rRef
,
264 ScExternalRefManager
* pRefMgr
) const = 0;
266 enum SpecialSymbolType
269 * Character between sheet name and address. In OOO A1 this is
270 * '.', while XL A1 and XL R1C1 this is '!'.
275 * In OOO A1, a sheet name may be prefixed with '$' to indicate an
276 * absolute sheet position.
280 virtual sal_Unicode
getSpecialSymbol( SpecialSymbolType eSymType
) const = 0;
282 virtual sal_uLong
getCharTableFlags( sal_Unicode c
, sal_Unicode cLast
) const = 0;
285 const sal_uLong
* mpCharTable
;
287 friend struct Convention
;
292 static CharClass
*pCharClassEnglish
; // character classification for en_US locale
293 static const Convention
*pConventions
[ formula::FormulaGrammar::CONV_LAST
];
295 static const Convention
* const pConvOOO_A1
;
296 static const Convention
* const pConvOOO_A1_ODF
;
297 static const Convention
* const pConvXL_A1
;
298 static const Convention
* const pConvXL_R1C1
;
299 static const Convention
* const pConvXL_OOX
;
301 static struct AddInMap
304 const char* pEnglish
;
305 bool bMapDupToInternal
; // when writing ODFF
306 const char* pOriginal
; // programmatical name
307 const char* pUpper
; // upper case programmatical name
309 static const AddInMap
* GetAddInMap();
310 static size_t GetAddInMapCount();
315 // For CONV_XL_OOX, may be set via API by MOOXML filter.
316 ::com::sun::star::uno::Sequence
< const ::com::sun::star::sheet::ExternalLinkInfo
> maExternalLinks
;
318 sal_Unicode cSymbol
[MAXSTRLEN
]; // current Symbol
319 String aFormula
; // formula source code
320 xub_StrLen nSrcPos
; // tokenizer position (source code)
321 mutable ScRawTokenRef pRawToken
;
323 const CharClass
* pCharClass
; // which character classification is used for parseAnyToken
324 sal_uInt16 mnPredetectedReference
; // reference when reading ODF, 0 (none), 1 (single) or 2 (double)
325 SCsTAB nMaxTab
; // last sheet in document
326 sal_Int32 mnRangeOpPosInSymbol
; // if and where a range operator is in symbol
327 const Convention
*pConv
;
328 EncodeUrlMode meEncodeUrlMode
;
329 ExtendedErrorDetection meExtendedErrorDetection
;
330 bool mbCloseBrackets
; // whether to close open brackets automatically, default TRUE
331 bool mbRewind
; // whether symbol is to be rewound to some step during lexical analysis
332 std::vector
<sal_uInt16
> maExternalFiles
;
334 bool NextNewToken(bool bInArray
= false);
336 virtual void SetError(sal_uInt16 nError
);
337 xub_StrLen
NextSymbol(bool bInArray
);
338 bool IsValue( const String
& );
339 bool IsOpCode( const String
&, bool bInArray
);
340 bool IsOpCode2( const String
& );
342 bool IsReference( const String
& );
343 bool IsSingleReference( const String
& );
344 bool IsPredetectedReference( const String
& );
345 bool IsDoubleReference( const String
& );
346 bool IsMacro( const String
& );
347 bool IsNamedRange( const String
& );
348 bool IsExternalNamedRange( const String
& rSymbol
);
349 bool IsDBRange( const String
& );
350 bool IsColRowName( const String
& );
351 bool IsBoolean( const String
& );
352 void AutoCorrectParsedSymbol();
354 void SetRelNameReference();
356 /** Obtain range data for ocName token, global or sheet local.
358 Prerequisite: rToken is a FormulaIndexToken so IsGlobal() and
359 GetIndex() can be called on it. We don't check with RTTI.
361 ScRangeData
* GetRangeData( const formula::FormulaToken
& pToken
) const;
363 static void InitCharClassEnglish();
366 ScCompiler( ScDocument
* pDocument
, const ScAddress
&);
368 ScCompiler( ScDocument
* pDocument
, const ScAddress
&,ScTokenArray
& rArr
);
371 static void DeInit(); /// all
373 // for ScAddress::Format()
374 static void CheckTabQuotes( String
& aTabName
,
375 const formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_OOO
);
377 /** Analyzes a string for a 'Doc'#Tab construct, or 'Do''c'#Tab etc..
379 @returns the position of the unquoted # hash mark in 'Doc'#Tab, or
380 STRING_NOTFOUND if none. */
381 static xub_StrLen
GetDocTabPos( const String
& rString
);
383 static bool EnQuote( String
& rStr
);
384 sal_Unicode
GetNativeAddressSymbol( Convention::SpecialSymbolType eType
) const;
386 // Check if it is a valid english function name
387 bool IsEnglishSymbol( const String
& rName
);
388 bool IsErrorConstant( const String
& ) const;
390 //! _either_ CompileForFAP _or_ AutoCorrection, _not_ both
391 // #i101512# SetCompileForFAP is in formula::FormulaCompiler
392 void SetAutoCorrection( bool bVal
)
393 { bAutoCorrect
= bVal
; bIgnoreErrors
= bVal
; }
394 void SetCloseBrackets( bool bVal
) { mbCloseBrackets
= bVal
; }
395 void SetRefConvention( const Convention
*pConvP
);
396 void SetRefConvention( const formula::FormulaGrammar::AddressConvention eConv
);
398 /// Set symbol map if not empty.
399 void SetFormulaLanguage( const OpCodeMapPtr
& xMap
);
401 void SetGrammar( const formula::FormulaGrammar::Grammar eGrammar
);
403 EncodeUrlMode
GetEncodeUrlMode() const;
405 /** Set grammar and reference convention from within SetFormulaLanguage()
409 The new grammar to be set and the associated reference convention.
412 The previous grammar that was active before SetFormulaLanguage().
414 void SetGrammarAndRefConvention(
415 const formula::FormulaGrammar::Grammar eNewGrammar
,
416 const formula::FormulaGrammar::Grammar eOldGrammar
);
419 /// Set external link info for ScAddress::CONV_XL_OOX.
420 inline void SetExternalLinks(
421 const ::com::sun::star::uno::Sequence
<
422 const ::com::sun::star::sheet::ExternalLinkInfo
> & rLinks
)
424 maExternalLinks
= rLinks
;
427 void CreateStringFromXMLTokenArray( OUString
& rFormula
, OUString
& rFormulaNmsp
);
429 void SetExtendedErrorDetection( ExtendedErrorDetection eVal
) { meExtendedErrorDetection
= eVal
; }
431 bool IsCorrected() { return bCorrected
; }
432 const String
& GetCorrectedFormula() { return aCorrectedFormula
; }
434 // Use convention from this->aPos by default
435 ScTokenArray
* CompileString( const String
& rFormula
);
436 ScTokenArray
* CompileString( const String
& rFormula
, const String
& rFormulaNmsp
);
437 const ScDocument
* GetDoc() const { return pDoc
; }
438 const ScAddress
& GetPos() const { return aPos
; }
440 void MoveRelWrap( SCCOL nMaxCol
, SCROW nMaxRow
);
441 static void MoveRelWrap( ScTokenArray
& rArr
, ScDocument
* pDoc
, const ScAddress
& rPos
,
442 SCCOL nMaxCol
, SCROW nMaxRow
);
444 bool UpdateNameReference( UpdateRefMode eUpdateRefMode
,
446 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
447 bool& rChanged
, bool bSharedFormula
= false, bool bLocal
= false);
449 ScRangeData
* UpdateReference( UpdateRefMode eUpdateRefMode
,
450 const ScAddress
& rOldPos
, const ScRange
&,
451 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
452 bool& rChanged
, bool& rRefSizeChanged
);
454 /// Only once for converted shared formulas,
455 /// token array has to be compiled afterwards.
456 void UpdateSharedFormulaReference( UpdateRefMode eUpdateRefMode
,
457 const ScAddress
& rOldPos
, const ScRange
&,
458 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
);
460 ScRangeData
* UpdateInsertTab(SCTAB nTable
, bool bIsName
, SCTAB nNewSheets
= 1 );
461 ScRangeData
* UpdateDeleteTab(SCTAB nTable
, bool bIsMove
, bool bIsName
, bool& bCompile
, SCTAB nSheets
= 1);
462 ScRangeData
* UpdateMoveTab(SCTAB nOldPos
, SCTAB nNewPos
, bool bIsName
);
464 bool HasModifiedRange();
466 /** If the character is allowed as first character in sheet names or
467 references, includes '$' and '?'. */
468 static inline bool IsCharWordChar( String
const & rStr
,
470 const formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_OOO
)
472 sal_Unicode c
= rStr
.GetChar( nPos
);
473 sal_Unicode cLast
= nPos
> 0 ? rStr
.GetChar(nPos
-1) : 0;
476 return pConventions
[eConv
] ? (pConventions
[eConv
]->getCharTableFlags(c
, cLast
) & SC_COMPILER_C_CHAR_WORD
) == SC_COMPILER_C_CHAR_WORD
:
477 false; // no convention => assume invalid
480 return ScGlobal::pCharClass
->isLetterNumeric( rStr
, nPos
);
483 /** If the character is allowed in sheet names, thus may be part of a
484 reference, includes '$' and '?' and such. */
485 static inline bool IsWordChar( String
const & rStr
,
487 const formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_OOO
)
489 sal_Unicode c
= rStr
.GetChar( nPos
);
490 sal_Unicode cLast
= nPos
> 0 ? rStr
.GetChar(nPos
-1) : 0;
493 return pConventions
[eConv
] ? (pConventions
[eConv
]->getCharTableFlags(c
, cLast
) & SC_COMPILER_C_WORD
) == SC_COMPILER_C_WORD
:
494 false; // convention not known => assume invalid
497 return ScGlobal::pCharClass
->isLetterNumeric( rStr
, nPos
);
500 /** If the character is allowed as tested by nFlags (SC_COMPILER_C_...
501 bits) for all known address conventions. If more than one bit is given
502 in nFlags, all bits must match. If bTestLetterNumeric is false and
503 char>=128, no LetterNumeric test is done and false is returned. */
504 static inline bool IsCharFlagAllConventions( String
const & rStr
,
507 bool bTestLetterNumeric
= true )
509 sal_Unicode c
= rStr
.GetChar( nPos
);
510 sal_Unicode cLast
= nPos
> 0 ? rStr
.GetChar( nPos
-1 ) : 0;
513 for ( int nConv
= formula::FormulaGrammar::CONV_UNSPECIFIED
;
514 ++nConv
< formula::FormulaGrammar::CONV_LAST
; )
516 if (pConventions
[nConv
] &&
517 ((pConventions
[nConv
]->getCharTableFlags(c
, cLast
) & nFlags
) != nFlags
))
519 // convention not known => assume valid
523 else if (bTestLetterNumeric
)
524 return ScGlobal::pCharClass
->isLetterNumeric( rStr
, nPos
);
531 virtual String
FindAddInFunction( const String
& rUpperName
, bool bLocalFirst
) const;
532 virtual void fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr xMap
) const;
533 virtual void fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr xMap
) const;
534 virtual void fillFromAddInMap( NonConstOpCodeMapPtr xMap
, formula::FormulaGrammar::Grammar _eGrammar
) const;
535 virtual void fillAddInToken(::std::vector
< ::com::sun::star::sheet::FormulaOpCodeMapEntry
>& _rVec
,bool _bIsEnglish
) const;
537 virtual bool HandleExternalReference(const formula::FormulaToken
& _aToken
);
538 virtual bool HandleRange();
539 virtual bool HandleSingleRef();
540 virtual bool HandleDbData();
542 virtual formula::FormulaTokenRef
ExtendRangeReference( formula::FormulaToken
& rTok1
, formula::FormulaToken
& rTok2
, bool bReuseDoubleRef
);
543 virtual void CreateStringFromExternal(OUStringBuffer
& rBuffer
, formula::FormulaToken
* pTokenP
);
544 virtual void CreateStringFromSingleRef(OUStringBuffer
& rBuffer
,formula::FormulaToken
* _pTokenP
);
545 virtual void CreateStringFromDoubleRef(OUStringBuffer
& rBuffer
,formula::FormulaToken
* _pTokenP
);
546 virtual void CreateStringFromMatrix( OUStringBuffer
& rBuffer
, formula::FormulaToken
* _pTokenP
);
547 virtual void CreateStringFromIndex(OUStringBuffer
& rBuffer
,formula::FormulaToken
* _pTokenP
);
548 virtual void LocalizeString( String
& rName
); // modify rName - input: exact name
550 /// Access the CharTable flags
551 inline sal_uLong
GetCharTableFlags( sal_Unicode c
, sal_Unicode cLast
)
552 { return c
< 128 ? pConv
->getCharTableFlags(c
, cLast
) : 0; }
557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */