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