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