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