[NTDLL]
[reactos.git] / reactos / base / applications / calc / rpn.c
1 #include "calc.h"
2
3 typedef struct {
4 calc_node_t node;
5 void *next;
6 } stack_node_t;
7
8 typedef void (*operator_call)(calc_number_t *, calc_number_t *, calc_number_t *);
9
10 typedef struct {
11 unsigned int prec;
12 operator_call op_f;
13 operator_call op_i;
14 operator_call op_p;
15 } calc_operator_t;
16
17 static stack_node_t *stack;
18 static stack_node_t temp;
19 static BOOL percent_mode;
20
21 static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
22 static void rpn_sub_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
23 static void rpn_mul_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
24 static void rpn_div_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
25 static void rpn_mod_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
26 static void rpn_pow_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
27 static void rpn_sqr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
28 static void rpn_and_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
29 static void rpn_or_f (calc_number_t *r, calc_number_t *a, calc_number_t *b);
30 static void rpn_xor_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
31 static void rpn_shl_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
32 static void rpn_shr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
33
34 /* Integer mode calculations */
35 static void rpn_add_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
36 static void rpn_sub_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
37 static void rpn_mul_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
38 static void rpn_div_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
39 static void rpn_mod_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
40 static void rpn_and_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
41 static void rpn_or_i (calc_number_t *r, calc_number_t *a, calc_number_t *b);
42 static void rpn_xor_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
43 static void rpn_shl_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
44 static void rpn_shr_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
45
46 /* Percentage mode calculations */
47 static void rpn_add_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
48 static void rpn_sub_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
49 static void rpn_mul_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
50 static void rpn_div_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
51
52 static const calc_operator_t operator_list[] = {
53 { 0, NULL, NULL, NULL, }, // RPN_OPERATOR_PARENT
54 { 0, NULL, NULL, NULL, }, // RPN_OPERATOR_PERCENT
55 { 0, NULL, NULL, NULL, }, // RPN_OPERATOR_EQUAL
56 { 1, rpn_or_f, rpn_or_i, NULL, }, // RPN_OPERATOR_OR
57 { 2, rpn_xor_f, rpn_xor_i, NULL, }, // RPN_OPERATOR_XOR
58 { 3, rpn_and_f, rpn_and_i, NULL, }, // RPN_OPERATOR_AND
59 { 4, rpn_shl_f, rpn_shl_i, NULL, }, // RPN_OPERATOR_LSH
60 { 4, rpn_shr_f, rpn_shr_i, NULL, }, // RPN_OPERATOR_RSH
61 { 5, rpn_add_f, rpn_add_i, rpn_add_p, }, // RPN_OPERATOR_ADD
62 { 5, rpn_sub_f, rpn_sub_i, rpn_sub_p, }, // RPN_OPERATOR_SUB
63 { 6, rpn_mul_f, rpn_mul_i, rpn_mul_p, }, // RPN_OPERATOR_MULT
64 { 6, rpn_div_f, rpn_div_i, rpn_div_p, }, // RPN_OPERATOR_DIV
65 { 6, rpn_mod_f, rpn_mod_i, NULL, }, // RPN_OPERATOR_MOD
66 { 7, rpn_pow_f, NULL, NULL, }, // RPN_OPERATOR_POW
67 { 7, rpn_sqr_f, NULL, NULL, }, // RPN_OPERATOR_SQR
68 };
69
70 static stack_node_t *pop(void)
71 {
72 if (stack == NULL)
73 return NULL;
74
75 temp = *stack;
76 free(stack);
77 stack = temp.next;
78
79 return &temp;
80 }
81
82 static int is_stack_empty(void)
83 {
84 return (stack == NULL);
85 }
86
87 static void push(stack_node_t *op)
88 {
89 stack_node_t *z = (stack_node_t *)malloc(sizeof(stack_node_t));
90
91 *z = *op;
92 z->next = stack;
93 stack = z;
94 }
95 /*
96 static unsigned int get_prec(unsigned int opc)
97 {
98 unsigned int x;
99
100 for (x=0; x<SIZEOF(operator_list); x++)
101 if (operator_list[x].opc == opc) break;
102 return operator_list[x].prec;
103 }
104 */
105 /* Real mode calculations */
106 static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
107 {
108 r->f = a->f + b->f;
109 }
110
111 static void rpn_sub_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
112 {
113 r->f = a->f - b->f;
114 }
115
116 static void rpn_mul_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
117 {
118 r->f = a->f * b->f;
119 }
120
121 static void rpn_div_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
122 {
123 if (b->f == 0)
124 calc.is_nan = TRUE;
125 else
126 r->f = a->f / b->f;
127 }
128
129 static void rpn_mod_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
130 {
131 double t;
132
133 if (b->f == 0)
134 calc.is_nan = TRUE;
135 else {
136 modf(a->f/b->f, &t);
137 r->f = a->f - (t * b->f);
138 }
139 }
140
141 static void rpn_and_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
142 {
143 calc_number_t ai, bi;
144
145 ai.i = logic_dbl2int(a);
146 bi.i = logic_dbl2int(b);
147
148 r->f = (long double)(ai.i & bi.i);
149 }
150
151 static void rpn_or_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
152 {
153 calc_number_t ai, bi;
154
155 ai.i = logic_dbl2int(a);
156 bi.i = logic_dbl2int(b);
157
158 r->f = (long double)(ai.i | bi.i);
159 }
160
161 static void rpn_xor_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
162 {
163 calc_number_t ai, bi;
164
165 ai.i = logic_dbl2int(a);
166 bi.i = logic_dbl2int(b);
167
168 r->f = (long double)(ai.i ^ bi.i);
169 }
170
171 static void rpn_shl_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
172 {
173 calc_number_t n;
174
175 modf(b->f, &n.f);
176
177 r->f = a->f * pow(2., n.f);
178 }
179
180 static void rpn_shr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
181 {
182 calc_number_t n;
183
184 modf(b->f, &n.f);
185
186 r->f = a->f / pow(2., n.f);
187 }
188
189 static void rpn_pow_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
190 {
191 r->f = pow(a->f, b->f);
192 if (_finite(r->f) == 0 || _isnan(r->f))
193 calc.is_nan = TRUE;
194 }
195
196 static void rpn_sqr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
197 {
198 if (b->f == 0)
199 calc.is_nan = TRUE;
200 else {
201 r->f = pow(a->f, 1./b->f);
202 if (_finite(r->f) == 0 || _isnan(r->f))
203 calc.is_nan = TRUE;
204 }
205 }
206
207 /* Integer mode calculations */
208 static void rpn_add_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
209 {
210 r->i = a->i + b->i;
211 }
212
213 static void rpn_sub_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
214 {
215 r->i = a->i - b->i;
216 }
217
218 static void rpn_mul_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
219 {
220 r->i = a->i * b->i;
221 }
222
223 static void rpn_div_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
224 {
225 if (b->i == 0)
226 calc.is_nan = TRUE;
227 else
228 r->i = a->i / b->i;
229 }
230
231 static void rpn_mod_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
232 {
233 if (b->i == 0)
234 calc.is_nan = TRUE;
235 else
236 r->i = a->i % b->i;
237 }
238
239 static void rpn_and_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
240 {
241 r->i = a->i & b->i;
242 }
243
244 static void rpn_or_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
245 {
246 r->i = a->i | b->i;
247 }
248
249 static void rpn_xor_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
250 {
251 r->i = a->i ^ b->i;
252 }
253
254 static void rpn_shl_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
255 {
256 r->i = a->i << b->i;
257 }
258
259 static void rpn_shr_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
260 {
261 r->i = a->i >> b->i;
262 }
263
264 /* Percent mode calculations */
265 static void rpn_add_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
266 {
267 r->f = a->f * (1. + b->f/100.);
268 }
269
270 static void rpn_sub_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
271 {
272 r->f = a->f * (1. - b->f/100.);
273 }
274
275 static void rpn_mul_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
276 {
277 r->f = a->f * b->f / 100.;
278 }
279
280 static void rpn_div_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
281 {
282 if (b->f == 0)
283 calc.is_nan = TRUE;
284 else
285 r->f = a->f * 100. / b->f;
286 }
287
288 void run_operator(calc_node_t *result,
289 calc_node_t *a,
290 calc_node_t *b,
291 unsigned int operation)
292 {
293 calc_number_t da, db, dc;
294 DWORD base = calc.base;
295
296 da = a->number;
297 db = b->number;
298 if (a->base == IDC_RADIO_DEC && b->base != IDC_RADIO_DEC) {
299 db.f = logic_int2dbl(&b->number);
300 base = IDC_RADIO_DEC;
301 } else
302 if (a->base != IDC_RADIO_DEC && b->base == IDC_RADIO_DEC) {
303 da.f = logic_int2dbl(&a->number);
304 base = IDC_RADIO_DEC;
305 }
306
307 if (base == IDC_RADIO_DEC) {
308 if (percent_mode) {
309 percent_mode = FALSE;
310 operator_list[operation].op_p(&dc, &da, &db);
311 } else
312 operator_list[operation].op_f(&dc, &da, &db);
313 if (_finite(dc.f) == 0)
314 calc.is_nan = TRUE;
315 } else {
316 operator_list[operation].op_i(&dc, &da, &db);
317 /* apply final limitator to result */
318 apply_int_mask(&dc);
319 }
320
321 if (a->base == IDC_RADIO_DEC && b->base != IDC_RADIO_DEC) {
322 result->number.i = logic_dbl2int(&dc);
323 apply_int_mask(&result->number);
324 } else
325 if (a->base != IDC_RADIO_DEC && b->base == IDC_RADIO_DEC)
326 result->number.f = dc.f;
327 else
328 result->number = dc;
329 }
330
331 static void evalStack(calc_number_t *number)
332 {
333 stack_node_t *op, ip;
334 unsigned int prec;
335
336 op = pop();
337 ip = *op;
338 prec = operator_list[ip.node.operation].prec;
339 while (!is_stack_empty()) {
340 op = pop();
341
342 if (prec <= operator_list[op->node.operation].prec) {
343 if (op->node.operation == RPN_OPERATOR_PARENT) continue;
344
345 calc.prev = ip.node.number;
346 run_operator(&ip.node, &op->node, &ip.node, op->node.operation);
347 if (calc.is_nan) {
348 flush_postfix();
349 return;
350 }
351 } else {
352 push(op);
353 break;
354 }
355 }
356
357 if(ip.node.operation != RPN_OPERATOR_EQUAL && ip.node.operation != RPN_OPERATOR_PERCENT)
358 push(&ip);
359
360 calc.prev_operator = op->node.operation;
361
362 *number = ip.node.number;
363 }
364
365 int exec_infix2postfix(calc_number_t *number, unsigned int func)
366 {
367 stack_node_t tmp;
368
369 if (is_stack_empty() && func == RPN_OPERATOR_EQUAL) {
370 /* if a number has been entered with exponential */
371 /* notation, I may update it with normal mode */
372 if (calc.sci_in)
373 return 1;
374 return 0;
375 }
376
377 if (func == RPN_OPERATOR_PERCENT)
378 percent_mode = TRUE;
379
380 tmp.node.number = *number;
381 tmp.node.base = calc.base;
382 tmp.node.operation = func;
383
384 push(&tmp);
385
386 if (func == RPN_OPERATOR_NONE)
387 return 0;
388
389 if (func != RPN_OPERATOR_PARENT) {
390 calc.last_operator = func;
391 evalStack(number);
392 }
393 return 1;
394 }
395
396 void exec_change_infix(void)
397 {
398 stack_node_t *op = stack;
399
400 if (op == NULL)
401 return;
402 if (op->node.operation == RPN_OPERATOR_PARENT ||
403 op->node.operation == RPN_OPERATOR_PERCENT ||
404 op->node.operation == RPN_OPERATOR_EQUAL)
405 return;
406 /* remove the head, it will be re-inserted with new operator */
407 pop();
408 }
409
410 void exec_closeparent(calc_number_t *number)
411 {
412 stack_node_t *op, ip;
413
414 ip.node.number = *number;
415 ip.node.base = calc.base;
416 while (!is_stack_empty()) {
417 op = pop();
418
419 if (op->node.operation == RPN_OPERATOR_PARENT)
420 break;
421
422 run_operator(&ip.node, &op->node, &ip.node, op->node.operation);
423 if (calc.is_nan) {
424 flush_postfix();
425 return;
426 }
427 }
428 *number = ip.node.number;
429 }
430
431 int eval_parent_count(void)
432 {
433 stack_node_t *s = stack;
434 int n = 0;
435
436 while (s != NULL) {
437 if (s->node.operation == RPN_OPERATOR_PARENT)
438 n++;
439 s = (stack_node_t *)(s->next);
440 }
441 return n;
442 }
443
444 void flush_postfix()
445 {
446 while (!is_stack_empty())
447 pop();
448 /* clear prev and last typed operators */
449 calc.prev_operator =
450 calc.last_operator = 0;
451 }
452
453 void start_rpn_engine(void)
454 {
455 stack = NULL;
456 }
457
458 void stop_rpn_engine(void)
459 {
460 }
461