|
1 | | -/* A Javascript program to evaluate a given |
2 | | - expression where tokens |
3 | | - are separated by space. |
4 | | - */ |
5 | | - |
6 | | -function evaluate(expression : string) : number | undefined { |
7 | | - const tokens = expression.split(''); |
8 | | - |
9 | | - // Stack for numbers: 'values' |
10 | | - const values : number[] = []; |
11 | | - |
12 | | - // Stack for Operators: 'ops' |
13 | | - const ops = []; |
14 | | - |
15 | | - for (let i = 0; i < tokens.length; i++) { |
16 | | - // Current token is a whitespace, skip it |
17 | | - if (tokens[i] === ' ') { |
18 | | - continue; |
19 | | - } |
20 | | - |
21 | | - // Current token is a number, |
22 | | - // push it to stack for numbers |
23 | | - if (tokens[i] >= '0' && tokens[i] <= '9') { |
24 | | - let sbuf = ''; |
25 | | - |
26 | | - // There may be more than |
27 | | - // one digits in number |
28 | | - while ( |
29 | | - i < tokens.length && |
30 | | - tokens[i] >= '0' && |
31 | | - tokens[i] <= '9' |
32 | | - ) { |
33 | | - sbuf = sbuf + tokens[i++]; |
34 | | - } |
35 | | - values.push(parseInt(sbuf, 10)); |
36 | | - |
37 | | - // Right now the i points to |
38 | | - // the character next to the digit, |
39 | | - // since the for loop also increases |
40 | | - // the i, we would skip one |
41 | | - // token position; we need to |
42 | | - // decrease the value of i by 1 to |
43 | | - // correct the offset. |
44 | | - i--; |
45 | | - } // Current token is an opening |
46 | | - // brace, push it to 'ops' |
47 | | - else if (tokens[i] === '(') { |
48 | | - ops.push(tokens[i]); |
49 | | - } // Closing brace encountered, |
50 | | - // solve entire brace |
51 | | - else if (tokens[i] === ')') { |
52 | | - while (ops[ops.length - 1] !== '(') { |
53 | | - values.push(applyOp(ops.pop(), values.pop(), values.pop())); |
54 | | - } |
55 | | - ops.pop(); |
56 | | - } // Current token is an operator. |
57 | | - else if ( |
58 | | - tokens[i] === '+' || |
59 | | - tokens[i] === '-' || |
60 | | - tokens[i] === '*' || |
61 | | - tokens[i] === '/' |
62 | | - ) { |
63 | | - // While top of 'ops' has same |
64 | | - // or greater precedence to current |
65 | | - // token, which is an operator. |
66 | | - // Apply operator on top of 'ops' |
67 | | - // to top two elements in values stack |
68 | | - while ( |
69 | | - ops.length > 0 && |
70 | | - hasPrecedence(tokens[i], ops[ops.length - 1]) |
71 | | - ) { |
72 | | - values.push(applyOp(ops.pop() ?? '', values.pop(), values.pop())); |
73 | | - } |
74 | | - |
75 | | - // Push current token to 'ops'. |
76 | | - ops.push(tokens[i]); |
| 1 | +import parseString from './parse_string.ts'; |
| 2 | +import { tokenValues } from './tokens.ts'; |
| 3 | + |
| 4 | +export default function evaluate(expression : string) : number { |
| 5 | + const parts = parseString(expression, tokenValues); |
| 6 | + |
| 7 | + parts.forEach((part) => { |
| 8 | + switch (part) { |
| 9 | + case value: |
| 10 | + |
| 11 | + break; |
| 12 | + |
| 13 | + default: |
| 14 | + break; |
77 | 15 | } |
78 | | - } |
79 | | - |
80 | | - // Entire expression has been |
81 | | - // parsed at this point, apply remaining |
82 | | - // ops to remaining values |
83 | | - while (ops.length > 0) { |
84 | | - values.push(applyOp(ops.pop() ?? '', values.pop() ?? 0, values.pop() ?? 0)); |
85 | | - } |
86 | | - |
87 | | - // Top of 'values' contains |
88 | | - // result, return it |
89 | | - return values.pop(); |
90 | | -} |
91 | | - |
92 | | -// Returns true if 'op2' has |
93 | | -// higher or same precedence as 'op1', |
94 | | -// otherwise returns false. |
95 | | -function hasPrecedence(op1 : string, op2 : string) : boolean { |
96 | | - if (op2 === '(' || op2 === ')') { |
97 | | - return false; |
98 | | - } |
99 | | - if ( |
100 | | - (op1 === '*' || op1 === '/') && |
101 | | - (op2 === '+' || op2 === '-') |
102 | | - ) { |
103 | | - return false; |
104 | | - } else { |
105 | | - return true; |
106 | | - } |
107 | | -} |
| 16 | + }) |
108 | 17 |
|
109 | | -// A utility method to apply an |
110 | | -// operator 'op' on operands 'a' |
111 | | -// and 'b'. Return the result. |
112 | | -function applyOp(op : string, b : number, a : number) : number { |
113 | | - switch (op) { |
114 | | - case '+': |
115 | | - return a + b; |
116 | | - case '-': |
117 | | - return a - b; |
118 | | - case '*': |
119 | | - return a * b; |
120 | | - case '/': |
121 | | - if (b === 0) { |
122 | | - throw new Error('Cannot divide by zero'); |
123 | | - } |
124 | | - return a / b |
125 | | - } |
126 | 18 | return 0; |
127 | 19 | } |
0 commit comments