File indexing completed on 2024-05-12 17:22:31

0001 // This file is part of the SpeedCrunch project
0002 // Copyright (C) 2004 Ariya Hidayat <ariya@kde.org>
0003 // Copyright (C) 2008-2016 @heldercorreia
0004 //
0005 // This program is free software; you can redistribute it and/or
0006 // modify it under the terms of the GNU General Public License
0007 // as published by the Free Software Foundation; either version 2
0008 // of the License, or (at your option) any later version.
0009 //
0010 // This program is distributed in the hope that it will be useful,
0011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 // GNU General Public License for more details.
0014 //
0015 // You should have received a copy of the GNU General Public License
0016 // along with this program; see the file COPYING.  If not, write to
0017 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018 // Boston, MA 02110-1301, USA.
0019 
0020 #ifndef CORE_EVALUATOR_H
0021 #define CORE_EVALUATOR_H
0022 
0023 #include "functions.h"
0024 #include "opcode.h"
0025 
0026 #include "hmath.h"
0027 #include "cmath.h"
0028 #include "quantity.h"
0029 
0030 #include <QHash>
0031 #include <QObject>
0032 #include <QSet>
0033 #include <QString>
0034 #include <QStringList>
0035 #include <QVector>
0036 
0037 class Token {
0038 public:
0039     enum Operator {
0040         Invalid = 0,
0041         Addition, Subtraction, Multiplication,
0042         Division, IntegerDivision, Exponentiation,
0043         Super0, Super1, Super2, Super3, Super4,
0044         Super5, Super6, Super7, Super8, Super9,
0045         AssociationStart, AssociationEnd,
0046         ListSeparator, Factorial, Assignment, Modulo,
0047         ArithmeticLeftShift, ArithmeticRightShift,
0048         BitwiseLogicalAND, BitwiseLogicalOR,
0049         UnitConversion,
0050         Function // For managing shift/reduce conflicts.
0051     };
0052     enum Type {
0053         stxUnknown, stxNumber, stxIdentifier, stxAbstract, // isOperand
0054         stxOperator, stxOpenPar, stxClosePar, stxSep // isOperator
0055     };
0056 
0057     static const Token null;
0058 
0059     Token(Type = stxUnknown, const QString& = QString(), int pos = -1,
0060           int size = -1);
0061     Token(const Token&);
0062 
0063     Quantity asNumber() const;
0064     Operator asOperator() const;
0065     QString description() const;
0066     bool isNumber() const { return m_type == stxNumber; }
0067     bool isOperator() const { return m_type >= stxOperator; }
0068     bool isIdentifier() const { return m_type == stxIdentifier; }
0069     bool isAbstract() const { return m_type == stxAbstract; }
0070     bool isOperand() const { return isNumber() || isIdentifier()
0071                                     || isAbstract(); }
0072     int pos() const { return m_pos; }
0073     void setPos(int pos) { m_pos = pos; }
0074     int size() const { return m_size; }
0075     void setSize(int size) { m_size = size; }
0076     QString text() const { return m_text; }
0077     Type type() const { return m_type; }
0078     int minPrecedence() const { return m_minPrecedence; }
0079     void setMinPrecedence(int value) { m_minPrecedence = value; }
0080 
0081     Token& operator=(const Token&);
0082 
0083 protected:
0084     // Start position of the text that token represents in the expression
0085     // (might include extra space characters).
0086     int m_pos;
0087     // Size of text that token represents in the expression
0088     // (might include extra space characters).
0089     int m_size;
0090     // Precedence of the operator with the lowest precedence contained
0091     // in this token.
0092     int m_minPrecedence;
0093     // Normalized version of that token text (only valid when the token
0094     // represents a single token).
0095     QString m_text;
0096     Type m_type;
0097 };
0098 
0099 class Tokens : public QVector<Token> {
0100 public:
0101     Tokens()
0102         : QVector<Token>()
0103         , m_valid(true)
0104     { }
0105 
0106     bool valid() const { return m_valid; }
0107     void setValid(bool v) { m_valid = v; }
0108 
0109 #ifdef EVALUATOR_DEBUG
0110     void append(const Token&);
0111 #endif  /* EVALUATOR_DEBUG */
0112 
0113 protected:
0114     bool m_valid;
0115 };
0116 
0117 class Evaluator : public QObject {
0118     Q_OBJECT
0119     using ForceBuiltinVariableErasure = bool;
0120 
0121 public:
0122     static Evaluator* instance();
0123     void reset();
0124 
0125 //    void setSession(Session*);
0126 //    const Session* session();
0127 
0128     static bool isSeparatorChar(const QChar&);
0129     static bool isRadixChar(const QChar&);
0130     static QString fixNumberRadix(const QString&);
0131 
0132     QString autoFix(const QString&);
0133     QString dump();
0134     QString error() const;
0135     Quantity evalNoAssign();
0136     QString expression() const;
0137     bool isValid();
0138     Tokens scan(const QString&) const;
0139     void setExpression(const QString&);
0140     Tokens tokens() const;
0141 
0142     void setVariable(const QString&, Quantity);
0143     void unsetVariable(const QString&, ForceBuiltinVariableErasure = false);
0144     bool isBuiltInVariable(const QString&) const;
0145     void initializeBuiltInVariables();
0146     void initializeAngleUnits();
0147 
0148 protected:
0149     void compile(const Tokens&);
0150 
0151 private:
0152     Evaluator();
0153     Q_DISABLE_COPY(Evaluator)
0154 
0155     bool m_dirty;
0156     QString m_error;
0157     QString m_expression;
0158     bool m_valid;
0159     QString m_assignId;
0160     bool m_assignFunc;
0161     QStringList m_assignArg;
0162     QVector<Opcode> m_codes;
0163     QVector<Quantity> m_constants;
0164     QStringList m_identifiers;
0165     QSet<QString> m_functionsInUse;
0166     QHash<QString, QString> m_unitFixups;
0167     QSet<QString> m_allUnits;
0168     QHash<QString, Quantity> m_variables;
0169 
0170     const Quantity& checkOperatorResult(const Quantity&);
0171     static QString stringFromFunctionError(Function*);
0172     Quantity exec(const QVector<Opcode>& opcodes,
0173                   const QVector<Quantity>& constants,
0174                   const QStringList& identifiers);
0175 
0176     bool isFunction(Token token) {
0177         return token.isIdentifier()
0178                 && (FunctionRepo::instance()->find(token.text()));
0179     }
0180 };
0181 
0182 #endif