Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
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/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
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 .
18 : : */
19 : :
20 : : #ifndef FORMULA_COMPILER_HXX_INCLUDED
21 : : #define FORMULA_COMPILER_HXX_INCLUDED
22 : :
23 : : #include "formula/formuladllapi.h"
24 : : #include <tools/string.hxx>
25 : : #include <tools/debug.hxx>
26 : : #include <rtl/ustrbuf.hxx>
27 : :
28 : : #include <boost/shared_ptr.hpp>
29 : : #include <boost/unordered_map.hpp>
30 : :
31 : : #include <com/sun/star/uno/Sequence.hxx>
32 : :
33 : : #include "formula/opcode.hxx"
34 : : #include "formula/grammar.hxx"
35 : : #include "formula/token.hxx"
36 : : #include "formula/ExternalReferenceHelper.hxx"
37 : :
38 : :
39 : : #define MAXJUMPCOUNT 32 /* maximum number of jumps (ocChose) */
40 : : #define MAXCODE 512 /* maximum number of tokens in formula */
41 : :
42 : :
43 : : namespace com { namespace sun { namespace star {
44 : : namespace sheet {
45 : : struct FormulaOpCodeMapEntry;
46 : : struct FormulaToken;
47 : : }
48 : : }}}
49 : :
50 : :
51 : : namespace formula
52 : : {
53 : : class FormulaTokenArray;
54 : :
55 : : struct FormulaArrayStack
56 : : {
57 : : FormulaArrayStack* pNext;
58 : : FormulaTokenArray* pArr;
59 : : bool bTemp;
60 : : };
61 : :
62 : :
63 : : struct FORMULA_DLLPUBLIC StringHashCode
64 : : {
65 : 173315 : size_t operator()( const String& rStr ) const
66 : : {
67 : 173315 : return rtl_ustr_hashCode_WithLength( rStr.GetBuffer(), rStr.Len() );
68 : : }
69 : : };
70 : :
71 : : typedef ::boost::unordered_map< String, OpCode, StringHashCode, ::std::equal_to< String > > OpCodeHashMap;
72 : : typedef ::boost::unordered_map< String, String, StringHashCode, ::std::equal_to< String > > ExternalHashMap;
73 : :
74 : : class FORMULA_DLLPUBLIC FormulaCompiler
75 : : {
76 : : public:
77 : : FormulaCompiler();
78 : : FormulaCompiler(FormulaTokenArray& _rArr);
79 : : virtual ~FormulaCompiler();
80 : :
81 : : // SUNWS8 needs a forward declared friend, otherwise members of the outer
82 : : // class are not accessible.
83 : : class OpCodeMap;
84 : : friend class FormulaCompiler::OpCodeMap;
85 : :
86 : : /** Mappings from strings to OpCodes and vice versa. */
87 : : class FORMULA_DLLPUBLIC OpCodeMap
88 : : {
89 : : OpCodeHashMap * mpHashMap; /// Hash map of symbols, String -> OpCode
90 : : String * mpTable; /// Array of symbols, OpCode -> String, offset==OpCode
91 : : ExternalHashMap * mpExternalHashMap; /// Hash map of ocExternal, Filter String -> AddIn String
92 : : ExternalHashMap * mpReverseExternalHashMap; /// Hash map of ocExternal, AddIn String -> Filter String
93 : : FormulaGrammar::Grammar meGrammar; /// Grammar, language and reference convention
94 : : sal_uInt16 mnSymbols; /// Count of OpCode symbols
95 : : bool mbCore : 1; /// If mapping was setup by core, not filters
96 : : bool mbEnglish : 1; /// If English symbols and external names
97 : :
98 : : OpCodeMap(); // prevent usage
99 : : OpCodeMap( const OpCodeMap& ); // prevent usage
100 : : OpCodeMap& operator=( const OpCodeMap& ); // prevent usage
101 : :
102 : : public:
103 : :
104 : 468 : OpCodeMap(sal_uInt16 nSymbols, bool bCore, FormulaGrammar::Grammar eGrammar ) :
105 [ + - ]: 468 : mpHashMap( new OpCodeHashMap( nSymbols)),
106 [ + - ][ + + : 189072 : mpTable( new String[ nSymbols ]),
# # # # ]
107 [ + - ]: 468 : mpExternalHashMap( new ExternalHashMap),
108 [ + - ]: 468 : mpReverseExternalHashMap( new ExternalHashMap),
109 : : meGrammar( eGrammar),
110 : : mnSymbols( nSymbols),
111 [ + - ][ + - ]: 2340 : mbCore( bCore)
[ + - ]
112 : : {
113 : 468 : mbEnglish = FormulaGrammar::isEnglish( meGrammar);
114 : 468 : }
115 : : virtual ~OpCodeMap();
116 : :
117 : : void copyFrom( const OpCodeMap& r );
118 : :
119 : : /// Get the symbol String -> OpCode hash map for finds.
120 : 17290 : inline const OpCodeHashMap* getHashMap() const { return mpHashMap; }
121 : :
122 : : /// Get the symbol String -> AddIn String hash map for finds.
123 : 166 : inline const ExternalHashMap* getExternalHashMap() const { return mpExternalHashMap; }
124 : :
125 : : /// Get the AddIn String -> symbol String hash map for finds.
126 : 0 : inline const ExternalHashMap* getReverseExternalHashMap() const { return mpReverseExternalHashMap; }
127 : :
128 : : /// Get the symbol string matching an OpCode.
129 : 103949 : inline const String& getSymbol( const OpCode eOp ) const
130 : : {
131 : : DBG_ASSERT( sal_uInt16(eOp) < mnSymbols, "OpCodeMap::getSymbol: OpCode out of range");
132 [ + - ]: 103949 : if (sal_uInt16(eOp) < mnSymbols)
133 : 103949 : return mpTable[ eOp ];
134 [ # # ][ # # ]: 0 : static String s_sEmpty;
[ # # ][ # # ]
135 : 103949 : return s_sEmpty;
136 : : }
137 : :
138 : : /// Get the grammar.
139 : 33478 : inline FormulaGrammar::Grammar getGrammar() const { return meGrammar; }
140 : :
141 : : /// Get the symbol count.
142 : 25392 : inline sal_uInt16 getSymbolCount() const { return mnSymbols; }
143 : :
144 : : /** Are these English symbols, as opposed to native language (which may
145 : : be English as well)? */
146 : 57465 : inline bool isEnglish() const { return mbEnglish; }
147 : :
148 : : /// Is it an internal core mapping, or setup by filters?
149 : : inline bool isCore() const { return mbCore; }
150 : :
151 : : /// Is it an ODF 1.1 compatibility mapping?
152 : 0 : inline bool isPODF() const { return FormulaGrammar::isPODF( meGrammar); }
153 : :
154 : : /// Is it an ODFF / ODF 1.2 mapping?
155 : 2383 : inline bool isODFF() const { return FormulaGrammar::isODFF( meGrammar); }
156 : :
157 : : /// Does it have external symbol/name mappings?
158 : 2399 : inline bool hasExternals() const { return !mpExternalHashMap->empty(); }
159 : :
160 : : /// Put entry of symbol String and OpCode pair.
161 : : void putOpCode( const String & rStr, const OpCode eOp );
162 : :
163 : : /// Put entry of symbol String and AddIn international String pair.
164 : : void putExternal( const String & rSymbol, const String & rAddIn );
165 : :
166 : : /** Put entry of symbol String and AddIn international String pair,
167 : : failing silently if rAddIn name already exists. */
168 : : void putExternalSoftly( const String & rSymbol, const String & rAddIn );
169 : :
170 : : /// Core implementation of XFormulaOpCodeMapper::getMappings()
171 : : ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken >
172 : : createSequenceOfFormulaTokens(const FormulaCompiler& _rCompiler,
173 : : const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rNames ) const;
174 : :
175 : : /// Core implementation of XFormulaOpCodeMapper::getAvailableMappings()
176 : : ::com::sun::star::uno::Sequence<
177 : : ::com::sun::star::sheet::FormulaOpCodeMapEntry >
178 : : createSequenceOfAvailableMappings( const FormulaCompiler& _rCompiler,const sal_Int32 nGroup ) const;
179 : :
180 : : /** The value used in createSequenceOfAvailableMappings() and thus in
181 : : XFormulaOpCodeMapper::getMappings() for an unknown symbol. */
182 : : static sal_Int32 getOpCodeUnknown();
183 : : };
184 : :
185 : : public:
186 : : typedef ::boost::shared_ptr< const OpCodeMap > OpCodeMapPtr;
187 : : typedef ::boost::shared_ptr< OpCodeMap > NonConstOpCodeMapPtr;
188 : :
189 : : /** Get OpCodeMap for formula language.
190 : : @param nLanguage
191 : : One of ::com::sun::star::sheet::FormulaLanguage constants.
192 : : @return Map for nLanguage. If nLanguage is unknown, a NULL map is returned.
193 : : */
194 : : OpCodeMapPtr GetOpCodeMap( const sal_Int32 nLanguage ) const;
195 : :
196 : : /** Create an internal symbol map from API mapping.
197 : : @param bEnglish
198 : : Use English number parser / formatter instead of native.
199 : : */
200 : : OpCodeMapPtr CreateOpCodeMap(
201 : : const ::com::sun::star::uno::Sequence<
202 : : const ::com::sun::star::sheet::FormulaOpCodeMapEntry > & rMapping,
203 : : bool bEnglish );
204 : :
205 : : /** Get current OpCodeMap in effect. */
206 : 0 : inline OpCodeMapPtr GetCurrentOpCodeMap() const { return mxSymbols; }
207 : :
208 : : /** Get OpCode for English symbol.
209 : : Used in XFunctionAccess to create token array.
210 : : @param rName
211 : : Symbol to lookup. MUST be upper case.
212 : : */
213 : : OpCode GetEnglishOpCode( const String& rName ) const;
214 : :
215 : 117 : void SetCompileForFAP( bool bVal )
216 : 117 : { bCompileForFAP = bVal; bIgnoreErrors = bVal; }
217 : :
218 : : static bool IsOpCodeVolatile( OpCode eOp );
219 : :
220 : : static bool DeQuote( String& rStr );
221 : :
222 : :
223 : : static const String& GetNativeSymbol( OpCode eOp );
224 : : static bool IsMatrixFunction(OpCode _eOpCode); // if a function _always_ returns a Matrix
225 : :
226 : 4843 : short GetNumFormatType() const { return nNumFmt; }
227 : : bool CompileTokenArray();
228 : :
229 : : void CreateStringFromTokenArray( String& rFormula );
230 : : void CreateStringFromTokenArray( rtl::OUStringBuffer& rBuffer );
231 : : FormulaToken* CreateStringFromToken( String& rFormula, FormulaToken* pToken,
232 : : bool bAllowArrAdvance = false );
233 : : FormulaToken* CreateStringFromToken( rtl::OUStringBuffer& rBuffer, FormulaToken* pToken,
234 : : bool bAllowArrAdvance = false );
235 : :
236 : : void AppendBoolean( rtl::OUStringBuffer& rBuffer, bool bVal );
237 : : void AppendDouble( rtl::OUStringBuffer& rBuffer, double fVal );
238 : : void AppendString( rtl::OUStringBuffer& rBuffer, const String & rStr );
239 : :
240 : : /** Set symbol map corresponding to one of predefined formula::FormulaGrammar::Grammar,
241 : : including an address reference convention. */
242 : 135976 : inline FormulaGrammar::Grammar GetGrammar() const { return meGrammar; }
243 : :
244 : : static void UpdateSeparatorsNative( const rtl::OUString& rSep, const rtl::OUString& rArrayColSep, const rtl::OUString& rArrayRowSep );
245 : : static void ResetNativeSymbols();
246 : : static void SetNativeSymbols( const OpCodeMapPtr& xMap );
247 : : protected:
248 : : virtual String FindAddInFunction( const String& rUpperName, bool bLocalFirst ) const;
249 : : virtual void fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr xMap ) const;
250 : : virtual void fillFromAddInMap( NonConstOpCodeMapPtr xMap, FormulaGrammar::Grammar _eGrammar ) const;
251 : : virtual void fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr xMap ) const;
252 : : virtual void fillAddInToken(::std::vector< ::com::sun::star::sheet::FormulaOpCodeMapEntry >& _rVec,bool _bIsEnglish) const;
253 : :
254 : : virtual void SetError(sal_uInt16 nError);
255 : : virtual FormulaTokenRef ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, bool bReuseDoubleRef );
256 : : virtual bool HandleExternalReference(const FormulaToken& _aToken);
257 : : virtual bool HandleRange();
258 : : virtual bool HandleSingleRef();
259 : : virtual bool HandleDbData();
260 : :
261 : : virtual void CreateStringFromExternal(rtl::OUStringBuffer& rBuffer, FormulaToken* pTokenP);
262 : : virtual void CreateStringFromSingleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* pTokenP);
263 : : virtual void CreateStringFromDoubleRef(rtl::OUStringBuffer& rBuffer,FormulaToken* pTokenP);
264 : : virtual void CreateStringFromMatrix(rtl::OUStringBuffer& rBuffer,FormulaToken* pTokenP);
265 : : virtual void CreateStringFromIndex(rtl::OUStringBuffer& rBuffer,FormulaToken* pTokenP);
266 : : virtual void LocalizeString( String& rName ); // modify rName - input: exact name
267 : :
268 : : sal_uInt16 GetErrorConstant( const String& rName );
269 : : void AppendErrorConstant( rtl::OUStringBuffer& rBuffer, sal_uInt16 nError );
270 : :
271 : : bool GetToken();
272 : : OpCode NextToken();
273 : : void PutCode( FormulaTokenRef& );
274 : : void Factor();
275 : : void RangeLine();
276 : : void UnionLine();
277 : : void IntersectionLine();
278 : : void UnaryLine();
279 : : void PostOpLine();
280 : : void PowLine();
281 : : void MulDivLine();
282 : : void AddSubLine();
283 : : void ConcatLine();
284 : : void CompareLine();
285 : : void NotLine();
286 : : OpCode Expression();
287 : : void PopTokenArray();
288 : : void PushTokenArray( FormulaTokenArray*, bool = false );
289 : :
290 : : bool MergeRangeReference( FormulaToken * * const pCode1, FormulaToken * const * const pCode2 );
291 : :
292 : : String aCorrectedFormula; // autocorrected Formula
293 : : String aCorrectedSymbol; // autocorrected Symbol
294 : :
295 : : OpCodeMapPtr mxSymbols; // which symbols are used
296 : :
297 : : FormulaTokenRef mpToken; // current token
298 : : FormulaTokenRef pCurrentFactorToken; // current factor token (of Factor() method)
299 : : FormulaTokenArray* pArr;
300 : : ExternalReferenceHelper* pExternalRef;
301 : :
302 : : FormulaToken** pCode;
303 : : FormulaArrayStack* pStack;
304 : :
305 : : OpCode eLastOp;
306 : : short nRecursion; // GetToken() recursions
307 : : short nNumFmt; // set during CompileTokenArray()
308 : : sal_uInt16 pc; // program counter
309 : :
310 : : FormulaGrammar::Grammar meGrammar; // The grammar used, language plus convention.
311 : :
312 : : bool bAutoCorrect; // whether to apply AutoCorrection
313 : : bool bCorrected; // AutoCorrection was applied
314 : : bool bCompileForFAP; //! not real RPN but names, for FunctionAutoPilot
315 : : // will not be resolved
316 : : bool bIgnoreErrors; // on AutoCorrect and CompileForFAP
317 : : // ignore errors and create RPN nevertheless
318 : : bool glSubTotal; // if code contains one or more subtotal functions
319 : : private:
320 : : void InitSymbolsNative() const; /// only SymbolsNative, on first document creation
321 : : void InitSymbolsEnglish() const; /// only SymbolsEnglish, maybe later
322 : : void InitSymbolsPODF() const; /// only SymbolsPODF, on demand
323 : : void InitSymbolsODFF() const; /// only SymbolsODFF, on demand
324 : : void InitSymbolsEnglishXL() const; /// only SymbolsEnglishXL, on demand
325 : :
326 : : void loadSymbols(sal_uInt16 _nSymbols,FormulaGrammar::Grammar _eGrammar,NonConstOpCodeMapPtr& _xMap) const;
327 : :
328 : 46628 : static inline void ForceArrayOperator( FormulaTokenRef& rCurr, const FormulaTokenRef& rPrev )
329 : : {
330 [ + + ][ + + : 46640 : if ( rPrev && rPrev->HasForceArray() &&
+ + + - -
+ ][ - + ]
331 : 9 : rCurr->GetType() == svByte && rCurr->GetOpCode() != ocPush
332 : 3 : && !rCurr->HasForceArray() )
333 : 0 : rCurr->SetForceArray( true);
334 : 46628 : }
335 : :
336 : : // SUNWS7 needs a forward declared friend, otherwise members of the outer
337 : : // class are not accessible.
338 : : class CurrentFactor;
339 : : friend class FormulaCompiler::CurrentFactor;
340 : : class CurrentFactor
341 : : {
342 : : FormulaTokenRef pPrevFac;
343 : : FormulaCompiler* pCompiler;
344 : : // not implemented
345 : : CurrentFactor( const CurrentFactor& );
346 : : CurrentFactor& operator=( const CurrentFactor& );
347 : : public:
348 : 30874 : explicit CurrentFactor( FormulaCompiler* pComp )
349 : : : pPrevFac( pComp->pCurrentFactorToken )
350 : 30874 : , pCompiler( pComp )
351 : 30874 : {}
352 : 30874 : ~CurrentFactor()
353 [ + - ]: 30874 : { pCompiler->pCurrentFactorToken = pPrevFac; }
354 : : // yes, this operator= may modify the RValue
355 : 9769 : void operator=( FormulaTokenRef& r )
356 : : {
357 : 9769 : ForceArrayOperator( r, pPrevFac);
358 : 9769 : pCompiler->pCurrentFactorToken = r;
359 : 9769 : }
360 : 0 : void operator=( FormulaToken* p )
361 : : {
362 : 0 : FormulaTokenRef xTemp( p );
363 [ # # ][ # # ]: 0 : *this = xTemp;
364 : 0 : }
365 : 9769 : operator FormulaTokenRef&()
366 : 9769 : { return pCompiler->pCurrentFactorToken; }
367 : 9829 : FormulaToken* operator->()
368 : 9829 : { return pCompiler->pCurrentFactorToken.operator->(); }
369 : 0 : operator FormulaToken*()
370 : 0 : { return operator->(); }
371 : : };
372 : :
373 : :
374 : : mutable NonConstOpCodeMapPtr mxSymbolsODFF; // ODFF symbols
375 : : mutable NonConstOpCodeMapPtr mxSymbolsPODF; // ODF 1.1 symbols
376 : : mutable NonConstOpCodeMapPtr mxSymbolsNative; // native symbols
377 : : mutable NonConstOpCodeMapPtr mxSymbolsEnglish; // English symbols
378 : : mutable NonConstOpCodeMapPtr mxSymbolsEnglishXL; // English Excel symbols (for VBA formula parsing)
379 : : };
380 : : // =============================================================================
381 : : } // formula
382 : : // =============================================================================
383 : :
384 : : #endif // FORMULA_COMPILER_HXX_INCLUDED
385 : :
386 : :
387 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|