1 /*
2     SPDX-FileCopyrightText: 2001-2013 Evan Teran <evan.teran@gmail.com>
3     SPDX-FileCopyrightText: 1996-2000 Bernd Johannes Wuebben <wuebben@kde.org>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #pragma once
9 
10 #include "knumber.h"
11 #include "stats.h"
12 #include <QStack>
13 
14 class CalcEngine
15 {
16 public:
17     // operations that can be stored in calculation stack
18     enum Operation {
19         FUNC_EQUAL,
20         FUNC_PERCENT,
21         FUNC_BRACKET,
22         FUNC_OR,
23         FUNC_XOR,
24         FUNC_AND,
25         FUNC_LSH,
26         FUNC_RSH,
27         FUNC_ADD,
28         FUNC_SUBTRACT,
29         FUNC_MULTIPLY,
30         FUNC_DIVIDE,
31         FUNC_MOD,
32         FUNC_INTDIV,
33         FUNC_BINOM,
34         FUNC_POWER,
35         FUNC_PWR_ROOT
36     };
37 
38     enum Repeat { REPEAT_ALLOW, REPEAT_PREVENT };
39 
40     CalcEngine();
41 
42     KNumber lastOutput(bool &error) const;
43 
44     void enterOperation(const KNumber &num, Operation func, Repeat allow_repeat = REPEAT_ALLOW);
45 
46     void ArcCosDeg(const KNumber &input);
47     void ArcCosRad(const KNumber &input);
48     void ArcCosGrad(const KNumber &input);
49     void ArcSinDeg(const KNumber &input);
50     void ArcSinRad(const KNumber &input);
51     void ArcSinGrad(const KNumber &input);
52     void ArcTangensDeg(const KNumber &input);
53     void ArcTangensRad(const KNumber &input);
54     void ArcTangensGrad(const KNumber &input);
55     void AreaCosHyp(const KNumber &input);
56     void AreaSinHyp(const KNumber &input);
57     void AreaTangensHyp(const KNumber &input);
58     void Complement(const KNumber &input);
59     void CosDeg(const KNumber &input);
60     void CosRad(const KNumber &input);
61     void CosGrad(const KNumber &input);
62     void CosHyp(const KNumber &input);
63     void Cube(const KNumber &input);
64     void CubeRoot(const KNumber &input);
65     void Exp(const KNumber &input);
66     void Exp10(const KNumber &input);
67     void Factorial(const KNumber &input);
68     void Gamma(const KNumber &input);
69     void InvertSign(const KNumber &input);
70     void Ln(const KNumber &input);
71     void Log10(const KNumber &input);
72     void ParenClose(KNumber input);
73     void ParenOpen(const KNumber &input);
74     void Reciprocal(const KNumber &input);
75     void SinDeg(const KNumber &input);
76     void SinGrad(const KNumber &input);
77     void SinRad(const KNumber &input);
78     void SinHyp(const KNumber &input);
79     void Square(const KNumber &input);
80     void SquareRoot(const KNumber &input);
81     void StatClearAll(const KNumber &input);
82     void StatCount(const KNumber &input);
83     void StatDataNew(const KNumber &input);
84     void StatDataDel(const KNumber &input);
85     void StatMean(const KNumber &input);
86     void StatMedian(const KNumber &input);
87     void StatStdDeviation(const KNumber &input);
88     void StatStdSample(const KNumber &input);
89     void StatSum(const KNumber &input);
90     void StatSumSquares(const KNumber &input);
91     void TangensDeg(const KNumber &input);
92     void TangensRad(const KNumber &input);
93     void TangensGrad(const KNumber &input);
94     void TangensHyp(const KNumber &input);
95 
96     void Reset();
97     void setOnlyUpdateOperation(bool update);
98     bool getOnlyUpdateOperation() const;
99 
100 private:
101     KStats stats;
102 
103     struct Node {
104         KNumber number;
105         Operation operation;
106     };
107 
108     // Stack holds all operations and numbers that have not yet been
109     // processed, e.g. user types "2+3*", the calculation can not be
110     // executed, because "*" has a higher precedence than "+", so we
111     // need to wait for the next number.
112     //
113     // In the stack this would be stored as ((2,+),(3,*),...)
114     //
115     // "enterOperation": If the introduced Operation has lower priority
116     // than the preceding operations in the stack, then we can start to
117     // evaluate the stack (with "evalStack"). Otherwise we append the new
118     // Operation and number to the stack.
119     //
120     // E.g. "2*3+" evaluates to "6+", but "2+3*" can not be evaluated
121     // yet.
122     //
123     // We also take care of brackets, by writing a marker "FUNC_BRACKET"
124     // into the stack, each time the user opens one.  When a bracket is
125     // closed, everything in the stack is evaluated until the first
126     // marker "FUNC_BRACKET" found.
127     QStack<Node> stack_;
128 
129     KNumber last_number_;
130 
131     Operation last_operation_;
132     KNumber last_repeat_number_;
133     bool only_update_operation_;
134 
135     bool percent_mode_;
136     bool repeat_mode_;
137 
138     bool evalStack();
139 
140     KNumber evalOperation(const KNumber &arg1, Operation operation, const KNumber &arg2);
141 };
142 
143