1/* This file is part of the KDE project
2 Copyright (C) 2008-2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
3 Copyright (C) 2003,2004 Ariya Hidayat <ariya@kde.org>
4 Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; only
9 version 2 of the License.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22#include "Formula.h"
23
24#include "CalculationSettings.h"
25#include "Cell.h"
26#include "CellStorage.h"
27#include "Function.h"
28#include "FunctionRepository.h"
29#include "Sheet.h"
30#include "Map.h"
31#include "NamedAreaManager.h"
32#include "Region.h"
33#include "Value.h"
34#include "Util.h"
35
36#include "ValueCalc.h"
37#include "ValueConverter.h"
38#include "ValueParser.h"
39
40#include <limits.h>
41
42#include <QStack>
43#include <QString>
44#include <QTextStream>
45
46#include <klocale.h>
47
48#define CALLIGRA_SHEETS_UNICODE_OPERATORS
49
50/*
51 To understand how this formula engine works, please refer to the documentation
52 in file DESIGN.html.
53
54 Useful references:
55 - "Principles of Compiler Design", A.V.Aho, J.D.Ullman, Addison Wesley, 1978
56 - "Writing Interactive Compilers and Interpreters", P.J. Brown,
57 John Wiley and Sons, 1979.
58 - "The Theory and Practice of Compiler Writing", J.Tremblay, P.G.Sorenson,
59 McGraw-Hill, 1985.
60 - "The Java(TM) Virtual Machine Specification", T.Lindholm, F.Yellin,
61 Addison-Wesley, 1997.
62 - "Java Virtual Machine", J.Meyer, T.Downing, O'Reilly, 1997.
63
64 */
65
66
67/*
68TODO - features:
69- handle Intersection
70- cell reference is made relative (absolute now)
71- shared formula (different owner, same data)
72- relative internal representation (independent of owner)
73- OASIS support
74TODO - optimizations:
75- handle initial formula marker = (and +)
76- reuse constant already in the pool
77- reuse references already in the pool
78- expression optimization (e.g. 1+2+A1 becomes 3+A1)
79*/
80
81namespace Calligra
82{
83namespace Sheets
84{
85
86class Opcode
87{
88public:
89
90 enum { Nop = 0, Load, Ref, Cell, Range, Function, Add, Sub, Neg, Mul, Div,
91 Pow, Concat, Intersect, Not, Equal, Less, Greater, Array, Union
92 };
93
94 unsigned type;
95 unsigned index;
96
97 Opcode(): type(Nop), index(0) {}
98 Opcode(unsigned t): type(t), index(0) {}
99 Opcode(unsigned t, unsigned i): type(t), index(i) {}
100};
101
102// used when evaluation formulas
103struct stackEntry {
104 void reset() {
105 row1 = col1 = row2 = col2 = -1;
106 reg = Calligra::Sheets::Region();
107 regIsNamedOrLabeled = false;
108 }
109 Value val;
110 Calligra::Sheets::Region reg;
111 bool regIsNamedOrLabeled;
112 int row1, col1, row2, col2;
113};
114
115class Formula::Private : public QSharedData
116{
117public:
118 Cell cell;
119 Sheet *sheet;
120 mutable bool dirty;
121 mutable bool valid;
122 QString expression;
123 mutable QVector<Opcode> codes;
124 mutable QVector<Value> constants;
125
126 Value valueOrElement(FuncExtra &fe, const stackEntry& entry) const;
127};
128
129class TokenStack : public QVector<Token>
130{
131public:
132 TokenStack();
133 unsigned itemCount() const;
134 void push(const Token& token);
135 Token pop();
136 const Token& top();
137 const Token& top(unsigned index);
138};
139
140} // namespace Sheets
141} // namespace Calligra
142
143using namespace Calligra::Sheets;
144
145// for null token
146const Token Token::null;
147
148// helper function: return operator of given token text
149// e.g. '*' yields Operator::Asterisk, and so on
150Token::Op Calligra::Sheets::matchOperator(const QString& text)
151{
152 Token::Op result = Token::InvalidOp;
153
154 if (text.length() == 1) {
155 QChar p = text[0];
156 switch (p.unicode()) {
157 case '+': result = Token::Plus; break;
158 case '-': result = Token::Minus; break;
159 case '*': result = Token::Asterisk; break;
160 case '/': result = Token::Slash; break;
161 case '^': result = Token::Caret; break;
162 case ',': result = Token::Comma; break;
163 case ';': result = Token::Semicolon; break;
164 case ' ': result = Token::Intersect; break;
165 case '(': result = Token::LeftPar; break;
166 case ')': result = Token::RightPar; break;
167 case '&': result = Token::Ampersand; break;
168 case '=': result = Token::Equal; break;
169 case '<': result = Token::Less; break;
170 case '>': result = Token::Greater; break;
171 case '%': result = Token::Percent; break;
172 case '~': result = Token::Union; break;
173#ifdef CALLIGRA_SHEETS_INLINE_ARRAYS
174 case '{': result = Token::CurlyBra; break;
175 case '}': result = Token::CurlyKet; break;
176 case '|': result = Token::Pipe; break;
177#endif
178#ifdef CALLIGRA_SHEETS_UNICODE_OPERATORS
179 case 0x2212: result = Token::Minus; break;
180 case 0x00D7: result = Token::Asterisk; break;
181 case 0x00F7: result = Token::Slash; break;
182 case 0x2215: result = Token::Slash; break;
183#endif
184 default : result = Token::InvalidOp; break;
185 }
186 }
187
188 if (text.length() == 2) {
189 if (text == "<>") result = Token::NotEqual;
190 if (text == "!=") result = Token::NotEqual;
191 if (text == "<=") result = Token::LessEqual;
192 if (text == ">=") result = Token::GreaterEqual;
193 if (text == "==") result = Token::Equal;
194 }
195
196 return result;
197}
198
199bool Calligra::Sheets::parseOperator(const QChar *&data, QChar *&out)
200{
201 bool retval = true;
202 switch(data->unicode()) {
203 case '+':
204 case '-':
205 case '*':
206 case '/':
207 case '^':
208 case ',':
209 case ';':
210 case ' ':
211 case '(':
212 case ')':
213 case '&':
214 case '%':
215 case '~':
216#ifdef CALLIGRA_SHEETS_INLINE_ARRAYS
217 case '{':
218 case '}':
219 case '|':
220#endif
221#ifdef CALLIGRA_SHEETS_UNICODE_OPERATORS
222 case 0x2212:
223 case 0x00D7:
224 case 0x00F7:
225 case 0x2215:
226#endif
227 *out = *data;
228 ++out;
229 ++data;
230 break;
231 case '<':
232 *out = *data;
233 ++out;
234 ++data;
235 if (!data->isNull()) {
236 if (*data == QChar('>', 0) || *data == QChar('=', 0)) {
237 *out = *data;
238 ++out;
239 ++data;
240 }
241 }
242 break;
243 case '>':
244 *out = *data;
245 ++out;
246 ++data;
247 if (!data->isNull() && *data == QChar('=', 0)) {
248 *out = *data;
249 ++out;
250 ++data;
251 }
252 break;
253 case '=':
254 *out++ = *data++;
255 if (!data->isNull() && *data == QChar('=', 0)) {
256 *out++ = *data++;
257 }
258 break;
259 case '!': {
260 const QChar * next = data + 1;
261 if (!next->isNull() && *next == QChar('=', 0)) {
262 *out = *data;
263 ++out;
264 ++data;
265 *out = *data;
266 ++out;
267 ++data;
268 }
269 else {
270 retval = false;
271 }
272 } break;
273 default:
274 retval = false;
275 break;
276 }
277 return retval;
278}
279
280// helper function: give operator precedence
281// e.g. '+' is 1 while '*' is 3
282static int opPrecedence(Token::Op op)
283{
284 int prec = -1;
285 switch (op) {
286 case Token::Percent : prec = 8; break;
287 case Token::Caret : prec = 7; break;
288 case Token::Asterisk : prec = 5; break;
289 case Token::Slash : prec = 6; break;
290 case Token::Plus : prec = 3; break;
291 case Token::Minus : prec = 3; break;
292 case Token::Union : prec = 2; break;
293 case Token::Ampersand : prec = 2; break;
294 case Token::Intersect : prec = 2; break;
295 case Token::Equal : prec = 1; break;
296 case Token::NotEqual : prec = 1; break;
297 case Token::Less : prec = 1; break;
298 case Token::Greater : prec = 1; break;
299 case Token::LessEqual : prec = 1; break;
300 case Token::GreaterEqual : prec = 1; break;
301#ifdef CALLIGRA_SHEETS_INLINE_ARRAYS
302 // FIXME Stefan: I don't know whether zero is right for this case. :-(
303 case Token::CurlyBra : prec = 0; break;
304 case Token::CurlyKet : prec = 0; break;
305 case Token::Pipe : prec = 0; break;
306#endif
307 case Token::Semicolon : prec = 0; break;
308 case Token::RightPar : prec = 0; break;
309 case Token::LeftPar : prec = -1; break;
310 default: prec = -1; break;
311 }
312 return prec;
313}
314
315// helper function
316static Value tokenAsValue(const Token& token)
317{
318 Value value;
319 if (token.isBoolean()) value = Value(token.asBoolean());
320 else if (token.isInteger()) value = Value(token.asInteger());
321 else if (token.isFloat()) value = Value(token.asFloat());
322 else if (token.isString()) value = Value(token.asString());
323 else if (token.isError()) {
324 const QString error = token.asError();
325 if (error == Value::errorCIRCLE().errorMessage())
326 value = Value::errorCIRCLE();
327 else if (error == Value::errorDEPEND().errorMessage())
328 value = Value::errorDEPEND();
329 else if (error == Value::errorDIV0().errorMessage())
330 value = Value::errorDIV0();
331 else if (error == Value::errorNA().errorMessage())
332 value = Value::errorNA();
333 else if (error == Value::errorNAME().errorMessage())
334 value = Value::errorNAME();
335 else if (error == Value::errorNUM().errorMessage())
336 value = Value::errorNUM();
337 else if (error == Value::errorNULL().errorMessage())
338 value = Value::errorNULL();
339 else if (error == Value::errorPARSE().errorMessage())
340 value = Value::errorPARSE();
341 else if (error == Value::errorREF().errorMessage())
342 value = Value::errorREF();
343 else if (error == Value::errorVALUE().errorMessage())
344 value = Value::errorVALUE();
345 else {
346 value = Value(Value::Error);
347 value.setError(error);
348 }
349 }
350 return value;
351}
352
353/**********************
354 Token
355 **********************/
356
357// creates a token
358Token::Token(Type type, const QString& text, int pos)
359: m_type(type)
360, m_text(text)
361, m_pos(pos)
362{
363 // the detach is needed as we manipulate the string we use as input afterwards
364 // by writing to QChar * data point which does nto detach automatically.
365 m_text.detach();
366}
367
368// copy constructor
369Token::Token(const Token& token)
370: m_type(token.m_type)
371, m_text(token.m_text)
372, m_pos(token.m_pos)
373{
374}
375
376// assignment operator
377Token& Token::operator=(const Token & token)
378{
379 m_type = token.m_type;
380 m_text = token.m_text;
381 m_pos = token.m_pos;
382 return *this;
383}
384
385bool Token::asBoolean() const
386{
387 if (!isBoolean()) return false;
388 return m_text.toLower() == "true";
389 // FIXME check also for i18n version
390}
391
392qint64 Token::asInteger() const
393{
394 if (isInteger()) return m_text.toLongLong();
395 else return 0;
396}
397
398double Token::asFloat() const
399{
400 if (isFloat()) return m_text.toDouble();
401 else return 0.0;
402}
403
404QString Token::asString() const
405{
406 if (isString()) return m_text.mid(1, m_text.length() - 2);
407 else return QString();
408}
409
410QString Token::asError() const
411{
412 if (isError())
413 return m_text;
414 else
415 return QString();
416}
417
418Token::Op Token::asOperator() const
419{
420 if (isOperator()) return matchOperator(m_text);
421 else return InvalidOp;
422}
423
424QString Token::sheetName() const
425{
426 if (!isCell() && !isRange()) return QString();
427 int i = m_text.indexOf('!');
428 if (i < 0) return QString();
429 QString sheet = m_text.left(i);
430 return sheet;
431}
432
433QString Token::description() const
434{
435 QString desc;
436
437 switch (m_type) {
438 case Boolean: desc = "Boolean"; break;
439 case Integer: desc = "Integer"; break;
440 case Float: desc = "Float"; break;
441 case String: desc = "String"; break;
442 case Identifier: desc = "Identifier"; break;
443 case Cell: desc = "Cell"; break;
444 case Range: desc = "Range"; break;
445 case Operator: desc = "Operator"; break;
446 case Error: desc = "Error"; break;
447 default: desc = "Unknown"; break;
448 }
449
450 while (desc.length() < 10) desc.prepend(' ');
451 desc.prepend(" ");
452 desc.prepend(QString::number(m_pos));
453 desc.append(" : ").append(m_text);
454
455 return desc;
456}
457
458
459/**********************
460 TokenStack
461 **********************/
462
463TokenStack::TokenStack(): QVector<Token>()
464{
465}
466
467unsigned TokenStack::itemCount() const
468{
469 return size();
470}
471
472void TokenStack::push(const Token& token)
473{
474 append(token);
475}
476
477Token TokenStack::pop()
478{
479 if (!isEmpty()) {
480 Token token = last();
481 pop_back();
482 return token;
483 }
484 return Token();
485}
486
487const Token& TokenStack::top()
488{
489 return top(0);
490}
491
492const Token& TokenStack::top(unsigned index)
493{
494 unsigned top = size();
495 if (top > index)
496 return at(top - index - 1);
497 return Token::null;
498}
499
500
501/**********************
502 FormulaPrivate
503 **********************/
504
505// helper function: return true for valid identifier character
506bool Calligra::Sheets::isIdentifier(QChar ch)
507{
508 switch(ch.unicode()) {
509 case '_':
510 case '$':
511 case '.':
512 return true;
513 default:
514 return ch.isLetter();
515 }
516}
517
518
519
520
521/**********************
522 Formula
523 **********************/
524
525// Constructor
526
527Formula::Formula(Sheet *sheet, const Cell& cell)
528 : d(new Private)
529{
530 d->cell = cell;
531 d->sheet = sheet;
532 clear();
533}
534
535Formula::Formula(Sheet *sheet)
536 : d(new Private)
537{
538 d->cell = Cell();
539 d->sheet = sheet;
540 clear();
541}
542
543Formula::Formula()
544 : d(new Private)
545{
546 d->cell = Cell();
547 d->sheet = 0;
548 clear();
549}
550
551Formula Formula::empty()
552{
553 static Formula f;
554 return f;
555}
556
557Formula::Formula(const Formula& other)
558 : d(other.d)
559{
560}
561
562// Destructor
563
564Formula::~Formula()
565{
566}
567
568const Cell& Formula::cell() const
569{
570 return d->cell;
571}
572
573Sheet* Formula::sheet() const
574{
575 return d->sheet;
576}
577
578// Sets a new expression for this formula.
579// note that both the real lex and parse processes will happen later on
580// when needed (i.e. "lazy parse"), for example during formula evaluation.
581
582void Formula::setExpression(const QString& expr)
583{
584 d->expression = expr;
585 d->dirty = true;
586 d->valid = false;
587}
588
589// Returns the expression associated with this formula.
590
591QString Formula::expression() const
592{
593 return d->expression;
594}
595
596// Returns the validity of the formula.
597// note: empty formula is always invalid.
598
599bool Formula::isValid() const
600{
601 if (d->dirty) {
602 KLocale* locale = !d->cell.isNull() ? d->cell.locale() : 0;
603 if ((!locale) && d->sheet)
604 locale = d->sheet->map()->calculationSettings()->locale();
605 Tokens tokens = scan(d->expression, locale);
606
607 if (tokens.valid())
608 compile(tokens);
609 else
610 d->valid = false;
611 }
612 return d->valid;
613}
614
615// Clears everything, also mark the formula as invalid.
616
617void Formula::clear()
618{
619 d->expression.clear();
620 d->dirty = true;
621 d->valid = false;
622 d->constants.clear();
623 d->codes.clear();
624}
625
626// Returns list of token for the expression.
627// this triggers again the lexical analysis step. it is however preferable
628// (even when there's small performance penalty) because otherwise we need to
629// store parsed tokens all the time which serves no good purpose.
630
631Tokens Formula::tokens() const
632{
633 KLocale* locale = !d->cell.isNull() ? d->cell.locale() : 0;
634 if ((!locale) && d->sheet)
635 locale = d->sheet->map()->calculationSettings()->locale();
636 return scan(d->expression, locale);
637}
638
639Tokens Formula::scan(const QString &expr, const KLocale* locale) const
640{
641 // parsing state
642 enum { Start, Finish, InNumber, InDecimal, InExpIndicator, InExponent,
643 InString, InIdentifier, InCell, InRange, InSheetOrAreaName, InError
644 } state;
645
646 // use locale settings if specified
647 QString thousand = locale ? locale->thousandsSeparator() : "";
648 QString decimal = locale ? locale->decimalSymbol() : ".";
649
650 const QChar *data = expr.constData();
651
652 Tokens tokens;
653 if (data->isNull() || *data != QChar('=', 0)) {
654 return tokens;
655 }
656 tokens.reserve(50);
657
658 ++data;
659 const QChar * const start = data;
660 const QChar * const end = start + expr.length();
661 const QChar *tokenStart = data;
662 const QChar *cellStart = data;
663
664 state = Start;
665 bool parseError = false;
666
667 int length = expr.length() * 1.1; // TODO check if that is needed at all
668 QString token(length, QChar());
669 token.reserve(length); // needed to not realloc at the resize at the end
670 QChar * out = token.data();
671 QChar * const outStart = token.data();
672
673 while (state != Finish && data < end) {
674 switch (state) {
675 case Start:
676 tokenStart = data;
677 // Whitespaces can be used as intersect-operator for two arrays.
678 if (data->isSpace()) {
679 ++data;
680 }
681 // check for number
682 else if (data->isDigit()) {
683 state = InNumber;
684 *out++ = *data++;
685 }
686 // terminator character
687 else if (data->isNull()) {
688 state = Finish;
689 }
690 else {
691 switch (data->unicode()) {
692 case '"': // a string ?
693 *out++ = *data++;
694 state = InString;
695 break;
696 case '\'': // aposthrophe (') marks sheet name for 3-d cell, e.g 'Sales Q3'!A4, or a named range
697 ++data;
698 state = InSheetOrAreaName;
699 break;
700 case '#': // error value?
701 *out++ = *data++;
702 state = InError;
703 break;
704 default:
705 // decimal dot ?
706 if (*data == decimal[0]) {
707 *out++ = *data++;
708 state = InDecimal;
709 }
710 // beginning with alphanumeric ?
711 // could be identifier, cell, range, or function...
712 else if (isIdentifier(*data)) {
713 *out++ = *data++;
714 state = InIdentifier;
715 }
716 else {
717 // look for operator match
718 if (parseOperator(data, out)) {
719 token.resize(out - outStart);
720 tokens.append(Token(Token::Operator, token, tokenStart - start));
721 token.resize(length);
722 out = outStart;
723 }
724 else {
725 // not matched an operator, add an Unknown token and remember we had a parse error
726 parseError = true;
727 *out++ = *data++;
728 token.resize(out - outStart);
729 tokens.append(Token(Token::Unknown, token, tokenStart - start));
730 token.resize(length);
731 out = outStart;
732 }
733 }
734 break;
735 }
736 }
737 break;
738 case InIdentifier:
739 // consume as long as alpha, dollar sign, underscore, or digit
740 if (isIdentifier(*data) || data->isDigit()) {
741 *out = *data;
742 ++out;
743 ++data;
744 }
745 // a '!' ? then this must be sheet name, e.g "Sheet4!", unless the next character is '='
746 else if (*data == QChar('!', 0) && !(data + 1)->isNull() && *(data + 1) != QChar('=', 0)) {
747 *out++ = *data++;
748 cellStart = out;
749 state = InCell;
750 }
751 // a '(' ? then this must be a function identifier
752 else if (*data == QChar('(', 0)) {
753 token.resize(out - outStart);
754 tokens.append(Token(Token::Identifier, token, tokenStart - start));
755 token.resize(length);
756 out = outStart;
757 state = Start;
758 }
759 // we're done with identifier
760 else {
761 *out = QChar();
762 // check for cell reference, e.g A1, VV123, ...
763 if (Util::isCellReference(token)) {
764 // so up to now we've got something like A2 or Sheet2!F4
765 // check for range reference
766 if (*data == QChar(':', 0)) {
767 *out++ = *data++;
768 state = InRange;
769 }
770 // we're done with cell reference
771 else {
772 token.resize(out - outStart);
773 tokens.append(Token(Token::Cell, token, tokenStart - start));
774 token.resize(length);
775 out = outStart;
776 state = Start;
777 }
778 }
779 else {
780 token.resize(out - outStart);
781 if (isNamedArea(token)) {
782 tokens.append(Token(Token::Range, token, tokenStart - start));
783 }
784 else {
785 tokens.append(Token(Token::Identifier, token, tokenStart - start));
786 }
787 token.resize(length);
788 out = outStart;
789 state = Start;
790 }
791 }
792 break;
793 case InCell:
794 // consume as long as alpha, dollar sign, underscore, or digit
795 if (isIdentifier(*data) || data->isDigit()) {
796 *out++ = *data++;
797 }
798 else {
799 *out = QChar();
800 // check if it's a cell ref like A32, not named area
801 if (!Util::isCellReference(token, cellStart - outStart)) {
802 // test failed, means we have something like "Sheet2!TotalSales"
803 // and not "Sheet2!A2"
804 // thus, assume so far that it's a named area
805 token.resize(out - outStart);
806 tokens.append(Token(Token::Range, token, tokenStart - start));
807 token.resize(length);
808 out = outStart;
809 state = Start;
810 }
811 else {
812 // so up to now we've got something like A2 or Sheet2!F4
813 // check for range reference
814 if (*data == QChar(':', 0)) {
815 *out++ = *data++;
816 state = InRange;
817 }
818 else {
819 // we're done with cell reference
820 token.resize(out - outStart);
821 tokens.append(Token(Token::Cell, token, tokenStart - start));
822 token.resize(length);
823 out = outStart;
824 state = Start;
825 }
826 }
827 }
828 break;
829 case InRange:
830 // consume as long as alpha, dollar sign, underscore, or digit or !
831 if (isIdentifier(*data) || data->isDigit() || *data == QChar('!', 0)) {
832 *out++ = *data++;
833 }
834 // we're done with range reference
835 else {
836 token.resize(out - outStart);
837 tokens.append(Token(Token::Range, token, tokenStart - start));
838 token.resize(length);
839 out = outStart;
840 state = Start;
841 }
842 break;
843 case InSheetOrAreaName:
844 // consume until '
845 if (data->isNull()) {
846 parseError = true;
847 token.resize(out - outStart);
848 tokens.append(Token(Token::Unknown, '\'' + token + '\'', tokenStart - start));
849 state = Start;
850 }
851 else if (*data != QChar('\'', 0)) {
852 *out++ = *data++;
853 }
854 else {
855 // eat the aposthrophe itself
856 ++data;
857 // must be followed by '!' to be sheet name
858 if (!data->isNull() && *data == QChar('!', 0)) {
859 *out++ = *data++;
860 cellStart = out;
861 state = InCell;
862 }
863 else {
864 token.resize(out - outStart);
865 if (isNamedArea(token)) {
866 tokens.append(Token(Token::Range, token, tokenStart - start));
867 }
868 else {
869 // for compatibility with oocalc (and the openformula spec), don't parse single-quoted
870 // text as an identifier, instead add an Unknown token and remember we had an error
871 parseError = true;
872 tokens.append(Token(Token::Unknown, '\'' + token + '\'', tokenStart - start));
873 }
874 token.resize(length);
875 out = outStart;
876 state = Start;
877 }
878 }
879 break;
880 case InNumber:
881 // consume as long as it's digit
882 if (data->isDigit()) {
883 *out++ = *data++;
884 }
885 // skip thousand separator
886 else if (!thousand.isEmpty() && (*data == thousand[0])) {
887 ++data;
888 }
889 // convert decimal separator to '.', also support '.' directly
890 // we always support '.' because of bug #98455
891 else if ((!decimal.isEmpty() && (*data == decimal[0])) || *data == QChar('.', 0)) {
892 *out++ = QChar('.', 0);
893 ++data;
894 state = InDecimal;
895 }
896 // exponent ?
897 else if (*data == QChar('E', 0) || *data == QChar('e', 0)) {
898 *out++ = QChar('E', 0);
899 ++data;
900 state = InExpIndicator;
901 }
902 // reference sheet delimiter?
903 else if (*data == QChar('!', 0)) {
904 *out++ = *data++;
905 cellStart = out;
906 state = InCell;
907 }
908 // identifier?
909 else if (isIdentifier(*data)) {
910 // has to be a sheet or area name then
911 *out++ = *data++;
912 state = InIdentifier;
913 }
914 // we're done with integer number
915 else {
916 token.resize(out - outStart);
917 tokens.append(Token(Token::Integer, token, tokenStart - start));
918 token.resize(length);
919 out = outStart;
920 state = Start;
921 }
922 break;
923 case InDecimal:
924 // consume as long as it's digit
925 if (data->isDigit()) {
926 *out++ = *data++;
927 }
928 // exponent ?
929 else if (*data == QChar('E', 0) || *data == QChar('e', 0)) {
930 *out++ = QChar('E', 0);
931 ++data;
932 state = InExpIndicator;
933 }
934 // we're done with floating-point number
935 else {
936 token.resize(out - outStart);
937 tokens.append(Token(Token::Float, token, tokenStart - start));
938 token.resize(length);
939 out = outStart;
940 state = Start;
941 }
942 break;
943 case InExpIndicator:
944 // possible + or - right after E, e.g 1.23E+12 or 4.67E-8
945 if (*data == QChar('+', 0) || *data == QChar('-', 0)) {
946 *out++ = *data++;
947 }
948 // consume as long as it's digit
949 else if (data->isDigit()) {
950 *out++ = *data++;
951 state = InExponent;
952 }
953 // invalid thing here
954 else {
955 parseError = true;
956 token.resize(out - outStart);
957 tokens.append(Token(Token::Unknown, token, tokenStart - start));
958 token.resize(length);
959 out = outStart;
960 state = Start;
961 }
962 break;
963 case InExponent:
964 // consume as long as it's digit
965 if (data->isDigit()) {
966 *out++ = *data++;
967 }
968 // we're done with floating-point number
969 else {
970 token.resize(out - outStart);
971 tokens.append(Token(Token::Float, token, tokenStart - start));
972 token.resize(length);
973 out = outStart;
974 state = Start;
975 }
976 break;
977 case InString:
978 // consume until "
979 if (*data != QChar('"', 0)) {
980 *out++ = *data++;
981 }
982 else {
983 *out++ = *data++;
984 // check for escaped ""
985 if (data->isNull() || *data != QChar('"', 0)) {
986 token.resize(out - outStart);
987 tokens.append(Token(Token::String, token, tokenStart - start));
988 token.resize(length);
989 out = outStart;
990 state = Start;
991 }
992 else {
993 ++data;
994 }
995 }
996 break;
997 case InError: {
998 ushort c = data->unicode();
999 switch (c) {
1000 case '!':
1001 case '?':
1002 // TODO check if there is at least one char that needs to be there
1003 *out++ = *data++;
1004 token.resize(out - outStart);
1005 tokens.append(Token(Token::Error, token, tokenStart - start));
1006 token.resize(length);
1007 out = outStart;
1008 state = Start;
1009 break;
1010 case '/':
1011 *out++ = *data++;
1012 if (!data->isNull()) {
1013 bool error = false;
1014 if (*data >= 'A' && *data <= 'Z') {
1015 *out++ = *data++;
1016 }
1017 else if (*data >= '0' && *data <= '9'){
1018 *out++ = *data++;
1019 if (!data->isNull() && (*data == QChar('!', 0) || *data == QChar('?', 0))) {
1020 *out++ = *data++;
1021 }
1022 }
1023 else {
1024 error = true;
1025 }
1026 if (error) {
1027 parseError = true;
1028 token.resize(out - outStart);
1029 tokens.append(Token(Token::Unknown, token, tokenStart - start));
1030 token.resize(length);
1031 out = outStart;
1032 state = Start;
1033 }
1034 else {
1035 token.resize(out - outStart);
1036 tokens.append(Token(Token::Error, token, tokenStart - start));
1037 token.resize(length);
1038 out = outStart;
1039 state = Start;
1040 }
1041 }
1042 break;
1043 default:
1044 if ((c >= 'A' && c <= 'Z') || (c >= '0' && c<= '9')) {
1045 *out++ = *data++;
1046 }
1047 else {
1048 parseError = true;
1049 token.resize(out - outStart);
1050 tokens.append(Token(Token::Unknown, token, tokenStart - start));
1051 token.resize(length);
1052 out = outStart;
1053 state = Start;
1054 }
1055 break;
1056 }
1057 } break;
1058 default:
1059 break;
1060 }
1061 }
1062
1063 // parse error if any text remains
1064 if (data+1 < end) {
1065 tokens.append(Token(Token::Unknown, expr.mid(tokenStart - start), tokenStart - start));
1066 parseError = true;
1067 }
1068
1069 if (parseError)
1070 tokens.setValid(false);
1071 return tokens;
1072}
1073
1074// will affect: dirty, valid, codes, constants
1075void Formula::compile(const Tokens& tokens) const
1076{
1077 // initialize variables
1078 d->dirty = false;
1079 d->valid = false;
1080 d->codes.clear();
1081 d->constants.clear();
1082
1083 // sanity check
1084 if (tokens.count() == 0) return;
1085
1086 TokenStack syntaxStack;
1087 QStack<int> argStack;
1088 unsigned argCount = 1;
1089
1090 for (int i = 0; i <= tokens.count(); i++) {
1091 // helper token: InvalidOp is end-of-formula
1092 Token token = (i < tokens.count()) ? tokens[i] : Token(Token::Operator);
1093 Token::Type tokenType = token.type();
1094
1095 // unknown token is invalid
1096 if (tokenType == Token::Unknown) break;
1097
1098 // are we entering a function ?
1099 // if stack already has: id (
1100 if (syntaxStack.itemCount() >= 2) {
1101 Token par = syntaxStack.top();
1102 Token id = syntaxStack.top(1);
1103 if (par.asOperator() == Token::LeftPar)
1104 if (id.isIdentifier()) {
1105 argStack.push(argCount);
1106 argCount = 1;
1107 }
1108 }
1109
1110#ifdef CALLIGRA_SHEETS_INLINE_ARRAYS
1111 // are we entering an inline array ?
1112 // if stack already has: {
1113 if (syntaxStack.itemCount() >= 1) {
1114 Token bra = syntaxStack.top();
1115 if (bra.asOperator() == Token::CurlyBra) {
1116 argStack.push(argCount);
1117 argStack.push(1); // row count
1118 argCount = 1;
1119 }
1120 }
1121#endif
1122
1123 // for constants, push immediately to stack
1124 // generate code to load from a constant
1125 if ((tokenType == Token::Integer) || (tokenType == Token::Float) ||
1126 (tokenType == Token::String) || (tokenType == Token::Boolean) ||
1127 (tokenType == Token::Error)) {
1128 syntaxStack.push(token);
1129 d->constants.append(tokenAsValue(token));
1130 d->codes.append(Opcode(Opcode::Load, d->constants.count() - 1));
1131 }
1132
1133 // for cell, range, or identifier, push immediately to stack
1134 // generate code to load from reference
1135 if ((tokenType == Token::Cell) || (tokenType == Token::Range) ||
1136 (tokenType == Token::Identifier)) {
1137 syntaxStack.push(token);
1138 d->constants.append(Value(token.text()));
1139 if (tokenType == Token::Cell)
1140 d->codes.append(Opcode(Opcode::Cell, d->constants.count() - 1));
1141 else if (tokenType == Token::Range)
1142 d->codes.append(Opcode(Opcode::Range, d->constants.count() - 1));
1143 else
1144 d->codes.append(Opcode(Opcode::Ref, d->constants.count() - 1));
1145 }
1146
1147 // special case for percentage
1148 if (tokenType == Token::Operator)
1149 if (token.asOperator() == Token::Percent)
1150 if (syntaxStack.itemCount() >= 1)
1151 if (!syntaxStack.top().isOperator()) {
1152 d->constants.append(Value(0.01));
1153 d->codes.append(Opcode(Opcode::Load, d->constants.count() - 1));
1154 d->codes.append(Opcode(Opcode::Mul));
1155 }
1156
1157 // for any other operator, try to apply all parsing rules
1158 if (tokenType == Token::Operator)
1159 if (token.asOperator() != Token::Percent) {
1160 // repeat until no more rule applies
1161 for (; ;) {
1162 bool ruleFound = false;
1163
1164 // rule for function arguments, if token is ; or )
1165 // id ( arg1 ; arg2 -> id ( arg
1166 if (!ruleFound)
1167 if (syntaxStack.itemCount() >= 5)
1168 if ((token.asOperator() == Token::RightPar) ||
1169 (token.asOperator() == Token::Semicolon)) {
1170 Token arg2 = syntaxStack.top();
1171 Token sep = syntaxStack.top(1);
1172 Token arg1 = syntaxStack.top(2);
1173 Token par = syntaxStack.top(3);
1174 Token id = syntaxStack.top(4);
1175 if (!arg2.isOperator())
1176 if (sep.asOperator() == Token::Semicolon)
1177 if (!arg1.isOperator())
1178 if (par.asOperator() == Token::LeftPar)
1179 if (id.isIdentifier()) {
1180 ruleFound = true;
1181 syntaxStack.pop();
1182 syntaxStack.pop();
1183 argCount++;
1184 }
1185 }
1186
1187 // rule for empty function arguments, if token is ; or )
1188 // id ( arg ; -> id ( arg
1189 if (!ruleFound)
1190 if (syntaxStack.itemCount() >= 3)
1191 if ((token.asOperator() == Token::RightPar) ||
1192 (token.asOperator() == Token::Semicolon)) {
1193 Token sep = syntaxStack.top();
1194 Token arg = syntaxStack.top(1);
1195 Token par = syntaxStack.top(2);
1196 Token id = syntaxStack.top(3);
1197 if (sep.asOperator() == Token::Semicolon)
1198 if (!arg.isOperator())
1199 if (par.asOperator() == Token::LeftPar)
1200 if (id.isIdentifier()) {
1201 ruleFound = true;
1202 syntaxStack.pop();
1203 d->constants.append(Value::null());
1204 d->codes.append(Opcode(Opcode::Load, d->constants.count() - 1));
1205 argCount++;
1206 }
1207 }
1208
1209 // rule for function last argument:
1210 // id ( arg ) -> arg
1211 if (!ruleFound)
1212 if (syntaxStack.itemCount() >= 4) {
1213 Token par2 = syntaxStack.top();
1214 Token arg = syntaxStack.top(1);
1215 Token par1 = syntaxStack.top(2);
1216 Token id = syntaxStack.top(3);
1217 if (par2.asOperator() == Token::RightPar)
1218 if (!arg.isOperator())
1219 if (par1.asOperator() == Token::LeftPar)
1220 if (id.isIdentifier()) {
1221 ruleFound = true;
1222 syntaxStack.pop();
1223 syntaxStack.pop();
1224 syntaxStack.pop();
1225 syntaxStack.pop();
1226 syntaxStack.push(arg);
1227 d->codes.append(Opcode(Opcode::Function, argCount));
1228 Q_ASSERT(!argStack.empty());
1229 argCount = argStack.empty() ? 0 : argStack.pop();
1230 }
1231 }
1232
1233 // rule for function call with parentheses, but without argument
1234 // e.g. "2*PI()"
1235 if (!ruleFound)
1236 if (syntaxStack.itemCount() >= 3) {
1237 Token par2 = syntaxStack.top();
1238 Token par1 = syntaxStack.top(1);
1239 Token id = syntaxStack.top(2);
1240 if (par2.asOperator() == Token::RightPar)
1241 if (par1.asOperator() == Token::LeftPar)
1242 if (id.isIdentifier()) {
1243 ruleFound = true;
1244 syntaxStack.pop();
1245 syntaxStack.pop();
1246 syntaxStack.pop();
1247 syntaxStack.push(Token(Token::Integer));
1248 d->codes.append(Opcode(Opcode::Function, 0));
1249 Q_ASSERT(!argStack.empty());
1250 argCount = argStack.empty() ? 0 : argStack.pop();
1251 }
1252 }
1253
1254#ifdef CALLIGRA_SHEETS_INLINE_ARRAYS
1255 // rule for inline array elements, if token is ; or | or }
1256 // { arg1 ; arg2 -> { arg
1257 if (!ruleFound)
1258 if (syntaxStack.itemCount() >= 4)
1259 if ((token.asOperator() == Token::Semicolon) ||
1260 (token.asOperator() == Token::CurlyKet) ||
1261 (token.asOperator() == Token::Pipe)) {
1262 Token arg2 = syntaxStack.top();
1263 Token sep = syntaxStack.top(1);
1264 Token arg1 = syntaxStack.top(2);
1265 Token bra = syntaxStack.top(3);
1266 if (!arg2.isOperator())
1267 if (sep.asOperator() == Token::Semicolon)
1268 if (!arg1.isOperator())
1269 if (bra.asOperator() == Token::CurlyBra) {
1270 ruleFound = true;
1271 syntaxStack.pop();
1272 syntaxStack.pop();
1273 argCount++;
1274 }
1275 }
1276
1277 // rule for last array row element, if token is ; or | or }
1278 // { arg1 | arg2 -> { arg
1279 if (!ruleFound)
1280 if (syntaxStack.itemCount() >= 4)
1281 if ((token.asOperator() == Token::Semicolon) ||
1282 (token.asOperator() == Token::CurlyKet) ||
1283 (token.asOperator() == Token::Pipe)) {
1284 Token arg2 = syntaxStack.top();
1285 Token sep = syntaxStack.top(1);
1286 Token arg1 = syntaxStack.top(2);
1287 Token bra = syntaxStack.top(3);
1288 if (!arg2.isOperator())
1289 if (sep.asOperator() == Token::Pipe)
1290 if (!arg1.isOperator())
1291 if (bra.asOperator() == Token::CurlyBra) {
1292 ruleFound = true;
1293 syntaxStack.pop();
1294 syntaxStack.pop();
1295 int rowCount = argStack.pop();
1296 argStack.push(++rowCount);
1297 argCount = 1;
1298 }
1299 }
1300
1301 // rule for last array element:
1302 // { arg } -> arg
1303 if (!ruleFound)
1304 if (syntaxStack.itemCount() >= 3) {
1305 Token ket = syntaxStack.top();
1306 Token arg = syntaxStack.top(1);
1307 Token bra = syntaxStack.top(2);
1308 if (ket.asOperator() == Token::CurlyKet)
1309 if (!arg.isOperator())
1310 if (bra.asOperator() == Token::CurlyBra) {
1311 ruleFound = true;
1312 syntaxStack.pop();
1313 syntaxStack.pop();
1314 syntaxStack.pop();
1315 syntaxStack.push(arg);
1316 const int rowCount = argStack.pop();
1317 d->constants.append(Value((int)argCount)); // cols
1318 d->constants.append(Value(rowCount));
1319 d->codes.append(Opcode(Opcode::Array, d->constants.count() - 2));
1320 Q_ASSERT(!argStack.empty());
1321 argCount = argStack.empty() ? 0 : argStack.pop();
1322 }
1323 }
1324#endif
1325 // rule for parenthesis: ( Y ) -> Y
1326 if (!ruleFound)
1327 if (syntaxStack.itemCount() >= 3) {
1328 Token right = syntaxStack.top();
1329 Token y = syntaxStack.top(1);
1330 Token left = syntaxStack.top(2);
1331 if (right.isOperator())
1332 if (!y.isOperator())
1333 if (left.isOperator())
1334 if (right.asOperator() == Token::RightPar)
1335 if (left.asOperator() == Token::LeftPar) {
1336 ruleFound = true;
1337 syntaxStack.pop();
1338 syntaxStack.pop();
1339 syntaxStack.pop();
1340 syntaxStack.push(y);
1341 }
1342 }
1343
1344 // rule for binary operator: A (op) B -> A
1345 // conditions: precedence of op >= precedence of token
1346 // action: push (op) to result
1347 // e.g. "A * B" becomes 'A' if token is operator '+'
1348 if (!ruleFound)
1349 if (syntaxStack.itemCount() >= 3) {
1350 Token b = syntaxStack.top();
1351 Token op = syntaxStack.top(1);
1352 Token a = syntaxStack.top(2);
1353 if (!a.isOperator())
1354 if (!b.isOperator())
1355 if (op.isOperator())
1356 if (token.asOperator() != Token::LeftPar)
1357 if (opPrecedence(op.asOperator()) >= opPrecedence(token.asOperator())) {
1358 ruleFound = true;
1359 syntaxStack.pop();
1360 syntaxStack.pop();
1361 syntaxStack.pop();
1362 syntaxStack.push(b);
1363 switch (op.asOperator()) {
1364 // simple binary operations
1365 case Token::Plus: d->codes.append(Opcode::Add); break;
1366 case Token::Minus: d->codes.append(Opcode::Sub); break;
1367 case Token::Asterisk: d->codes.append(Opcode::Mul); break;
1368 case Token::Slash: d->codes.append(Opcode::Div); break;
1369 case Token::Caret: d->codes.append(Opcode::Pow); break;
1370 case Token::Ampersand: d->codes.append(Opcode::Concat); break;
1371 case Token::Intersect: d->codes.append(Opcode::Intersect); break;
1372 case Token::Union: d->codes.append(Opcode::Union); break;
1373
1374 // simple value comparisons
1375 case Token::Equal: d->codes.append(Opcode::Equal); break;
1376 case Token::Less: d->codes.append(Opcode::Less); break;
1377 case Token::Greater: d->codes.append(Opcode::Greater); break;
1378
1379 // NotEqual is Equal, followed by Not
1380 case Token::NotEqual:
1381 d->codes.append(Opcode::Equal);
1382 d->codes.append(Opcode::Not);
1383 break;
1384
1385 // LessOrEqual is Greater, followed by Not
1386 case Token::LessEqual:
1387 d->codes.append(Opcode::Greater);
1388 d->codes.append(Opcode::Not);
1389 break;
1390
1391 // GreaterOrEqual is Less, followed by Not
1392 case Token::GreaterEqual:
1393 d->codes.append(Opcode::Less);
1394 d->codes.append(Opcode::Not);
1395 break;
1396 default: break;
1397 };
1398 }
1399 }
1400
1401 // rule for unary operator: (op1) (op2) X -> (op1) X
1402 // conditions: op2 is unary, token is not '('
1403 // action: push (op2) to result
1404 // e.g. "* - 2" becomes '*'
1405 if (!ruleFound)
1406 if (token.asOperator() != Token::LeftPar)
1407 if (syntaxStack.itemCount() >= 3) {
1408 Token x = syntaxStack.top();
1409 Token op2 = syntaxStack.top(1);
1410 Token op1 = syntaxStack.top(2);
1411 if (!x.isOperator())
1412 if (op1.isOperator())
1413 if (op2.isOperator())
1414 if ((op2.asOperator() == Token::Plus) ||
1415 (op2.asOperator() == Token::Minus)) {
1416 ruleFound = true;
1417 syntaxStack.pop();
1418 syntaxStack.pop();
1419 syntaxStack.push(x);
1420 if (op2.asOperator() == Token::Minus)
1421 d->codes.append(Opcode(Opcode::Neg));
1422 }
1423 }
1424
1425 // auxiliary rule for unary operator: (op) X -> X
1426 // conditions: op is unary, op is first in syntax stack, token is not '('
1427 // action: push (op) to result
1428 if (!ruleFound)
1429 if (token.asOperator() != Token::LeftPar)
1430 if (syntaxStack.itemCount() == 2) {
1431 Token x = syntaxStack.top();
1432 Token op = syntaxStack.top(1);
1433 if (!x.isOperator())
1434 if (op.isOperator())
1435 if ((op.asOperator() == Token::Plus) ||
1436 (op.asOperator() == Token::Minus)) {
1437 ruleFound = true;
1438 syntaxStack.pop();
1439 syntaxStack.pop();
1440 syntaxStack.push(x);
1441 if (op.asOperator() == Token::Minus)
1442 d->codes.append(Opcode(Opcode::Neg));
1443 }
1444 }
1445
1446 if (!ruleFound) break;
1447 }
1448
1449 // can't apply rules anymore, push the token
1450 if (token.asOperator() != Token::Percent)
1451 syntaxStack.push(token);
1452 }
1453 }
1454
1455 // syntaxStack must left only one operand and end-of-formula (i.e. InvalidOp)
1456 d->valid = false;
1457 if (syntaxStack.itemCount() == 2)
1458 if (syntaxStack.top().isOperator())
1459 if (syntaxStack.top().asOperator() == Token::InvalidOp)
1460 if (!syntaxStack.top(1).isOperator())
1461 d->valid = true;
1462
1463 // bad parsing ? clean-up everything
1464 if (!d->valid) {
1465 d->constants.clear();
1466 d->codes.clear();
1467 }
1468}
1469
1470bool Formula::isNamedArea(const QString& expr) const
1471{
1472 return d->sheet ? d->sheet->map()->namedAreaManager()->contains(expr) : false;
1473}
1474
1475
1476// Evaluates the formula, returns the result.
1477
1478// evaluate the cellIndirections
1479Value Formula::eval(CellIndirection cellIndirections) const
1480{
1481 QHash<Cell, Value> values;
1482 return evalRecursive(cellIndirections, values);
1483}
1484
1485// We need to unroll arrays. Do use the same logic to unroll like OpenOffice.org and Excel are using.
1486Value Formula::Private::valueOrElement(FuncExtra &fe, const stackEntry& entry) const
1487{
1488 const Value& v = entry.val;
1489 const Region& region = entry.reg;
1490 if(v.isArray()) {
1491 if(v.count() == 1) // if there is only one item, use that one
1492 return v.element(0);
1493
1494 if(region.isValid() && entry.regIsNamedOrLabeled) {
1495 const QPoint position = region.firstRange().topLeft();
1496 const int idx = fe.myrow - position.y(); // do we need to do the same for columns?
1497 if(idx >= 0 && idx < int(v.count()))
1498 return v.element(idx); // within the range returns the selected element
1499 }
1500 }
1501 return v;
1502}
1503
1504// On OO.org Calc and MS Excel operations done with +, -, * and / do fail if one of the values is
1505// non-numeric. This differs from formulas like SUM which just ignores non numeric values.
1506Value numericOrError(const ValueConverter* converter, const Value &v)
1507{
1508 switch (v.type()) {
1509 case Value::Empty:
1510 case Value::Boolean:
1511 case Value::Integer:
1512 case Value::Float:
1513 case Value::Complex:
1514 case Value::Error:
1515 return v;
1516 case Value::String: {
1517 if (v.asString().isEmpty())
1518 return v;
1519 bool ok;
1520 converter->asNumeric(v, &ok);
1521 if (ok)
1522 return v;
1523 } break;
1524 case Value::Array:
1525 case Value::CellRange:
1526 return v;
1527 }
1528 return Value::errorVALUE();
1529}
1530
1531Value Formula::evalRecursive(CellIndirection cellIndirections, QHash<Cell, Value>& values) const
1532{
1533 QStack<stackEntry> stack;
1534 stackEntry entry;
1535 int index;
1536 Value val1, val2;
1537 QString c;
1538 QVector<Value> args;
1539
1540 const Map* map = d->sheet ? d->sheet->map() : new Map(0 /*document*/);
1541 const ValueConverter* converter = map->converter();
1542 ValueCalc* calc = map->calc();
1543
1544 QSharedPointer<Function> function;
1545 FuncExtra fe;
1546 fe.mycol = fe.myrow = 0;
1547 if (!d->cell.isNull()) {
1548 fe.mycol = d->cell.column();
1549 fe.myrow = d->cell.row();
1550 }
1551
1552 if (d->dirty) {
1553 Tokens tokens = scan(d->expression);
1554 d->valid = tokens.valid();
1555 if (tokens.valid())
1556 compile(tokens);
1557 }
1558
1559 if (!d->valid)
1560 return Value::errorPARSE();
1561
1562 for (int pc = 0; pc < d->codes.count(); pc++) {
1563 Value ret; // for the function caller
1564 Opcode& opcode = d->codes[pc];
1565 index = opcode.index;
1566 switch (opcode.type) {
1567 // no operation
1568 case Opcode::Nop:
1569 break;
1570
1571 // load a constant, push to stack
1572 case Opcode::Load:
1573 entry.reset();
1574 entry.val = d->constants[index];
1575 stack.push(entry);
1576 break;
1577
1578 // unary operation
1579 case Opcode::Neg:
1580 entry.reset();
1581 entry.val = d->valueOrElement(fe, stack.pop());
1582 if (!entry.val.isError()) // do nothing if we got an error
1583 entry.val = calc->mul(entry.val, -1);
1584 stack.push(entry);
1585 break;
1586
1587 // binary operation: take two values from stack, do the operation,
1588 // push the result to stack
1589 case Opcode::Add:
1590 entry.reset();
1591 val2 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1592 val1 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1593 val2 = calc->add(val1, val2);
1594 entry.reset();
1595 entry.val = val2;
1596 stack.push(entry);
1597 break;
1598
1599 case Opcode::Sub:
1600 val2 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1601 val1 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1602 val2 = calc->sub(val1, val2);
1603 entry.reset();
1604 entry.val = val2;
1605 stack.push(entry);
1606 break;
1607
1608 case Opcode::Mul:
1609 val2 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1610 val1 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1611 val2 = calc->mul(val1, val2);
1612 entry.reset();
1613 entry.val = val2;
1614 stack.push(entry);
1615 break;
1616
1617 case Opcode::Div:
1618 val2 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1619 val1 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1620 val2 = calc->div(val1, val2);
1621 entry.reset();
1622 entry.val = val2;
1623 stack.push(entry);
1624 break;
1625
1626 case Opcode::Pow:
1627 val2 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1628 val1 = numericOrError(converter, d->valueOrElement(fe, stack.pop()));
1629 val2 = calc->pow(val1, val2);
1630 entry.reset();
1631 entry.val = val2;
1632 stack.push(entry);
1633 break;
1634
1635 // string concatenation
1636 case Opcode::Concat:
1637 val1 = converter->asString(stack.pop().val);
1638 val2 = converter->asString(stack.pop().val);
1639 if (val1.isError() || val2.isError())
1640 val1 = Value::errorVALUE();
1641 else
1642 val1 = Value(val2.asString().append(val1.asString()));
1643 entry.reset();
1644 entry.val = val1;
1645 stack.push(entry);
1646 break;
1647
1648 // array intersection
1649 case Opcode::Intersect: {
1650 val1 = stack.pop().val;
1651 val2 = stack.pop().val;
1652 Region r1(d->constants[index].asString(), map, d->sheet);
1653 Region r2(d->constants[index+1].asString(), map, d->sheet);
1654 if(!r1.isValid() || !r2.isValid()) {
1655 val1 = Value::errorNULL();
1656 } else {
1657 Region r = r1.intersected(r2);
1658 QRect rect = r.boundingRect();
1659 Cell cell;
1660 if(rect.top() == rect.bottom())
1661 cell = Cell(r.firstSheet(), fe.mycol, rect.top());
1662 else if(rect.left() == rect.right())
1663 cell = Cell(r.firstSheet(), rect.left(), fe.mycol);
1664 if(cell.isNull())
1665 val1 = Value::errorNULL();
1666 else if(cell.isEmpty())
1667 val1 = Value::errorNULL();
1668 else
1669 val1 = cell.value();
1670 }
1671 entry.reset();
1672 entry.val = val1;
1673 stack.push(entry);
1674 } break;
1675
1676 // region union
1677 case Opcode::Union: {
1678 Region r = stack.pop().reg;
1679 Region r2 = stack.pop().reg;
1680 entry.reset();
1681 if (!r.isValid() || !r2.isValid()) {
1682 val1 = Value::errorVALUE();
1683 r = Region();
1684 } else {
1685 r.add(r2);
1686 r.firstSheet()->cellStorage()->valueRegion(r);
1687 // store the reference, so we can use it within functions (not entirely correct)
1688 entry.col1 = r.boundingRect().left();
1689 entry.row1 = r.boundingRect().top();
1690 entry.col2 = r.boundingRect().right();
1691 entry.row2 = r.boundingRect().bottom();
1692 }
1693 entry.val = val1;
1694 entry.reg = r;
1695 stack.push(entry);
1696 } break;
1697
1698 // logical not
1699 case Opcode::Not:
1700 val1 = converter->asBoolean(d->valueOrElement(fe, stack.pop()));
1701 if (val1.isError())
1702 val1 = Value::errorVALUE();
1703 else
1704 val1 = Value(!val1.asBoolean());
1705 entry.reset();
1706 entry.val = val1;
1707 stack.push(entry);
1708 break;
1709
1710 // comparison
1711 case Opcode::Equal:
1712 val1 = d->valueOrElement(fe, stack.pop());
1713 val2 = d->valueOrElement(fe, stack.pop());
1714 if (val1.isError())
1715 ;
1716 else if (val2.isError())
1717 val1 = val2;
1718 else if (val2.compare(val1, calc->settings()->caseSensitiveComparisons()) == 0)
1719 val1 = Value(true);
1720 else
1721 val1 = Value(false);
1722 entry.reset();
1723 entry.val = val1;
1724 stack.push(entry);
1725 break;
1726
1727 // less than
1728 case Opcode::Less:
1729 val1 = d->valueOrElement(fe, stack.pop());
1730 val2 = d->valueOrElement(fe, stack.pop());
1731 if (val1.isError())
1732 ;
1733 else if (val2.isError())
1734 val1 = val2;
1735 else if (val2.compare(val1, calc->settings()->caseSensitiveComparisons()) < 0)
1736 val1 = Value(true);
1737 else
1738 val1 = Value(false);
1739 entry.reset();
1740 entry.val = val1;
1741 stack.push(entry);
1742 break;
1743
1744 // greater than
1745 case Opcode::Greater: {
1746 val1 = d->valueOrElement(fe, stack.pop());
1747 val2 = d->valueOrElement(fe, stack.pop());
1748 if (val1.isError())
1749 ;
1750 else if (val2.isError())
1751 val1 = val2;
1752 else if (val2.compare(val1, calc->settings()->caseSensitiveComparisons()) > 0)
1753 val1 = Value(true);
1754 else
1755 val1 = Value(false);
1756 entry.reset();
1757 entry.val = val1;
1758 stack.push(entry);
1759 }
1760 break;
1761
1762 // cell in a sheet
1763 case Opcode::Cell: {
1764 c = d->constants[index].asString();
1765 val1 = Value::empty();
1766 entry.reset();
1767
1768 const Region region(c, map, d->sheet);
1769 if (!region.isValid()) {
1770 val1 = Value::errorREF();
1771 } else if (region.isSingular()) {
1772 const QPoint position = region.firstRange().topLeft();
1773 if (cellIndirections.isEmpty())
1774 val1 = Cell(region.firstSheet(), position).value();
1775 else {
1776 Cell cell(region.firstSheet(), position);
1777 cell = cellIndirections.value(cell, cell);
1778 if (values.contains(cell))
1779 val1 = values.value(cell);
1780 else {
1781 values[cell] = Value::errorCIRCLE();
1782 if (cell.isFormula())
1783 val1 = cell.formula().evalRecursive(cellIndirections, values);
1784 else
1785 val1 = cell.value();
1786 values[cell] = val1;
1787 }
1788 }
1789 // store the reference, so we can use it within functions
1790 entry.col1 = entry.col2 = position.x();
1791 entry.row1 = entry.row2 = position.y();
1792 entry.reg = region;
1793 entry.regIsNamedOrLabeled = map->namedAreaManager()->contains(c);
1794 } else {
1795 kWarning() << "Unhandled non singular region in Opcode::Cell with rects=" << region.rects();
1796 }
1797 entry.val = val1;
1798 stack.push(entry);
1799 }
1800 break;
1801
1802 // selected range in a sheet
1803 case Opcode::Range: {
1804 c = d->constants[index].asString();
1805 val1 = Value::empty();
1806 entry.reset();
1807
1808 const Region region(c, map, d->sheet);
1809 if (region.isValid()) {
1810 val1 = region.firstSheet()->cellStorage()->valueRegion(region);
1811 // store the reference, so we can use it within functions
1812 entry.col1 = region.firstRange().left();
1813 entry.row1 = region.firstRange().top();
1814 entry.col2 = region.firstRange().right();
1815 entry.row2 = region.firstRange().bottom();
1816 entry.reg = region;
1817 entry.regIsNamedOrLabeled = map->namedAreaManager()->contains(c);
1818 }
1819
1820 entry.val = val1; // any array is valid here
1821 stack.push(entry);
1822 }
1823 break;
1824
1825 // reference
1826 case Opcode::Ref:
1827 val1 = d->constants[index];
1828 entry.reset();
1829 entry.val = val1;
1830 stack.push(entry);
1831 break;
1832
1833 // calling function
1834 case Opcode::Function:
1835 // sanity check, this should not happen unless opcode is wrong
1836 // (i.e. there's a bug in the compile() function)
1837 if (stack.count() < index)
1838 return Value::errorVALUE(); // not enough arguments
1839
1840 args.clear();
1841 fe.ranges.clear();
1842 fe.ranges.resize(index);
1843 fe.regions.clear();
1844 fe.regions.resize(index);
1845 fe.sheet = d->sheet;
1846 for (; index; index--) {
1847 stackEntry e = stack.pop();
1848 args.insert(args.begin(), e.val);
1849 // fill the FunctionExtra object
1850 fe.ranges[index - 1].col1 = e.col1;
1851 fe.ranges[index - 1].row1 = e.row1;
1852 fe.ranges[index - 1].col2 = e.col2;
1853 fe.ranges[index - 1].row2 = e.row2;
1854 fe.regions[index - 1] = e.reg;
1855 }
1856
1857 // function name as string value
1858 val1 = converter->asString(stack.pop().val);
1859 if (val1.isError())
1860 return val1;
1861 function = FunctionRepository::self()->function(val1.asString());
1862 if (!function)
1863 return Value::errorNAME(); // no such function
1864
1865 ret = function->exec(args, calc, &fe);
1866 entry.reset();
1867 entry.val = ret;
1868 stack.push(entry);
1869
1870 break;
1871
1872#ifdef CALLIGRA_SHEETS_INLINE_ARRAYS
1873 // creating an array
1874 case Opcode::Array: {
1875 const int cols = d->constants[index].asInteger();
1876 const int rows = d->constants[index+1].asInteger();
1877 // check if enough array elements are available
1878 if (stack.count() < cols * rows)
1879 return Value::errorVALUE();
1880 Value array(Value::Array);
1881 for (int row = rows - 1; row >= 0; --row) {
1882 for (int col = cols - 1; col >= 0; --col) {
1883 array.setElement(col, row, stack.pop().val);
1884 }
1885 }
1886 entry.reset();
1887 entry.val = array;
1888 stack.push(entry);
1889 break;
1890 }
1891#endif
1892 default:
1893 break;
1894 }
1895 }
1896
1897 if (!d->sheet)
1898 delete map;
1899
1900 // more than one value in stack ? unsuccessful execution...
1901 if (stack.count() != 1)
1902 return Value::errorVALUE();
1903
1904 return stack.pop().val;
1905}
1906
1907Formula& Formula::operator=(const Formula & other)
1908{
1909 d = other.d;
1910 return *this;
1911}
1912
1913bool Formula::operator==(const Formula& other) const
1914{
1915 return (d->expression == other.d->expression);
1916}
1917
1918// Debugging aid
1919
1920QString Formula::dump() const
1921{
1922 QString result;
1923
1924 if (d->dirty) {
1925 Tokens tokens = scan(d->expression);
1926 compile(tokens);
1927 }
1928
1929 result = QString("Expression: [%1]\n").arg(d->expression);
1930#if 0
1931 Value value = eval();
1932 result.append(QString("Result: %1\n").arg(
1933 converter->asString(value).asString()));
1934#endif
1935
1936 result.append(" Constants:\n");
1937 for (int c = 0; c < d->constants.count(); c++) {
1938 QString vtext;
1939 Value val = d->constants[c];
1940 if (val.isString()) vtext = QString("[%1]").arg(val.asString());
1941 else if (val.isNumber()) vtext = QString("%1").arg((double) numToDouble(val.asFloat()));
1942 else if (val.isBoolean()) vtext = QString("%1").arg(val.asBoolean() ? "True" : "False");
1943 else if (val.isError()) vtext = "error";
1944 else vtext = "???";
1945 result += QString(" #%1 = %2\n").arg(c).arg(vtext);
1946 }
1947
1948 result.append("\n");
1949 result.append(" Code:\n");
1950 for (int i = 0; i < d->codes.count(); i++) {
1951 QString ctext;
1952 switch (d->codes[i].type) {
1953 case Opcode::Load: ctext = QString("Load #%1").arg(d->codes[i].index); break;
1954 case Opcode::Ref: ctext = QString("Ref #%1").arg(d->codes[i].index); break;
1955 case Opcode::Function: ctext = QString("Function (%1)").arg(d->codes[i].index); break;
1956 case Opcode::Add: ctext = "Add"; break;
1957 case Opcode::Sub: ctext = "Sub"; break;
1958 case Opcode::Mul: ctext = "Mul"; break;
1959 case Opcode::Div: ctext = "Div"; break;
1960 case Opcode::Neg: ctext = "Neg"; break;
1961 case Opcode::Concat: ctext = "Concat"; break;
1962 case Opcode::Pow: ctext = "Pow"; break;
1963 case Opcode::Intersect: ctext = "Intersect"; break;
1964 case Opcode::Equal: ctext = "Equal"; break;
1965 case Opcode::Not: ctext = "Not"; break;
1966 case Opcode::Less: ctext = "Less"; break;
1967 case Opcode::Greater: ctext = "Greater"; break;
1968 case Opcode::Array: ctext = QString("Array (%1x%2)").arg(d->constants[d->codes[i].index].asInteger()).arg(d->constants[d->codes[i].index+1].asInteger()); break;
1969 case Opcode::Nop: ctext = "Nop"; break;
1970 case Opcode::Cell: ctext = "Cell"; break;
1971 case Opcode::Range: ctext = "Range"; break;
1972 default: ctext = "Unknown"; break;
1973 }
1974 result.append(" ").append(ctext).append("\n");
1975 }
1976
1977 return result;
1978}
1979
1980QTextStream& operator<<(QTextStream& ts, Formula formula)
1981{
1982 ts << formula.dump();
1983 return ts;
1984}
1985