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 INCLUDED_FORMULA_TOKENARRAY_HXX
21 : #define INCLUDED_FORMULA_TOKENARRAY_HXX
22 :
23 : #include <com/sun/star/sheet/FormulaToken.hpp>
24 : #include <formula/token.hxx>
25 : #include <formula/ExternalReferenceHelper.hxx>
26 : #include <o3tl/underlying_type.hxx>
27 : #include <o3tl/typed_flags_set.hxx>
28 :
29 : #include <limits.h>
30 : #include <unordered_set>
31 :
32 : namespace svl {
33 :
34 : class SharedString;
35 : class SharedStringPool;
36 :
37 : }
38 :
39 : // RecalcMode access only via TokenArray SetRecalcMode / IsRecalcMode...
40 :
41 : // Only one of the exclusive bits can be set,
42 : // handled by TokenArray SetRecalcMode... methods
43 : enum class ScRecalcMode : sal_uInt8
44 : {
45 : NORMAL = 0x01, // exclusive
46 : ALWAYS = 0x02, // exclusive, always
47 : ONLOAD = 0x04, // exclusive, always after load
48 : ONLOAD_ONCE = 0x08, // exclusive, once after load
49 : FORCED = 0x10, // combined, also if cell isn't visible
50 : ONREFMOVE = 0x20, // combined, if reference was moved
51 : };
52 : // If new bits are to be defined, AddRecalcMode has to be adjusted!
53 : namespace o3tl
54 : {
55 : template<> struct typed_flags<ScRecalcMode> : is_typed_flags<ScRecalcMode, 0x3f> {};
56 : }
57 : #define RECALCMODE_EMASK (ScRecalcMode(ScRecalcMode::NORMAL | ScRecalcMode::ALWAYS | ScRecalcMode::ONLOAD | ScRecalcMode::ONLOAD_ONCE)) // mask of exclusive bits
58 :
59 : namespace formula
60 : {
61 :
62 : class FormulaMissingContext;
63 :
64 : class FORMULA_DLLPUBLIC MissingConvention
65 : {
66 : public:
67 : enum Convention
68 : {
69 : FORMULA_MISSING_CONVENTION_PODF,
70 : FORMULA_MISSING_CONVENTION_ODFF,
71 : FORMULA_MISSING_CONVENTION_OOXML
72 : };
73 1914 : explicit MissingConvention( Convention eConvention ) : meConvention(eConvention) {}
74 522 : inline bool isPODF() const { return meConvention == FORMULA_MISSING_CONVENTION_PODF; }
75 522 : inline Convention getConvention() const { return meConvention; }
76 : private:
77 : Convention meConvention;
78 : };
79 :
80 : class FORMULA_DLLPUBLIC MissingConventionODF : public MissingConvention
81 : {
82 : public:
83 1354 : explicit MissingConventionODF( bool bODFF ) :
84 : MissingConvention( bODFF ?
85 : MissingConvention::FORMULA_MISSING_CONVENTION_ODFF :
86 1354 : MissingConvention::FORMULA_MISSING_CONVENTION_PODF)
87 : {
88 1354 : }
89 : // Implementation and usage only in token.cxx
90 : inline bool isRewriteNeeded( OpCode eOp ) const;
91 : };
92 :
93 : class FORMULA_DLLPUBLIC MissingConventionOOXML : public MissingConvention
94 : {
95 : public:
96 560 : explicit MissingConventionOOXML() : MissingConvention( MissingConvention::FORMULA_MISSING_CONVENTION_OOXML) {}
97 : // Implementation and usage only in token.cxx
98 : static inline bool isRewriteNeeded( OpCode eOp );
99 : };
100 :
101 : typedef std::unordered_set<OpCode, std::hash<o3tl::underlying_type<OpCode>::type> > unordered_opcode_set;
102 :
103 : class FORMULA_DLLPUBLIC FormulaTokenArray
104 : {
105 : friend class FormulaCompiler;
106 : friend class FormulaTokenIterator;
107 : friend class FormulaMissingContext;
108 :
109 : protected:
110 : FormulaToken** pCode; // Token code array
111 : FormulaToken** pRPN; // RPN array
112 : sal_uInt16 nLen; // Length of token array
113 : sal_uInt16 nRPN; // Length of RPN array
114 : sal_uInt16 nIndex; // Current step index
115 : sal_uInt16 nError; // Error code
116 : ScRecalcMode nMode; // Flags to indicate when to recalc this code
117 : bool bHyperLink; // If HYPERLINK() occurs in the formula.
118 :
119 : protected:
120 : void Assign( const FormulaTokenArray& );
121 : void Assign( sal_uInt16 nCode, FormulaToken **pTokens );
122 :
123 : /// Also used by the compiler. The token MUST had been allocated with new!
124 : FormulaToken* Add( FormulaToken* );
125 : /** Also used by the compiler. The token MUST had been allocated with new!
126 : @param nOffset negative offset of token, 0==last, 1==previous, ...
127 : */
128 : FormulaToken* ReplaceToken( sal_uInt16 nOffset, FormulaToken* );
129 1157 : inline void SetCombinedBitsRecalcMode( ScRecalcMode nBits )
130 1157 : { nMode |= (nBits & ~RECALCMODE_EMASK); }
131 203 : inline ScRecalcMode GetCombinedBitsRecalcMode() const
132 203 : { return nMode & ~RECALCMODE_EMASK; }
133 : /** Exclusive bits already set in nMode are
134 : zero'ed, nBits may contain combined bits, but
135 : only one exclusive bit may be set! */
136 203 : inline void SetMaskedRecalcMode( ScRecalcMode nBits )
137 203 : { nMode = GetCombinedBitsRecalcMode() | nBits; }
138 :
139 : public:
140 : FormulaTokenArray();
141 : /// Assignment with references to FormulaToken entries (not copied!)
142 : FormulaTokenArray( const FormulaTokenArray& );
143 : virtual ~FormulaTokenArray();
144 : FormulaTokenArray* Clone() const; /// True copy!
145 :
146 : void Clear();
147 : void DelRPN();
148 5976 : FormulaToken* First() { nIndex = 0; return Next(); }
149 : FormulaToken* Next();
150 : FormulaToken* FirstNoSpaces() { nIndex = 0; return NextNoSpaces(); }
151 : FormulaToken* NextNoSpaces();
152 : FormulaToken* GetNextName();
153 : FormulaToken* GetNextReference();
154 : FormulaToken* GetNextReferenceRPN();
155 : FormulaToken* GetNextReferenceOrName();
156 : FormulaToken* GetNextColRowName();
157 : /// Peek at nIdx-1 if not out of bounds, decrements nIdx if successful. Returns NULL if not.
158 : FormulaToken* PeekPrev( sal_uInt16 & nIdx );
159 : FormulaToken* PeekNext();
160 : FormulaToken* PeekPrevNoSpaces(); /// Only after Reset/First/Next/Last/Prev!
161 : FormulaToken* PeekNextNoSpaces(); /// Only after Reset/First/Next/Last/Prev!
162 244 : FormulaToken* FirstRPN() { nIndex = 0; return NextRPN(); }
163 : FormulaToken* NextRPN();
164 0 : FormulaToken* LastRPN() { nIndex = nRPN; return PrevRPN(); }
165 : FormulaToken* PrevRPN();
166 :
167 : bool HasReferences() const;
168 :
169 : bool HasExternalRef() const;
170 : bool HasOpCode( OpCode ) const;
171 : bool HasOpCodeRPN( OpCode ) const;
172 : /// Token of type svIndex or opcode ocColRowName
173 : bool HasNameOrColRowName() const;
174 :
175 : /**
176 : * Check if the token array contains any of specified opcode tokens.
177 : *
178 : * @param rOpCodes collection of opcodes to check against.
179 : *
180 : * @return true if the token array contains at least one of the specified
181 : * opcode tokens, false otherwise.
182 : */
183 : bool HasOpCodes( const unordered_opcode_set& rOpCodes ) const;
184 :
185 4726 : FormulaToken** GetArray() const { return pCode; }
186 12274 : FormulaToken** GetCode() const { return pRPN; }
187 34301 : sal_uInt16 GetLen() const { return nLen; }
188 108328 : sal_uInt16 GetCodeLen() const { return nRPN; }
189 30609 : void Reset() { nIndex = 0; }
190 240043 : sal_uInt16 GetCodeError() const { return nError; }
191 1819 : void SetCodeError( sal_uInt16 n ) { nError = n; }
192 1555 : void SetHyperLink( bool bVal ) { bHyperLink = bVal; }
193 773 : bool IsHyperLink() const { return bHyperLink; }
194 :
195 768 : inline ScRecalcMode GetRecalcMode() const { return nMode; }
196 : /** Bits aren't set directly but validated and
197 : maybe handled according to priority if more
198 : than one exclusive bit was set. */
199 : void AddRecalcMode( ScRecalcMode nBits );
200 :
201 40200 : inline void ClearRecalcMode() { nMode = ScRecalcMode::NORMAL; }
202 1 : inline void SetExclusiveRecalcModeNormal()
203 1 : { SetMaskedRecalcMode( ScRecalcMode::NORMAL ); }
204 34 : inline void SetExclusiveRecalcModeAlways()
205 34 : { SetMaskedRecalcMode( ScRecalcMode::ALWAYS ); }
206 168 : inline void SetExclusiveRecalcModeOnLoad()
207 168 : { SetMaskedRecalcMode( ScRecalcMode::ONLOAD ); }
208 0 : inline void SetExclusiveRecalcModeOnLoadOnce()
209 0 : { SetMaskedRecalcMode( ScRecalcMode::ONLOAD_ONCE ); }
210 0 : inline void SetRecalcModeForced()
211 0 : { nMode |= ScRecalcMode::FORCED; }
212 : inline void ClearRecalcModeForced()
213 : { nMode &= ~ScRecalcMode::FORCED; }
214 120 : inline void SetRecalcModeOnRefMove()
215 120 : { nMode |= ScRecalcMode::ONREFMOVE; }
216 : inline void ClearRecalcModeOnRefMove()
217 : { nMode &= ~ScRecalcMode::ONREFMOVE; }
218 4308 : inline bool IsRecalcModeNormal() const
219 4308 : { return bool(nMode & ScRecalcMode::NORMAL); }
220 88415 : inline bool IsRecalcModeAlways() const
221 88415 : { return bool(nMode & ScRecalcMode::ALWAYS); }
222 1528 : inline bool IsRecalcModeOnLoad() const
223 1528 : { return bool(nMode & ScRecalcMode::ONLOAD); }
224 1376 : inline bool IsRecalcModeOnLoadOnce() const
225 1376 : { return bool(nMode & ScRecalcMode::ONLOAD_ONCE); }
226 50713 : inline bool IsRecalcModeForced() const
227 50713 : { return bool(nMode & ScRecalcMode::FORCED); }
228 507 : inline bool IsRecalcModeOnRefMove() const
229 507 : { return bool(nMode & ScRecalcMode::ONREFMOVE); }
230 :
231 : /** Get OpCode of the most outer function */
232 : inline OpCode GetOuterFuncOpCode();
233 :
234 : /** Operators +,-,*,/,^,&,=,<>,<,>,<=,>=
235 : with DoubleRef in Formula? */
236 : bool HasMatrixDoubleRefOps();
237 :
238 : virtual FormulaToken* AddOpCode(OpCode e);
239 :
240 : /** Adds the single token to array.
241 : Derived classes must override it when they want to support derived classes from FormulaToken.
242 : @return true when an error occurs
243 : */
244 : virtual bool AddFormulaToken(
245 : const css::sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool,
246 : ExternalReferenceHelper* pExtRef );
247 :
248 : /** fill the array with the tokens from the sequence.
249 : It calls AddFormulaToken for each token in the list.
250 : @param _aSequence the token to add
251 : @return true when an error occurs
252 : */
253 : bool Fill(
254 : const css::uno::Sequence<css::sheet::FormulaToken>& rSequence,
255 : svl::SharedStringPool& rSPool, ExternalReferenceHelper* pExtRef );
256 :
257 : /**
258 : * Do some checking based on the individual tokens. For now, we use this
259 : * only to check whether we can vectorize the token array.
260 : */
261 : virtual void CheckToken( const FormulaToken& t );
262 :
263 : FormulaToken* AddToken( const FormulaToken& );
264 : FormulaToken* AddString( const svl::SharedString& rStr );
265 : FormulaToken* AddDouble( double fVal );
266 : FormulaToken* AddExternal( const sal_Unicode* pStr );
267 : /** Xcl import may play dirty tricks with OpCode!=ocExternal.
268 : Others don't use! */
269 : FormulaToken* AddExternal( const OUString& rStr, OpCode eOp = ocExternal );
270 : FormulaToken* AddBad( const OUString& rStr ); /// ocBad with OUString
271 : FormulaToken* AddStringXML( const OUString& rStr ); /// ocStringXML with OUString, temporary during import
272 :
273 : virtual FormulaToken* MergeArray( );
274 :
275 : /// Assignment with references to FormulaToken entries (not copied!)
276 : FormulaTokenArray& operator=( const FormulaTokenArray& );
277 :
278 : /** Determines if this formula needs any changes to convert it to something
279 : previous versions of OOo could consume (Plain Old Formula, pre-ODFF, or
280 : also ODFF) */
281 : bool NeedsPodfRewrite( const MissingConventionODF & rConv );
282 :
283 : /** Determines if this formula needs any changes to convert it to OOXML. */
284 : bool NeedsOoxmlRewrite();
285 :
286 : /** Rewrites to Plain Old Formula or OOXML, substituting missing parameters. The
287 : FormulaTokenArray* returned is new'ed. */
288 : FormulaTokenArray* RewriteMissing( const MissingConvention & rConv );
289 :
290 : /** Determines if this formula may be followed by a reference. */
291 : bool MayReferenceFollow();
292 : };
293 :
294 0 : inline OpCode FormulaTokenArray::GetOuterFuncOpCode()
295 : {
296 0 : if ( pRPN && nRPN )
297 0 : return pRPN[nRPN-1]->GetOpCode();
298 0 : return ocNone;
299 : }
300 :
301 : class FORMULA_DLLPUBLIC FormulaTokenIterator
302 : {
303 : struct Item
304 : {
305 : public:
306 : const FormulaTokenArray* pArr;
307 : short nPC;
308 : short nStop;
309 :
310 : Item(const FormulaTokenArray* arr, short pc, short stop);
311 : };
312 :
313 : std::vector<Item> *maStack;
314 :
315 : public:
316 : FormulaTokenIterator( const FormulaTokenArray& );
317 : ~FormulaTokenIterator();
318 : void Reset();
319 : const FormulaToken* Next();
320 : const FormulaToken* PeekNextOperator();
321 : bool IsEndOfPath() const; /// if a jump or subroutine path is done
322 25 : bool HasStacked() const { return maStack->size() > 1; }
323 8 : short GetPC() const { return maStack->back().nPC; }
324 :
325 : /** Jump or subroutine call.
326 : Program counter values will be incremented before code is executed =>
327 : positions are to be passed with -1 offset.
328 : @param nStart
329 : Start on code at position nStart+1 (yes, pass with offset -1)
330 : @param nNext
331 : After subroutine continue with instruction at position nNext+1
332 : @param nStop
333 : Stop before reaching code at position nStop. If not specified the
334 : default is to either run the entire code, or to stop if an ocSep or
335 : ocClose is encountered, which are only present in ocIf or ocChoose
336 : jumps.
337 : */
338 : void Jump( short nStart, short nNext, short nStop = SHRT_MAX );
339 : void Push( const FormulaTokenArray* );
340 : void Pop();
341 :
342 : private:
343 : const FormulaToken* GetNonEndOfPathToken( short nIdx ) const;
344 : };
345 : } // formula
346 :
347 : #endif // INCLUDED_FORMULA_TOKENARRAY_HXX
348 :
349 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|