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 formula::StackVar eType; // type of data
103 formula::StackVar eType
;
106 struct ScRawToken
: private ScRawTokenBase
108 friend class ScCompiler
;
109 // Friends that use a temporary ScRawToken on the stack (and therefore need
110 // the private dtor) and know what they're doing..
111 friend class ScTokenArray
;
117 bool bIsInForceArray
;
119 ScComplexRefData aRef
;
122 sal_Unicode cTabName
[MAXSTRLEN
+1];
123 ScComplexRefData aRef
;
127 sal_Unicode cName
[MAXSTRLEN
+1];
135 ScTableRefToken::Item eItem
;
139 rtl_uString
* mpDataIgnoreCase
;
143 sal_Unicode cStr
[ MAXSTRLEN
+1 ]; // string (up to 255 characters + 0)
144 short nJump
[ FORMULA_MAXJUMPCOUNT
+ 1 ]; // If/Chose token
147 //! members not initialized
150 ~ScRawToken() {} //! only delete via Delete()
152 DECL_FIXEDMEMPOOL_NEWDEL( ScRawToken
);
153 formula::StackVar
GetType() const { return eType
; }
154 OpCode
GetOpCode() const { return eOp
; }
155 void NewOpCode( OpCode e
) { eOp
= e
; }
157 // Use these methods only on tokens that are not part of a token array,
158 // since the reference count is cleared!
159 void SetOpCode( OpCode eCode
);
160 void SetString( rtl_uString
* pData
, rtl_uString
* pDataIgoreCase
);
161 void SetSingleReference( const ScSingleRefData
& rRef
);
162 void SetDoubleReference( const ScComplexRefData
& rRef
);
163 void SetDouble( double fVal
);
164 void SetErrorConstant( sal_uInt16 nErr
);
166 // These methods are ok to use, reference count not cleared.
167 void SetName(sal_Int16 nSheet
, sal_uInt16 nIndex
);
168 void SetExternalSingleRef( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScSingleRefData
& rRef
);
169 void SetExternalDoubleRef( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScComplexRefData
& rRef
);
170 void SetExternalName( sal_uInt16 nFileId
, const OUString
& rName
);
171 void SetExternal(const sal_Unicode
* pStr
);
173 /** If the token is a non-external reference, determine if the reference is
174 valid. If the token is an external reference, return true. Else return
175 false. Used only in ScCompiler::NextNewToken() to preserve non-existing
176 sheet names in otherwise valid references.
178 bool IsValidReference() const;
180 formula::FormulaToken
* CreateToken() const; // create typified token
182 static sal_Int32
GetStrLen( const sal_Unicode
* pStr
); // as long as a "string" is an array
183 static size_t GetStrLenBytes( sal_Int32 nLen
)
184 { return nLen
* sizeof(sal_Unicode
); }
187 class SC_DLLPUBLIC ScCompiler
: public formula::FormulaCompiler
191 enum ExtendedErrorDetection
193 EXTENDED_ERROR_DETECTION_NONE
= 0, // no error on unknown symbols, default (interpreter handles it)
194 EXTENDED_ERROR_DETECTION_NAME_BREAK
, // name error on unknown symbols and break, pCode incomplete
195 EXTENDED_ERROR_DETECTION_NAME_NO_BREAK
// name error on unknown symbols, don't break, continue
200 const formula::FormulaGrammar::AddressConvention meConv
;
202 Convention( formula::FormulaGrammar::AddressConvention eConvP
);
203 virtual ~Convention();
205 virtual void makeRefStr(
206 OUStringBuffer
& rBuffer
,
207 formula::FormulaGrammar::Grammar eGram
,
208 const ScAddress
& rPos
,
209 const OUString
& rErrRef
, const std::vector
<OUString
>& rTabNames
,
210 const ScComplexRefData
& rRef
, bool bSingleRef
, bool bFromRangeName
) const = 0;
212 virtual css::i18n::ParseResult
213 parseAnyToken( const OUString
& rFormula
,
215 const CharClass
* pCharClass
) const = 0;
218 * Parse the symbol string and pick up the file name and the external
221 * @return true on successful parse, or false otherwise.
223 virtual bool parseExternalName( const OUString
& rSymbol
, OUString
& rFile
, OUString
& rName
,
224 const ScDocument
* pDoc
,
225 const css::uno::Sequence
< css::sheet::ExternalLinkInfo
>* pExternalLinks
) const = 0;
227 virtual OUString
makeExternalNameStr( sal_uInt16 nFileId
, const OUString
& rFile
,
228 const OUString
& rName
) const = 0;
230 virtual void makeExternalRefStr(
231 OUStringBuffer
& rBuffer
, const ScAddress
& rPos
, sal_uInt16 nFileId
, const OUString
& rFileName
,
232 const OUString
& rTabName
, const ScSingleRefData
& rRef
) const = 0;
234 virtual void makeExternalRefStr(
235 OUStringBuffer
& rBuffer
, const ScAddress
& rPos
,
236 sal_uInt16 nFileId
, const OUString
& rFileName
, const std::vector
<OUString
>& rTabNames
,
237 const OUString
& rTabName
, const ScComplexRefData
& rRef
) const = 0;
239 enum SpecialSymbolType
242 * Character between sheet name and address. In OOO A1 this is
243 * '.', while XL A1 and XL R1C1 this is '!'.
248 * In OOO A1, a sheet name may be prefixed with '$' to indicate an
249 * absolute sheet position.
253 virtual sal_Unicode
getSpecialSymbol( SpecialSymbolType eSymType
) const = 0;
255 virtual ScCharFlags
getCharTableFlags( sal_Unicode c
, sal_Unicode cLast
) const = 0;
258 const ScCharFlags
* mpCharTable
;
260 friend struct Convention
;
264 static CharClass
*pCharClassEnglish
; // character classification for en_US locale
265 static const Convention
*pConventions
[ formula::FormulaGrammar::CONV_LAST
];
267 static struct AddInMap
270 const char* pEnglish
;
271 const char* pOriginal
; // programmatical name
272 const char* pUpper
; // upper case programmatical name
274 static const AddInMap
* GetAddInMap();
275 static size_t GetAddInMapCount();
280 SvNumberFormatter
* mpFormatter
;
282 SCTAB mnCurrentSheetTab
; // indicates current sheet number parsed so far
283 sal_Int32 mnCurrentSheetEndPos
; // position after current sheet name if parsed
285 // For CONV_XL_OOX, may be set via API by MOOXML filter.
286 css::uno::Sequence
<css::sheet::ExternalLinkInfo
> maExternalLinks
;
288 sal_Unicode cSymbol
[MAXSTRLEN
]; // current Symbol
289 OUString aFormula
; // formula source code
290 sal_Int32 nSrcPos
; // tokenizer position (source code)
291 mutable ScRawToken maRawToken
;
293 const CharClass
* pCharClass
; // which character classification is used for parseAnyToken
294 sal_uInt16 mnPredetectedReference
; // reference when reading ODF, 0 (none), 1 (single) or 2 (double)
295 SCsTAB nMaxTab
; // last sheet in document
296 sal_Int32 mnRangeOpPosInSymbol
; // if and where a range operator is in symbol
297 const Convention
*pConv
;
298 ExtendedErrorDetection meExtendedErrorDetection
;
299 bool mbCloseBrackets
; // whether to close open brackets automatically, default TRUE
300 bool mbRewind
; // whether symbol is to be rewound to some step during lexical analysis
301 std::vector
<sal_uInt16
> maExternalFiles
;
303 std::vector
<OUString
> maTabNames
; /// sheet names mangled for the current grammar for output
304 std::vector
<OUString
> &GetSetupTabNames() const; /// get or setup tab names for the current grammar
310 TableRefEntry( formula::FormulaToken
* p
) : mxToken(p
), mnLevel(0) {}
312 std::vector
<TableRefEntry
> maTableRefs
; /// "stack" of currently active ocTableRef tokens
314 bool NextNewToken(bool bInArray
= false);
316 virtual void SetError(sal_uInt16 nError
) override
;
317 sal_Int32
NextSymbol(bool bInArray
);
318 bool IsValue( const OUString
& );
319 bool IsOpCode( const OUString
&, bool bInArray
);
320 bool IsOpCode2( const OUString
& );
322 bool IsReference( const OUString
& rSymbol
, const OUString
* pErrRef
= nullptr );
323 bool IsSingleReference( const OUString
& rSymbol
, const OUString
* pErrRef
= nullptr );
324 bool IsDoubleReference( const OUString
& rSymbol
, const OUString
* pErrRef
= nullptr );
325 bool IsPredetectedReference( const OUString
& rSymbol
);
326 bool IsPredetectedErrRefReference( const OUString
& rName
, const OUString
* pErrRef
);
327 bool IsMacro( const OUString
& );
328 bool IsNamedRange( const OUString
& );
329 bool IsExternalNamedRange( const OUString
& rSymbol
, bool& rbInvalidExternalNameRange
);
330 bool IsDBRange( const OUString
& );
331 bool IsColRowName( const OUString
& );
332 bool IsBoolean( const OUString
& );
333 void AutoCorrectParsedSymbol();
335 void AdjustSheetLocalNameRelReferences( SCTAB nDelta
);
336 void SetRelNameReference();
338 /** Obtain range data for ocName token, global or sheet local.
340 Prerequisite: rToken is a FormulaIndexToken so IsGlobal() and
341 GetIndex() can be called on it. We don't check with RTTI.
343 ScRangeData
* GetRangeData( const formula::FormulaToken
& pToken
) const;
345 static void InitCharClassEnglish();
348 ScCompiler( sc::CompileFormulaContext
& rCxt
, const ScAddress
& rPos
);
350 ScCompiler( ScDocument
* pDocument
, const ScAddress
&);
352 ScCompiler( sc::CompileFormulaContext
& rCxt
, const ScAddress
& rPos
, ScTokenArray
& rArr
);
354 ScCompiler( ScDocument
* pDocument
, const ScAddress
&,ScTokenArray
& rArr
);
356 virtual ~ScCompiler();
359 static void DeInit(); /// all
361 // for ScAddress::Format()
362 static void CheckTabQuotes( OUString
& aTabName
,
363 const formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_OOO
);
365 /** Analyzes a string for a 'Doc'#Tab construct, or 'Do''c'#Tab etc..
367 @returns the position of the unquoted # hash mark in 'Doc'#Tab, or
369 static sal_Int32
GetDocTabPos( const OUString
& rString
);
371 static bool EnQuote( OUString
& rStr
);
372 sal_Unicode
GetNativeAddressSymbol( Convention::SpecialSymbolType eType
) const;
374 // Check if it is a valid english function name
375 bool IsEnglishSymbol( const OUString
& rName
);
377 bool IsErrorConstant( const OUString
& ) const;
378 bool IsTableRefItem( const OUString
& ) const;
379 bool IsTableRefColumn( const OUString
& ) const;
381 /** Calls GetToken() if PeekNextNoSpaces() is of given OpCode. */
382 bool GetTokenIfOpCode( OpCode eOp
);
385 * When auto correction is set, the jump command reorder must be enabled.
387 void SetAutoCorrection( bool bVal
);
388 void SetCloseBrackets( bool bVal
) { mbCloseBrackets
= bVal
; }
389 void SetRefConvention( const Convention
*pConvP
);
390 void SetRefConvention( const formula::FormulaGrammar::AddressConvention eConv
);
392 static const Convention
* GetRefConvention( formula::FormulaGrammar::AddressConvention eConv
);
394 /// Set symbol map if not empty.
395 void SetFormulaLanguage( const OpCodeMapPtr
& xMap
);
397 void SetGrammar( const formula::FormulaGrammar::Grammar eGrammar
);
399 void SetNumberFormatter( SvNumberFormatter
* pFormatter
);
402 /** Set grammar and reference convention from within SetFormulaLanguage()
406 The new grammar to be set and the associated reference convention.
409 The previous grammar that was active before SetFormulaLanguage().
411 void SetGrammarAndRefConvention(
412 const formula::FormulaGrammar::Grammar eNewGrammar
,
413 const formula::FormulaGrammar::Grammar eOldGrammar
);
416 /// Set external link info for ScAddress::CONV_XL_OOX.
417 void SetExternalLinks(
418 const css::uno::Sequence
<
419 css::sheet::ExternalLinkInfo
>& rLinks
)
421 maExternalLinks
= rLinks
;
424 void CreateStringFromXMLTokenArray( OUString
& rFormula
, OUString
& rFormulaNmsp
);
426 void SetExtendedErrorDetection( ExtendedErrorDetection eVal
) { meExtendedErrorDetection
= eVal
; }
428 bool IsCorrected() { return bCorrected
; }
429 const OUString
& GetCorrectedFormula() { return aCorrectedFormula
; }
432 * Tokenize formula expression string into an array of tokens.
434 * @param rFormula formula expression to tokenize.
436 * @return heap allocated token array object. The caller <i>must</i>
437 * manage the life cycle of this object.
439 ScTokenArray
* CompileString( const OUString
& rFormula
);
440 ScTokenArray
* CompileString( const OUString
& rFormula
, const OUString
& rFormulaNmsp
);
441 const ScAddress
& GetPos() const { return aPos
; }
443 void MoveRelWrap( SCCOL nMaxCol
, SCROW nMaxRow
);
444 static void MoveRelWrap( ScTokenArray
& rArr
, ScDocument
* pDoc
, const ScAddress
& rPos
,
445 SCCOL nMaxCol
, SCROW nMaxRow
);
447 /** If the character is allowed as tested by nFlags (SC_COMPILER_C_...
448 bits) for all known address conventions. If more than one bit is given
449 in nFlags, all bits must match. */
450 static bool IsCharFlagAllConventions(
451 OUString
const & rStr
, sal_Int32 nPos
, ScCharFlags nFlags
);
455 virtual OUString
FindAddInFunction( const OUString
& rUpperName
, bool bLocalFirst
) const override
;
456 virtual void fillFromAddInCollectionUpperName( const NonConstOpCodeMapPtr
& xMap
) const override
;
457 virtual void fillFromAddInCollectionEnglishName( const NonConstOpCodeMapPtr
& xMap
) const override
;
458 virtual void fillFromAddInMap( const NonConstOpCodeMapPtr
& xMap
, formula::FormulaGrammar::Grammar _eGrammar
) const override
;
459 virtual void fillAddInToken(::std::vector
< css::sheet::FormulaOpCodeMapEntry
>& _rVec
,bool _bIsEnglish
) const override
;
461 virtual bool HandleExternalReference(const formula::FormulaToken
& _aToken
) override
;
462 virtual bool HandleRange() override
;
463 virtual bool HandleColRowName() override
;
464 virtual bool HandleDbData() override
;
465 virtual bool HandleTableRef() override
;
467 virtual formula::FormulaTokenRef
ExtendRangeReference( formula::FormulaToken
& rTok1
, formula::FormulaToken
& rTok2
) override
;
468 virtual void CreateStringFromExternal( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
469 virtual void CreateStringFromSingleRef( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
470 virtual void CreateStringFromDoubleRef( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
471 virtual void CreateStringFromMatrix( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
472 virtual void CreateStringFromIndex( OUStringBuffer
& rBuffer
, const formula::FormulaToken
* pToken
) const override
;
473 virtual void LocalizeString( OUString
& rName
) const override
; // modify rName - input: exact name
475 virtual bool IsForceArrayParameter( const formula::FormulaToken
* pToken
, sal_uInt16 nParam
) const override
;
477 /// Access the CharTable flags
478 inline ScCharFlags
GetCharTableFlags( sal_Unicode c
, sal_Unicode cLast
)
479 { return c
< 128 ? pConv
->getCharTableFlags(c
, cLast
) : ScCharFlags::NONE
; }
484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */