-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCalculator.js
More file actions
144 lines (132 loc) · 2.67 KB
/
Calculator.js
File metadata and controls
144 lines (132 loc) · 2.67 KB
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
// https://www.codewars.com/kata/5235c913397cbf2508000048/solutions/javascript
let tokens = [];
let nextToken = "";
// let postfix = "";
// export const Calculator = function (this: any) {
const Calculator = function () {
this.evaluate = (input) => {
console.log(input);
try {
if (input.length == 0) {
return "";
}
tokens = tokenizer(input);
console.log(tokens);
nextToken = tokens[0];
// postfix = "";
let ast = expr();
console.log(flatArray(ast));
// console.log(postfix);
// return postfix;
const result = caculate(ast);
console.log(result);
return result;
} catch (err) {
console.log(err);
}
};
};
// function caculate(ast: any[]): number {
function caculate(ast) {
if (ast instanceof Array) {
const [op, e1, e2] = ast;
switch (op) {
case "+":
return caculate(e1) + caculate(e2);
case "-":
return caculate(e1) - caculate(e2);
case "*":
return caculate(e1) * caculate(e2);
case "/":
return caculate(e1) / caculate(e2);
default:
console.log("unsupported operator");
return 0;
}
} else {
return parseInt(ast);
}
}
function tokenizer(input) {
let tokens = input
.replace(/[+\-*/^()]/g, " $& ")
.replace(/ +/g, " ")
.replace(/^ */, "")
.replace(/ *$/, "")
.split(" ");
return tokens;
}
function match(t) {
switch (t) {
case undefined:
case nextToken:
tokens.shift();
nextToken = tokens.length > 0 ? tokens[0] : "#";
return true;
default:
return false;
}
}
function expr() {
return combineExpr(term());
function combineExpr(t1) {
if ("+-".includes(nextToken)) {
const op = nextToken;
match();
const t2 = term();
return combineExpr([op, t1, t2]);
} else {
return t1;
}
}
}
function term() {
return combineTerm(factor());
function combineTerm(f1) {
if ("*/^".includes(nextToken)) {
const op = nextToken;
match();
const f2 = factor();
return combineTerm([op, f1, f2]);
} else {
return f1;
}
}
}
function factor() {
if (nextToken == "(") {
match();
const e = expr();
if (match(")")) {
return e;
} else {
throw "')' expected!";
}
} else if (!isNaN(Number(nextToken))) {
const i = nextToken;
match();
return i;
} else if (nextToken == " ") {
return "";
} else {
throw "unexpected token:" + nextToken;
}
}
function flatArray(array) {
if (array instanceof Array) {
return (
"[" +
array
.reduce((a, b) => a + ", " + flatArray(b), "")
.slice(1) +
"]"
);
} else {
return array;
}
}
var calculate = new Calculator();
console.log(calculate.evaluate('127'));
// console.log(calculate.evaluate('2 + 3'));
// console.log(calculate.evaluate('2 - 3 - 4'));
console.log(calculate.evaluate('10 * 5 / 2'));