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>
37 #include <formula/FormulaCompiler.hxx>
38 #include <o3tl/typed_flags_set.hxx>
40 // constants and data types also for external modules (ScInterpreter et al)
42 #define MAXSTRLEN 1024 /* maximum length of input string of one symbol */
44 // flag values of CharTable
45 enum class ScCharFlags
: sal_uInt32
{
49 CharBool
= 0x00000002,
50 CharWord
= 0x00000004,
51 CharValue
= 0x00000008,
52 CharString
= 0x00000010,
53 CharDontCare
= 0x00000020,
58 ValueSep
= 0x00000400,
59 ValueExp
= 0x00000800,
60 ValueSign
= 0x00001000,
61 ValueValue
= 0x00002000,
62 StringSep
= 0x00004000,
63 NameSep
= 0x00008000, // there can be only one! '\''
64 CharIdent
= 0x00010000, // identifier (built-in function) or reference start
65 Ident
= 0x00020000, // identifier or reference continuation
66 OdfLBracket
= 0x00040000, // ODF '[' reference bracket
67 OdfRBracket
= 0x00080000, // ODF ']' reference bracket
68 OdfLabelOp
= 0x00100000, // ODF '!!' automatic intersection of labels
69 OdfNameMarker
= 0x00200000, // ODF '$$' marker that starts a defined (range) name
70 CharName
= 0x00400000, // start character of a defined name
71 Name
= 0x00800000, // continuation character of a defined name
72 CharErrConst
= 0x01000000, // start character of an error constant ('#')
75 template<> struct typed_flags
<ScCharFlags
> : is_typed_flags
<ScCharFlags
, 0x01ffffff> {};
78 #define SC_COMPILER_FILE_TAB_SEP '#' // 'Doc'#Tab
83 class ScExternalRefManager
;
88 class CompileFormulaContext
;
92 // constants and data types internal to compiler
96 friend class ScCompiler
;
97 // Friends that use a temporary ScRawToken on the stack (and therefore need
98 // the private dtor) and know what they're doing..
99 friend class ScTokenArray
;
102 formula::StackVar eType
; // type of data; this determines how the unions are used
108 bool bIsInForceArray
;
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
[ MAXSTRLEN
+1 ]; // string (up to 255 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 const 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
]; // current Symbol
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 SCsTAB nMaxTab
; // last sheet in document
284 sal_Int32 mnRangeOpPosInSymbol
; // if and where a range operator is in symbol
285 const Convention
*pConv
;
286 ExtendedErrorDetection meExtendedErrorDetection
;
287 bool mbCloseBrackets
; // whether to close open brackets automatically, default TRUE
288 bool mbRewind
; // whether symbol is to be rewound to some step during lexical analysis
289 std::vector
<sal_uInt16
> maExternalFiles
;
291 std::vector
<OUString
> maTabNames
; /// sheet names mangled for the current grammar for output
292 std::vector
<OUString
> &GetSetupTabNames() const; /// get or setup tab names for the current grammar
298 TableRefEntry( formula::FormulaToken
* p
) : mxToken(p
), mnLevel(0) {}
300 std::vector
<TableRefEntry
> maTableRefs
; /// "stack" of currently active ocTableRef tokens
302 bool NextNewToken(bool bInArray
);
304 virtual void SetError(FormulaError nError
) override
;
305 sal_Int32
NextSymbol(bool bInArray
);
306 bool IsValue( const OUString
& );
307 bool IsOpCode( const OUString
&, bool bInArray
);
308 bool IsOpCode2( const OUString
& );
310 bool IsReference( const OUString
& rSymbol
, const OUString
* pErrRef
= nullptr );
311 bool IsSingleReference( const OUString
& rSymbol
, const OUString
* pErrRef
= nullptr );
312 bool IsDoubleReference( const OUString
& rSymbol
, const OUString
* pErrRef
= nullptr );
313 bool IsPredetectedReference( const OUString
& rSymbol
);
314 bool IsPredetectedErrRefReference( const OUString
& rName
, const OUString
* pErrRef
);
315 bool IsMacro( const OUString
& );
316 bool IsNamedRange( const OUString
& );
317 bool IsExternalNamedRange( const OUString
& rSymbol
, bool& rbInvalidExternalNameRange
);
318 bool IsDBRange( const OUString
& );
319 bool IsColRowName( const OUString
& );
320 bool IsBoolean( const OUString
& );
321 void AutoCorrectParsedSymbol();
323 void AdjustSheetLocalNameRelReferences( SCTAB nDelta
);
324 void SetRelNameReference();
326 /** Obtain range data for ocName token, global or sheet local.
328 Prerequisite: rToken is a FormulaIndexToken so IsGlobal() and
329 GetIndex() can be called on it. We don't check with RTTI.
331 ScRangeData
* GetRangeData( const formula::FormulaToken
& pToken
) const;
333 static void InitCharClassEnglish();
336 ScCompiler( sc::CompileFormulaContext
& rCxt
, const ScAddress
& rPos
);
338 ScCompiler( ScDocument
* pDocument
, const ScAddress
&);
340 ScCompiler( sc::CompileFormulaContext
& rCxt
, const ScAddress
& rPos
, ScTokenArray
& rArr
);
342 ScCompiler( ScDocument
* pDocument
, const ScAddress
&,ScTokenArray
& rArr
);
344 virtual ~ScCompiler() override
;
347 static void DeInit(); /// all
349 // for ScAddress::Format()
350 static void CheckTabQuotes( OUString
& aTabName
,
351 const formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_OOO
);
353 /** Analyzes a string for a 'Doc'#Tab construct, or 'Do''c'#Tab etc..
355 @returns the position of the unquoted # hash mark in 'Doc'#Tab, or
357 static sal_Int32
GetDocTabPos( const OUString
& rString
);
359 static bool EnQuote( OUString
& rStr
);
360 sal_Unicode
GetNativeAddressSymbol( Convention::SpecialSymbolType eType
) const;
362 // Check if it is a valid english function name
363 bool IsEnglishSymbol( const OUString
& rName
);
365 bool IsErrorConstant( const OUString
& ) const;
366 bool IsTableRefItem( const OUString
& ) const;
367 bool IsTableRefColumn( const OUString
& ) const;
369 /** Calls GetToken() if PeekNextNoSpaces() is of given OpCode. */
370 bool GetTokenIfOpCode( OpCode eOp
);
373 * When auto correction is set, the jump command reorder must be enabled.
375 void SetAutoCorrection( bool bVal
);
376 void SetCloseBrackets( bool bVal
) { mbCloseBrackets
= bVal
; }
377 void SetRefConvention( const Convention
*pConvP
);
378 void SetRefConvention( const formula::FormulaGrammar::AddressConvention eConv
);
380 static const Convention
* GetRefConvention( formula::FormulaGrammar::AddressConvention eConv
);
382 /// Set symbol map if not empty.
383 void SetFormulaLanguage( const OpCodeMapPtr
& xMap
);
385 void SetGrammar( const formula::FormulaGrammar::Grammar eGrammar
);
387 void SetNumberFormatter( SvNumberFormatter
* pFormatter
);
390 /** Set grammar and reference convention from within SetFormulaLanguage()
394 The new grammar to be set and the associated reference convention.
397 The previous grammar that was active before SetFormulaLanguage().
399 void SetGrammarAndRefConvention(
400 const formula::FormulaGrammar::Grammar eNewGrammar
,
401 const formula::FormulaGrammar::Grammar eOldGrammar
);
404 /// Set external link info for ScAddress::CONV_XL_OOX.
405 void SetExternalLinks(
406 const css::uno::Sequence
<
407 css::sheet::ExternalLinkInfo
>& rLinks
)
409 maExternalLinks
= rLinks
;
412 void CreateStringFromXMLTokenArray( OUString
& rFormula
, OUString
& rFormulaNmsp
);
414 void SetExtendedErrorDetection( ExtendedErrorDetection eVal
) { meExtendedErrorDetection
= eVal
; }
416 bool IsCorrected() { return bCorrected
; }
417 const OUString
& GetCorrectedFormula() { return aCorrectedFormula
; }
420 * Tokenize formula expression string into an array of tokens.
422 * @param rFormula formula expression to tokenize.
424 * @return heap allocated token array object. The caller <i>must</i>
425 * manage the life cycle of this object.
427 ScTokenArray
* CompileString( const OUString
& rFormula
);
428 ScTokenArray
* CompileString( const OUString
& rFormula
, const OUString
& rFormulaNmsp
);
429 const ScAddress
& GetPos() const { return aPos
; }
431 void MoveRelWrap( SCCOL nMaxCol
, SCROW nMaxRow
);
432 static void MoveRelWrap( ScTokenArray
& rArr
, ScDocument
* pDoc
, const ScAddress
& rPos
,
433 SCCOL nMaxCol
, SCROW nMaxRow
);
435 /** If the character is allowed as tested by nFlags (SC_COMPILER_C_...
436 bits) for all known address conventions. If more than one bit is given
437 in nFlags, all bits must match. */
438 static bool IsCharFlagAllConventions(
439 OUString
const & rStr
, sal_Int32 nPos
, ScCharFlags nFlags
);
443 virtual OUString
FindAddInFunction( const OUString
& rUpperName
, bool bLocalFirst
) const override
;
444 virtual void fillFromAddInCollectionUpperName( const NonConstOpCodeMapPtr
& xMap
) const override
;
445 virtual void fillFromAddInCollectionEnglishName( const NonConstOpCodeMapPtr
& xMap
) const override
;
446 virtual void fillFromAddInMap( const NonConstOpCodeMapPtr
& xMap
, formula::FormulaGrammar::Grammar _eGrammar
) const override
;
447 virtual void fillAddInToken(::std::vector
< css::sheet::FormulaOpCodeMapEntry
>& _rVec
,bool _bIsEnglish
) const override
;
449 virtual bool HandleExternalReference(const formula::FormulaToken
& _aToken
) override
;
450 virtual bool HandleRange() override
;
451 virtual bool HandleColRowName() override
;
452 virtual bool HandleDbData() override
;
453 virtual bool HandleTableRef() override
;
455 virtual formula::FormulaTokenRef
ExtendRangeReference( formula::FormulaToken
& rTok1
, formula::FormulaToken
& rTok2
) override
;
456 virtual void CreateStringFromExternal( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
457 virtual void CreateStringFromSingleRef( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
458 virtual void CreateStringFromDoubleRef( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
459 virtual void CreateStringFromMatrix( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
460 virtual void CreateStringFromIndex( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
461 virtual void LocalizeString( OUString
& rName
) const override
; // modify rName - input: exact name
463 virtual bool IsForceArrayParameter( const formula::FormulaToken
* pToken
, sal_uInt16 nParam
) const override
;
465 /// Access the CharTable flags
466 inline ScCharFlags
GetCharTableFlags( sal_Unicode c
, sal_Unicode cLast
)
467 { return c
< 128 ? pConv
->getCharTableFlags(c
, cLast
) : ScCharFlags::NONE
; }
472 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */