-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalculate.ino
132 lines (120 loc) · 2.77 KB
/
calculate.ino
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
void calculate(char (&input)[INPUT_SIZE]) {
String num;
num.reserve(INPUT_SIZE); //prevents heap fragmentation
Stack<char> opstack(INPUT_SIZE / 2); //binary operators need two operands
List<BigNumber> operands;
for (int x = 0; x <= index; x++) {
char token = input[x];
switch (token) {
case '0'...'9':
case '.':
num.concat(token);
break;
case '+':
case '-':
case '*':
case '/':
case '^':
if (num)
transfer(num, operands);
while (precedence(token) <= precedence(opstack.peek())) {
if (associativity(token))
break;
doMath(opstack.pop(), operands);
}
case '(':
opstack.push(token);
break;
case ')':
while (opstack.peek() && opstack.peek() != '(') {
doMath(opstack.pop(), operands);
}
opstack.pop(); //discard closing parenth
break;
}
}
// process entire opstack at the end of input stream
while (opstack.peek() && opstack.peek() != '(') {
doMath(opstack.pop(), operands);
}
//END OF ALGORITHM, CHECK STATUS OF RESULTS HERE
if (opstack.peek() == '(') {
raise(4); //extra closing parenth, parenth mismatch
return;
}
if (!opstack.isEmpty()) {
raise(2); //opstack should have been empty if syntax was respected
return;
}
if (operands.count() != 1) {
raise(3); //if parenthesis were abused, there werent enough operators
return;
}
auto final = operands.pop();
printBignum(final);
}
void transfer(String &num, List<BigNumber> &output) {
char array[num.length() + 1];
num.toCharArray(array, num.length() + 1);
output.push(BigNumber(array));
num.remove(0);
}
inline byte doMath(char op, List<BigNumber> &output) {
if (output.count() < 2)
return 0; //if there arent enough operands, return error
BigNumber y = output.pop();
BigNumber z = output.pop();
switch (op) {
case ('+'):
z += y;
break;
case ('-'):
z -= y;
break;
case ('*'):
z *= y;
break;
case ('/'):
z /= y;
break;
case ('^'):
z = z.pow(y);
break;
default: //defense against a dumb anti-pattern I accidentally made
output.push(z);
output.push(y);
return 0; //if invalid op, put operands back in their place
}
output.push(z);
return 1;
}
bool isOperator(char &op) {
switch (op) {
case '+':
case '-':
case '*':
case '/':
case '^':
return true;
default:
return false;
}
}
byte precedence(char &op) {
switch (op) {
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
return 3;
default:
return 0;
}
}
bool associativity(char &op) {
if (op == '^') return 1;
return 0;
}