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