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 35313 : size_t operator()( const String& rStr ) const
66 : {
67 35313 : 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 89 : OpCodeMap(sal_uInt16 nSymbols, bool bCore, FormulaGrammar::Grammar eGrammar ) :
105 89 : mpHashMap( new OpCodeHashMap( nSymbols)),
106 178 : mpTable( new String[ nSymbols ]),
107 89 : mpExternalHashMap( new ExternalHashMap),
108 89 : mpReverseExternalHashMap( new ExternalHashMap),
109 : meGrammar( eGrammar),
110 : mnSymbols( nSymbols),
111 534 : mbCore( bCore)
112 : {
113 89 : mbEnglish = FormulaGrammar::isEnglish( meGrammar);
114 89 : }
115 : virtual ~OpCodeMap();
116 :
117 : void copyFrom( const OpCodeMap& r );
118 :
119 : /// Get the symbol String -> OpCode hash map for finds.
120 4586 : inline const OpCodeHashMap* getHashMap() const { return mpHashMap; }
121 :
122 : /// Get the symbol String -> AddIn String hash map for finds.
123 32 : 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 12983 : inline const String& getSymbol( const OpCode eOp ) const
130 : {
131 : DBG_ASSERT( sal_uInt16(eOp) < mnSymbols, "OpCodeMap::getSymbol: OpCode out of range");
132 12983 : if (sal_uInt16(eOp) < mnSymbols)
133 12983 : return mpTable[ eOp ];
134 0 : static String s_sEmpty;
135 0 : return s_sEmpty;
136 : }
137 :
138 : /// Get the grammar.
139 4190 : inline FormulaGrammar::Grammar getGrammar() const { return meGrammar; }
140 :
141 : /// Get the symbol count.
142 180 : 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 9807 : 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 152 : inline bool isODFF() const { return FormulaGrammar::isODFF( meGrammar); }
156 :
157 : /// Does it have external symbol/name mappings?
158 163 : 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 58 : void SetCompileForFAP( bool bVal )
216 58 : { 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 3474 : 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 17360 : 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 24062 : static inline void ForceArrayOperator( FormulaTokenRef& rCurr, const FormulaTokenRef& rPrev )
329 : {
330 24066 : if ( rPrev && rPrev->HasForceArray() &&
331 3 : rCurr->GetType() == svByte && rCurr->GetOpCode() != ocPush
332 1 : && !rCurr->HasForceArray() )
333 0 : rCurr->SetForceArray( true);
334 24062 : }
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 16454 : explicit CurrentFactor( FormulaCompiler* pComp )
349 : : pPrevFac( pComp->pCurrentFactorToken )
350 16454 : , pCompiler( pComp )
351 16454 : {}
352 16454 : ~CurrentFactor()
353 16454 : { pCompiler->pCurrentFactorToken = pPrevFac; }
354 : // yes, this operator= may modify the RValue
355 3621 : void operator=( FormulaTokenRef& r )
356 : {
357 3621 : ForceArrayOperator( r, pPrevFac);
358 3621 : pCompiler->pCurrentFactorToken = r;
359 3621 : }
360 0 : void operator=( FormulaToken* p )
361 : {
362 0 : FormulaTokenRef xTemp( p );
363 0 : *this = xTemp;
364 0 : }
365 3621 : operator FormulaTokenRef&()
366 3621 : { return pCompiler->pCurrentFactorToken; }
367 3677 : FormulaToken* operator->()
368 3677 : { 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: */
|