summaryrefslogtreecommitdiffstats
path: root/kspread/formula.h
blob: 2425e73dd569834207f1b867acb69e1c09231384 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
/* This file is part of the KDE project
   Copyright (C) 2003,2004 Ariya Hidayat <ariya@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#ifndef KSPREAD_FORMULA
#define KSPREAD_FORMULA

#include <qstring.h>
#include <qvaluevector.h>

class KLocale;

namespace KSpread
{
class Cell;
class Sheet;
class Value;

/**
 * Token
 */
class Token
{
  public:
    /**
     * token types
     */
    enum Type
    {
      Unknown = 0, ///< unknown type
      Boolean,     ///< True, False (also i18n-ized)
      Integer,     ///< 14, 3, 1977
      Float,       ///< 3.141592, 1e10, 5.9e-7
      String,      ///< "KOffice", "The quick brown fox..."
      Operator,    ///< +, *, /, -
      Cell,        ///< $A$1, F4, Sheet2!B5, 'Sales Forecast'!Sum
      Range,       ///< C1:C100
      Identifier   ///< function name or named area
    };

    /**
     * operator types
     */
    enum Op
    {
      InvalidOp = 0,  ///< invalid operator
      Plus,           ///<  + (addition)
      Minus,          ///<  - (substraction, negation)
      Asterisk,       ///<  * (multiplication)
      Slash,          ///<  / (division)
      Caret,          ///<  ^ (power)
      LeftPar,        ///<  (
      RightPar,       ///<  )
      Comma,          ///<  ,
      Semicolon,      ///<  ; (argument separator)
      Ampersand,      ///<  & (string concat)
      Equal,          ///<  =
      NotEqual,       ///<  <>
      Less,           ///<  <
      Greater,        ///<  >
      LessEqual,      ///<  <=
      GreaterEqual,   ///<  >=
      Percent         ///<  %
    };

    /**
     * Creates a token.
     */
    Token( Type type = Unknown, const QString& text = QString::null, int pos = -1 );

    static const Token null;

    Token( const Token& );
    Token& operator=( const Token& );

    /**
     * Returns type of the token.
     */
    Type type() const { return m_type; }

    /**
     * Returns text associated with the token.
     *
     * If you want to obtain meaningful value of this token, instead of
     * text(), you might use asInteger(), asFloat(), asString(), sheetName(),
     * etc.
     */
    QString text() const { return m_text; }

    int pos() const { return m_pos; };

    /**
     * Returns true if token is a boolean token.
     */
    bool isBoolean() const { return m_type == Boolean; }

    /**
     * Returns true if token is a integer token.
     */
    bool isInteger() const { return m_type == Integer; }

    /**
     * Returns true if token is a floating-point token.
     */
    bool isFloat() const { return m_type == Float; }

    /**
     * Returns true if token is either integer or floating-point token.
     */
    bool isNumber() const { return (m_type == Integer) || (m_type == Float); }

    /**
     * Returns true if token is a string token.
     */
    bool isString() const { return m_type == String; }

    /**
     * Returns true if token is an operator token.
     */
    bool isOperator() const { return m_type == Operator; }

    /**
     * Returns true if token is a cell reference token.
     */
    bool isCell() const { return m_type == Cell; }

    /**
     * Returns true if token is a range reference token.
     */
    bool isRange() const { return m_type == Range; }

    /**
     * Returns true if token is an identifier.
     */
    bool isIdentifier() const { return m_type == Identifier; }

    /**
     * Returns boolean value for an boolean token.
     * For any other type of token, return value is undefined.
     */
    bool asBoolean() const;

    /**
     * Returns integer value for an integer token.
     * For any other type of token, returns 0.
     */
    long asInteger() const;

    /**
     * Returns floating-point value for a floating-point token.
     * For any other type of token, returns 0.0.
     */
    double asFloat() const;

    /**
     * Returns string value for a string token.
     * For any other type of token, it returns QString::null.
     *
     * Note that token text for a string token still has leading and trailing
     * double-quotes, i.e for "KOffice", text() return "KOffice"
     * (with the quotes, 9 characters) while asString() only return KOffice
     * (without quotes, 7 characters).
     */
    QString asString() const;

    /**
     * Returns operator value for an operator token.
     * For any other type of token, returns Token::InvalidOp.
     */
    Op asOperator() const;

    /**
     * Returns sheet name in a cell reference token.
     * For any other type of token, it returns QString::null.
     *
     * If the cell reference doesn't specify sheet name, an empty string
     * is returned. As example, for "Sheet1!B3" , sheetName() returns
     * "Sheet1" while for "A2" sheetName() returns "".
     *
     * When sheet name contains quotes (as if the name has spaces) like
     * in "'Sales Forecast'!F4", sheetName() returns the name
     * without the quotes, i.e "Sales Forecast" in this case.
     */
    QString sheetName() const;

    /**
     * Returns a short description of the token.
     * Should be used only to assist debugging.
     */
    QString description() const;

  protected:

    Type m_type;
    QString m_text;
    int m_pos;

};

/**
 * Class Tokens represents array of tokens.
 *
 */
class Tokens: public QValueVector<Token>
{
public:
  Tokens(): QValueVector<Token>(), m_valid(true) {};
  bool valid() const { return m_valid; }
  void setValid( bool v ){ m_valid = v; }
protected:
  bool m_valid;
};


/**
 * Class Formula encapsulates a formula for a cell.
 *
 * A Formula is a equations which perform calculations on values in the cells
 * and sheets. Every formula must start with an equal sign (=).
 *
 *
 */
class Formula
{
  public:

    /**
     * Creates a formula. It must be owned by a sheet, and optionally sheet.
     */
    Formula (Sheet *sheet,  Cell *cell = 0);

    /**
     * Creates a formula that is not owned by any sheet.
     * This might be useful in some cases.
     */
    Formula();

    /**
     * Destroys the formula.
     */
    ~Formula();

    /**
     * Returns the cell which owns this formula.
     */
    Sheet* sheet() const;
    /**
     * Returns the cell which owns this formula.
     */
    Cell* cell() const;

    /**
     * Sets the expression for this formula.
     */
    void setExpression( const QString& expr );

    /**
     * Gets the expression of this formula.
     */
    QString expression() const;

    /**
     * Clears everything, makes as like a newly constructed formula.
     */
    void clear();

    /**
     * Returns true if the specified expression is valid, i.e. it contains
     * no parsing error.
     * Empty formula (i.e. without expression) is always invalid.
     */
    bool isValid() const;

    /**
     * Returns list of tokens associated with this formula. This has nothing to
     * with the formula evaluation but might be useful, e.g. for syntax
     * highlight or similar features.
     * If the formula contains error, the returned tokens is invalid.
     */
    Tokens tokens() const;

    /**
     * Evaluates the formula and returns the result.
     */
    Value eval() const;

    /**
     * Given an expression, this function separates it into tokens.
     * If the expression contains error (e.g. unknown operator, string no terminated)
     * this function returns tokens which is not valid.
     */
    Tokens scan( const QString& expr, KLocale* locale = 0 ) const;

    QString dump() const;

  protected:

    void compile( const Tokens& tokens ) const;

    /**
     * helper function: return true for valid named area
     */
    bool isNamedArea( const QString& expr ) const;

  private:
    class Private;
    Private *d;
    // no copy or assign
    Formula( const Formula& );
    Formula& operator=( const Formula& );
};

/**
 * Dumps the formula, should be used only to assist debugging.
 */
QTextStream& operator<<( QTextStream& ts, Formula formula );


/**
 * helper function: return operator of given token text
 * e.g. "*" yields Operator::Asterisk, and so on
 */
Token::Op matchOperator( const QString& text );

/**
 * helper function: return true for valid identifier character
 */
bool isIdentifier( QChar ch );

} // namespace KSpread



#endif // KSPREAD_FORMULA