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