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 INCLUDED_SC_INC_COMPILER_HXX
21 #define INCLUDED_SC_INC_COMPILER_HXX
25 #include <tools/mempool.hxx>
28 #include "refdata.hxx"
30 #include <formula/token.hxx>
31 #include <formula/grammar.hxx>
32 #include <unotools/charclass.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <com/sun/star/sheet/ExternalLinkInfo.hpp>
38 #include <formula/FormulaCompiler.hxx>
39 #include <o3tl/typed_flags_set.hxx>
41 // constants and data types also for external modules (ScInterpreter et al)
43 #define MAXSTRLEN 1024 /* maximum length of input string of one symbol */
45 // flag values of CharTable
46 enum class ScCharFlags
: sal_uInt32
{
50 CharBool
= 0x00000002,
51 CharWord
= 0x00000004,
52 CharValue
= 0x00000008,
53 CharString
= 0x00000010,
54 CharDontCare
= 0x00000020,
59 ValueSep
= 0x00000400,
60 ValueExp
= 0x00000800,
61 ValueSign
= 0x00001000,
62 ValueValue
= 0x00002000,
63 StringSep
= 0x00004000,
64 NameSep
= 0x00008000, // there can be only one! '\''
65 CharIdent
= 0x00010000, // identifier (built-in function) or reference start
66 Ident
= 0x00020000, // identifier or reference continuation
67 OdfLBracket
= 0x00040000, // ODF '[' reference bracket
68 OdfRBracket
= 0x00080000, // ODF ']' reference bracket
69 OdfLabelOp
= 0x00100000, // ODF '!!' automatic intersection of labels
70 OdfNameMarker
= 0x00200000, // ODF '$$' marker that starts a defined (range) name
71 CharName
= 0x00400000, // start character of a defined name
72 Name
= 0x00800000, // continuation character of a defined name
73 CharErrConst
= 0x01000000, // start character of an error constant ('#')
76 template<> struct typed_flags
<ScCharFlags
> : is_typed_flags
<ScCharFlags
, 0x01ffffff> {};
79 #define SC_COMPILER_FILE_TAB_SEP '#' // 'Doc'#Tab
84 class ScExternalRefManager
;
89 class CompileFormulaContext
;
93 // constants and data types internal to compiler
95 struct ScRawToken final
97 friend class ScCompiler
;
98 // Friends that use a temporary ScRawToken on the stack (and therefore need
99 // the private dtor) and know what they're doing..
100 friend class ScTokenArray
;
102 formula::StackVar eType
; // type of data; this determines how the unions are used
108 formula::ParamClass eInForceArray
;
110 ScComplexRefData aRef
;
113 sal_Unicode cTabName
[MAXSTRLEN
+1];
114 ScComplexRefData aRef
;
118 sal_Unicode cName
[MAXSTRLEN
+1];
126 ScTableRefToken::Item eItem
;
130 rtl_uString
* mpDataIgnoreCase
;
134 sal_Unicode cStr
[ 1+MAXSTRLEN
+1 ]; // string (byteparam + up to MAXSTRLEN characters + 0)
135 short nJump
[ FORMULA_MAXJUMPCOUNT
+ 1 ]; // If/Chose token
138 // coverity[uninit_member] - members deliberately not initialized
141 ~ScRawToken() {} //! only delete via Delete()
143 DECL_FIXEDMEMPOOL_NEWDEL( ScRawToken
);
144 formula::StackVar
GetType() const { return eType
; }
145 OpCode
GetOpCode() const { return eOp
; }
146 void NewOpCode( OpCode e
) { eOp
= e
; }
148 // Use these methods only on tokens that are not part of a token array,
149 // since the reference count is cleared!
150 void SetOpCode( OpCode eCode
);
151 void SetString( rtl_uString
* pData
, rtl_uString
* pDataIgoreCase
);
152 void SetSingleReference( const ScSingleRefData
& rRef
);
153 void SetDoubleReference( const ScComplexRefData
& rRef
);
154 void SetDouble( double fVal
);
155 void SetErrorConstant( FormulaError nErr
);
157 // These methods are ok to use, reference count not cleared.
158 void SetName(sal_Int16 nSheet
, sal_uInt16 nIndex
);
159 void SetExternalSingleRef( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScSingleRefData
& rRef
);
160 void SetExternalDoubleRef( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScComplexRefData
& rRef
);
161 void SetExternalName( sal_uInt16 nFileId
, const OUString
& rName
);
162 void SetExternal(const sal_Unicode
* pStr
);
164 /** If the token is a non-external reference, determine if the reference is
165 valid. If the token is an external reference, return true. Else return
166 false. Used only in ScCompiler::NextNewToken() to preserve non-existing
167 sheet names in otherwise valid references.
169 bool IsValidReference() const;
171 formula::FormulaToken
* CreateToken() const; // create typified token
173 static sal_Int32
GetStrLen( const sal_Unicode
* pStr
); // as long as a "string" is an array
176 class SC_DLLPUBLIC ScCompiler
: public formula::FormulaCompiler
180 enum ExtendedErrorDetection
182 EXTENDED_ERROR_DETECTION_NONE
= 0, // no error on unknown symbols, default (interpreter handles it)
183 EXTENDED_ERROR_DETECTION_NAME_BREAK
, // name error on unknown symbols and break, pCode incomplete
184 EXTENDED_ERROR_DETECTION_NAME_NO_BREAK
// name error on unknown symbols, don't break, continue
189 const formula::FormulaGrammar::AddressConvention meConv
;
191 Convention( formula::FormulaGrammar::AddressConvention eConvP
);
192 virtual ~Convention();
194 virtual void makeRefStr(
195 OUStringBuffer
& rBuffer
,
196 formula::FormulaGrammar::Grammar eGram
,
197 const ScAddress
& rPos
,
198 const OUString
& rErrRef
, const std::vector
<OUString
>& rTabNames
,
199 const ScComplexRefData
& rRef
, bool bSingleRef
, bool bFromRangeName
) const = 0;
201 virtual css::i18n::ParseResult
202 parseAnyToken( const OUString
& rFormula
,
204 const CharClass
* pCharClass
) const = 0;
207 * Parse the symbol string and pick up the file name and the external
210 * @return true on successful parse, or false otherwise.
212 virtual bool parseExternalName( const OUString
& rSymbol
, OUString
& rFile
, OUString
& rName
,
213 const ScDocument
* pDoc
,
214 const css::uno::Sequence
< css::sheet::ExternalLinkInfo
>* pExternalLinks
) const = 0;
216 virtual OUString
makeExternalNameStr( sal_uInt16 nFileId
, const OUString
& rFile
,
217 const OUString
& rName
) const = 0;
219 virtual void makeExternalRefStr(
220 OUStringBuffer
& rBuffer
, const ScAddress
& rPos
, sal_uInt16 nFileId
, const OUString
& rFileName
,
221 const OUString
& rTabName
, const ScSingleRefData
& rRef
) const = 0;
223 virtual void makeExternalRefStr(
224 OUStringBuffer
& rBuffer
, const ScAddress
& rPos
,
225 sal_uInt16 nFileId
, const OUString
& rFileName
, const std::vector
<OUString
>& rTabNames
,
226 const OUString
& rTabName
, const ScComplexRefData
& rRef
) const = 0;
228 enum SpecialSymbolType
231 * Character between sheet name and address. In OOO A1 this is
232 * '.', while XL A1 and XL R1C1 this is '!'.
237 * In OOO A1, a sheet name may be prefixed with '$' to indicate an
238 * absolute sheet position.
242 virtual sal_Unicode
getSpecialSymbol( SpecialSymbolType eSymType
) const = 0;
244 virtual ScCharFlags
getCharTableFlags( sal_Unicode c
, sal_Unicode cLast
) const = 0;
247 std::unique_ptr
<ScCharFlags
[]> mpCharTable
;
249 friend struct Convention
;
253 static CharClass
*pCharClassEnglish
; // character classification for en_US locale
254 static const Convention
*pConventions
[ formula::FormulaGrammar::CONV_LAST
];
256 static const struct AddInMap
259 const char* pEnglish
;
260 const char* pOriginal
; // programmatical name
261 const char* pUpper
; // upper case programmatical name
263 static size_t GetAddInMapCount();
268 SvNumberFormatter
* mpFormatter
;
270 SCTAB mnCurrentSheetTab
; // indicates current sheet number parsed so far
271 sal_Int32 mnCurrentSheetEndPos
; // position after current sheet name if parsed
273 // For CONV_XL_OOX, may be set via API by MOOXML filter.
274 css::uno::Sequence
<css::sheet::ExternalLinkInfo
> maExternalLinks
;
276 sal_Unicode cSymbol
[MAXSTRLEN
+1]; // current Symbol + 0
277 OUString aFormula
; // formula source code
278 sal_Int32 nSrcPos
; // tokenizer position (source code)
279 mutable ScRawToken maRawToken
;
281 const CharClass
* pCharClass
; // which character classification is used for parseAnyToken
282 sal_uInt16 mnPredetectedReference
; // reference when reading ODF, 0 (none), 1 (single) or 2 (double)
283 sal_Int32 mnRangeOpPosInSymbol
; // if and where a range operator is in symbol
284 const Convention
*pConv
;
285 ExtendedErrorDetection meExtendedErrorDetection
;
286 bool mbCloseBrackets
; // whether to close open brackets automatically, default TRUE
287 bool mbRewind
; // whether symbol is to be rewound to some step during lexical analysis
288 std::vector
<sal_uInt16
> maExternalFiles
;
290 std::vector
<OUString
> maTabNames
; /// sheet names mangled for the current grammar for output
291 std::vector
<OUString
> &GetSetupTabNames() const; /// get or setup tab names for the current grammar
297 TableRefEntry( formula::FormulaToken
* p
) : mxToken(p
), mnLevel(0) {}
299 std::vector
<TableRefEntry
> maTableRefs
; /// "stack" of currently active ocTableRef tokens
301 bool NextNewToken(bool bInArray
);
303 virtual void SetError(FormulaError nError
) override
;
304 sal_Int32
NextSymbol(bool bInArray
);
305 bool IsValue( const OUString
& );
306 bool IsOpCode( const OUString
&, bool bInArray
);
307 bool IsOpCode2( const OUString
& );
309 bool IsReference( const OUString
& rSymbol
, const OUString
* pErrRef
= nullptr );
310 bool IsSingleReference( const OUString
& rSymbol
, const OUString
* pErrRef
= nullptr );
311 bool IsDoubleReference( const OUString
& rSymbol
, const OUString
* pErrRef
= nullptr );
312 bool IsPredetectedReference( const OUString
& rSymbol
);
313 bool IsPredetectedErrRefReference( const OUString
& rName
, const OUString
* pErrRef
);
314 bool IsMacro( const OUString
& );
315 bool IsNamedRange( const OUString
& );
316 bool IsExternalNamedRange( const OUString
& rSymbol
, bool& rbInvalidExternalNameRange
);
317 bool IsDBRange( const OUString
& );
318 bool IsColRowName( const OUString
& );
319 bool IsBoolean( const OUString
& );
320 void AutoCorrectParsedSymbol();
322 void AdjustSheetLocalNameRelReferences( SCTAB nDelta
);
323 void SetRelNameReference();
325 /** Obtain range data for ocName token, global or sheet local.
327 Prerequisite: rToken is a FormulaIndexToken so IsGlobal() and
328 GetIndex() can be called on it. We don't check with RTTI.
330 ScRangeData
* GetRangeData( const formula::FormulaToken
& pToken
) const;
332 static void InitCharClassEnglish();
335 ScCompiler( sc::CompileFormulaContext
& rCxt
, const ScAddress
& rPos
);
337 /** If eGrammar == GRAM_UNSPECIFIED then the grammar of pDocument is used,
338 if pDocument==nullptr then GRAM_DEFAULT.
340 ScCompiler( ScDocument
* pDocument
, const ScAddress
&,
341 formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_UNSPECIFIED
);
343 ScCompiler( sc::CompileFormulaContext
& rCxt
, const ScAddress
& rPos
, ScTokenArray
& rArr
);
345 /** If eGrammar == GRAM_UNSPECIFIED then the grammar of pDocument is used,
346 if pDocument==nullptr then GRAM_DEFAULT.
348 ScCompiler( ScDocument
* pDocument
, const ScAddress
&, ScTokenArray
& rArr
,
349 formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_UNSPECIFIED
);
351 virtual ~ScCompiler() override
;
354 static void DeInit(); /// all
356 // for ScAddress::Format()
357 static void CheckTabQuotes( OUString
& aTabName
,
358 const formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_OOO
);
360 /** Analyzes a string for a 'Doc'#Tab construct, or 'Do''c'#Tab etc..
362 @returns the position of the unquoted # hash mark in 'Doc'#Tab, or
364 static sal_Int32
GetDocTabPos( const OUString
& rString
);
366 static bool EnQuote( OUString
& rStr
);
367 sal_Unicode
GetNativeAddressSymbol( Convention::SpecialSymbolType eType
) const;
369 // Check if it is a valid english function name
370 bool IsEnglishSymbol( const OUString
& rName
);
372 bool IsErrorConstant( const OUString
& ) const;
373 bool IsTableRefItem( const OUString
& ) const;
374 bool IsTableRefColumn( const OUString
& ) const;
376 /** Calls GetToken() if PeekNextNoSpaces() is of given OpCode. */
377 bool GetTokenIfOpCode( OpCode eOp
);
380 * When auto correction is set, the jump command reorder must be enabled.
382 void SetAutoCorrection( bool bVal
);
383 void SetCloseBrackets( bool bVal
) { mbCloseBrackets
= bVal
; }
384 void SetRefConvention( const Convention
*pConvP
);
385 void SetRefConvention( const formula::FormulaGrammar::AddressConvention eConv
);
387 static const Convention
* GetRefConvention( formula::FormulaGrammar::AddressConvention eConv
);
389 /// Set symbol map if not empty.
390 void SetFormulaLanguage( const OpCodeMapPtr
& xMap
);
392 void SetGrammar( const formula::FormulaGrammar::Grammar eGrammar
);
394 void SetNumberFormatter( SvNumberFormatter
* pFormatter
);
397 /** Set grammar and reference convention from within SetFormulaLanguage()
401 The new grammar to be set and the associated reference convention.
404 The previous grammar that was active before SetFormulaLanguage().
406 void SetGrammarAndRefConvention(
407 const formula::FormulaGrammar::Grammar eNewGrammar
,
408 const formula::FormulaGrammar::Grammar eOldGrammar
);
411 /// Set external link info for ScAddress::CONV_XL_OOX.
412 void SetExternalLinks(
413 const css::uno::Sequence
<
414 css::sheet::ExternalLinkInfo
>& rLinks
)
416 maExternalLinks
= rLinks
;
419 void CreateStringFromXMLTokenArray( OUString
& rFormula
, OUString
& rFormulaNmsp
);
421 void SetExtendedErrorDetection( ExtendedErrorDetection eVal
) { meExtendedErrorDetection
= eVal
; }
423 bool IsCorrected() { return bCorrected
; }
424 const OUString
& GetCorrectedFormula() { return aCorrectedFormula
; }
427 * Tokenize formula expression string into an array of tokens.
429 * @param rFormula formula expression to tokenize.
431 * @return heap allocated token array object. The caller <i>must</i>
432 * manage the life cycle of this object.
434 ScTokenArray
* CompileString( const OUString
& rFormula
);
435 ScTokenArray
* CompileString( const OUString
& rFormula
, const OUString
& rFormulaNmsp
);
436 const ScAddress
& GetPos() const { return aPos
; }
438 void MoveRelWrap( SCCOL nMaxCol
, SCROW nMaxRow
);
439 static void MoveRelWrap( const ScTokenArray
& rArr
, const ScDocument
* pDoc
, const ScAddress
& rPos
,
440 SCCOL nMaxCol
, SCROW nMaxRow
);
442 /** If the character is allowed as tested by nFlags (SC_COMPILER_C_...
443 bits) for all known address conventions. If more than one bit is given
444 in nFlags, all bits must match. */
445 static bool IsCharFlagAllConventions(
446 OUString
const & rStr
, sal_Int32 nPos
, ScCharFlags nFlags
);
450 virtual OUString
FindAddInFunction( const OUString
& rUpperName
, bool bLocalFirst
) const override
;
451 virtual void fillFromAddInCollectionUpperName( const NonConstOpCodeMapPtr
& xMap
) const override
;
452 virtual void fillFromAddInCollectionEnglishName( const NonConstOpCodeMapPtr
& xMap
) const override
;
453 virtual void fillFromAddInMap( const NonConstOpCodeMapPtr
& xMap
, formula::FormulaGrammar::Grammar _eGrammar
) const override
;
454 virtual void fillAddInToken(::std::vector
< css::sheet::FormulaOpCodeMapEntry
>& _rVec
,bool _bIsEnglish
) const override
;
456 virtual bool HandleExternalReference(const formula::FormulaToken
& _aToken
) override
;
457 virtual bool HandleRange() override
;
458 virtual bool HandleColRowName() override
;
459 virtual bool HandleDbData() override
;
460 virtual bool HandleTableRef() override
;
462 virtual formula::FormulaTokenRef
ExtendRangeReference( formula::FormulaToken
& rTok1
, formula::FormulaToken
& rTok2
) override
;
463 virtual void CreateStringFromExternal( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
464 virtual void CreateStringFromSingleRef( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
465 virtual void CreateStringFromDoubleRef( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
466 virtual void CreateStringFromMatrix( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
467 virtual void CreateStringFromIndex( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
468 virtual void LocalizeString( OUString
& rName
) const override
; // modify rName - input: exact name
470 virtual formula::ParamClass
GetForceArrayParameter( const formula::FormulaToken
* pToken
, sal_uInt16 nParam
) const override
;
472 /// Access the CharTable flags
473 ScCharFlags
GetCharTableFlags( sal_Unicode c
, sal_Unicode cLast
)
474 { return c
< 128 ? pConv
->getCharTableFlags(c
, cLast
) : ScCharFlags::NONE
; }
476 bool IsIIOpCode(OpCode nOpCode
) const override
;
477 void HandleIIOpCode(OpCode nOpCode
, formula::FormulaToken
*** pppToken
, sal_uInt8 nNumParams
) override
;
478 bool AdjustSumRangeShape(const ScComplexRefData
& rBaseRange
, ScComplexRefData
& rSumRange
);
479 void CorrectSumRange(const ScComplexRefData
& rBaseRange
, ScComplexRefData
& rSumRange
, formula::FormulaToken
** ppSumRangeToken
);
484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */