reactos/rosapps/roscalc/rpn.c
Timo Kreuzer ca60bdfbe8 New version of calc written by Carlo Bramini (carlo(dot)bramix AT libero.it)
Better than the one we currently have. For now in rosapps, so we can test it, if it's all working fine, we should replace the wine one.
Changes by me: use pow() instead of cbrt(), as cbrt doesn't work in our tree.
I imported the whole codebase, although the mpfr files are not used.
I moved the localizations to "lang" and the icons to "res" subfolder.

svn path=/trunk/; revision=31512
2007-12-31 05:51:52 +00:00

419 lines
11 KiB
C

#include "calc.h"
typedef struct {
calc_number_t number;
unsigned int operation;
} calc_node_t;
typedef struct {
calc_node_t node;
void *next;
} stack_node_t;
typedef void (*operator_call)(calc_number_t *, calc_number_t *, calc_number_t *);
typedef struct {
unsigned int prec;
operator_call op_f;
operator_call op_i;
operator_call op_p;
} calc_operator_t;
static stack_node_t *stack;
static stack_node_t temp;
static BOOL percent_mode;
static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_sub_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_mul_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_div_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_mod_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_pow_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_sqr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_and_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_or_f (calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_xor_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_shl_f(calc_number_t *r, calc_number_t *a, calc_number_t *b);
/* Integer mode calculations */
static void rpn_add_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_sub_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_mul_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_div_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_mod_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_and_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_or_i (calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_xor_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_shl_i(calc_number_t *r, calc_number_t *a, calc_number_t *b);
/* Percentage mode calculations */
static void rpn_add_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_sub_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_mul_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static void rpn_div_p(calc_number_t *r, calc_number_t *a, calc_number_t *b);
static const calc_operator_t operator_list[] = {
{ 0, NULL, NULL, NULL, }, // RPN_OPERATOR_PARENT
{ 0, NULL, NULL, NULL, }, // RPN_OPERATOR_PERCENT
{ 0, NULL, NULL, NULL, }, // RPN_OPERATOR_EQUAL
{ 1, rpn_or_f, rpn_or_i, NULL, }, // RPN_OPERATOR_OR
{ 2, rpn_xor_f, rpn_xor_i, NULL, }, // RPN_OPERATOR_XOR
{ 3, rpn_and_f, rpn_and_i, NULL, }, // RPN_OPERATOR_AND
{ 4, rpn_shl_f, rpn_shl_i, NULL, }, // RPN_OPERATOR_LSH
{ 5, rpn_add_f, rpn_add_i, rpn_add_p, }, // RPN_OPERATOR_ADD
{ 5, rpn_sub_f, rpn_sub_i, rpn_sub_p, }, // RPN_OPERATOR_SUB
{ 6, rpn_mul_f, rpn_mul_i, rpn_mul_p, }, // RPN_OPERATOR_MULT
{ 6, rpn_div_f, rpn_div_i, rpn_div_p, }, // RPN_OPERATOR_DIV
{ 6, rpn_mod_f, rpn_mod_i, NULL, }, // RPN_OPERATOR_MOD
{ 7, rpn_pow_f, NULL, NULL, }, // RPN_OPERATOR_POW
{ 7, rpn_sqr_f, NULL, NULL, }, // RPN_OPERATOR_SQR
};
static stack_node_t *pop(void)
{
if (stack == NULL)
return NULL;
temp = *stack;
free(stack);
stack = temp.next;
return &temp;
}
static int is_stack_empty(void)
{
return (stack == NULL);
}
static void push(stack_node_t *op)
{
stack_node_t *z = (stack_node_t *)malloc(sizeof(stack_node_t));
*z = *op;
z->next = stack;
stack = z;
}
/*
static unsigned int get_prec(unsigned int opc)
{
unsigned int x;
for (x=0; x<SIZEOF(operator_list); x++)
if (operator_list[x].opc == opc) break;
return operator_list[x].prec;
}
*/
/* Real mode calculations */
static void rpn_add_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->f = a->f + b->f;
}
static void rpn_sub_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->f = a->f - b->f;
}
static void rpn_mul_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->f = a->f * b->f;
}
static void rpn_div_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
if (b->f == 0)
calc.is_nan = TRUE;
else
r->f = a->f / b->f;
}
static void rpn_mod_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
double t;
if (b->f == 0)
calc.is_nan = TRUE;
else {
modf(a->f/b->f, &t);
r->f = a->f - (t * b->f);
}
}
static void rpn_and_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
calc_number_t ai, bi;
ai.i = logic_dbl2int(a);
bi.i = logic_dbl2int(b);
r->f = (long double)(ai.i & bi.i);
}
static void rpn_or_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
calc_number_t ai, bi;
ai.i = logic_dbl2int(a);
bi.i = logic_dbl2int(b);
r->f = (long double)(ai.i | bi.i);
}
static void rpn_xor_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
calc_number_t ai, bi;
ai.i = logic_dbl2int(a);
bi.i = logic_dbl2int(b);
r->f = (long double)(ai.i ^ bi.i);
}
static void rpn_shl_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
calc_number_t ai, bi;
ai.i = logic_dbl2int(a);
bi.i = logic_dbl2int(b);
r->f = (long double)(ai.i << bi.i);
}
static void rpn_pow_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->f = pow(a->f, b->f);
if (_finite(r->f) == 0 || _isnan(r->f))
calc.is_nan = TRUE;
}
static void rpn_sqr_f(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
if (b->f == 0)
calc.is_nan = TRUE;
else {
r->f = pow(a->f, 1./b->f);
if (_finite(r->f) == 0 || _isnan(r->f))
calc.is_nan = TRUE;
}
}
/* Integer mode calculations */
static void rpn_add_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->i = a->i + b->i;
}
static void rpn_sub_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->i = a->i - b->i;
}
static void rpn_mul_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->i = a->i * b->i;
}
static void rpn_div_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
if (b->i == 0)
calc.is_nan = TRUE;
else
r->i = a->i / b->i;
}
static void rpn_mod_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
if (b->i == 0)
calc.is_nan = TRUE;
else
r->i = a->i % b->i;
}
static void rpn_and_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->i = a->i & b->i;
}
static void rpn_or_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->i = a->i | b->i;
}
static void rpn_xor_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->i = a->i ^ b->i;
}
static void rpn_shl_i(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->i = a->i << b->i;
}
/* Percent mode calculations */
static void rpn_add_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->f = a->f * (1. + b->f/100.);
}
static void rpn_sub_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->f = a->f * (1. - b->f/100.);
}
static void rpn_mul_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
r->f = a->f * b->f / 100.;
}
static void rpn_div_p(calc_number_t *r, calc_number_t *a, calc_number_t *b)
{
if (b->f == 0)
calc.is_nan = TRUE;
else
r->f = a->f * 100. / b->f;
}
void run_operator(calc_number_t *result,
calc_number_t *a,
calc_number_t *b,
unsigned int operation)
{
if (calc.base == IDC_RADIO_DEC) {
if (percent_mode) {
percent_mode = FALSE;
operator_list[operation].op_p(result, a, b);
} else
operator_list[operation].op_f(result, a, b);
} else {
operator_list[operation].op_i(result, a, b);
/* apply final limitator to result */
apply_int_mask(result);
}
}
static void evalStack(calc_number_t *number)
{
stack_node_t *op, ip;
unsigned int prec;
percent_mode = FALSE;
op = pop();
ip = *op;
prec = operator_list[ip.node.operation].prec;
while (!is_stack_empty()) {
op = pop();
if (prec <= operator_list[op->node.operation].prec) {
if (op->node.operation == RPN_OPERATOR_PARENT) continue;
calc.prev = ip.node.number;
run_operator(&ip.node.number, &op->node.number, &ip.node.number, op->node.operation);
if (calc.is_nan) {
flush_postfix();
return;
}
} else {
push(op);
break;
}
}
if(ip.node.operation != RPN_OPERATOR_EQUAL && ip.node.operation != RPN_OPERATOR_PERCENT)
push(&ip);
calc.prev_operator = op->node.operation;
*number = ip.node.number;
}
int exec_infix2postfix(calc_number_t *number, unsigned int func)
{
stack_node_t tmp;
if (is_stack_empty() && func == RPN_OPERATOR_EQUAL) {
/* if a number has been entered with exponential */
/* notation, I may update it with normal mode */
if (calc.sci_in)
return 1;
return 0;
}
tmp.node.number = *number;
tmp.node.operation = func;
push(&tmp);
if (func != RPN_OPERATOR_PARENT) {
calc.last_operator = func;
evalStack(number);
}
return 1;
}
void exec_change_infix(void)
{
stack_node_t *op = stack;
if (op == NULL)
return;
if (op->node.operation == RPN_OPERATOR_PARENT ||
op->node.operation == RPN_OPERATOR_PERCENT ||
op->node.operation == RPN_OPERATOR_EQUAL)
return;
/* remove the head, it will be re-inserted with new operator */
pop();
}
void exec_closeparent(calc_number_t *number)
{
stack_node_t *op, ip;
ip.node.number = *number;
while (!is_stack_empty()) {
op = pop();
if (op->node.operation == RPN_OPERATOR_PARENT)
break;
run_operator(&ip.node.number, &op->node.number, &ip.node.number, op->node.operation);
if (calc.is_nan) {
flush_postfix();
return;
}
}
*number = ip.node.number;
}
int eval_parent_count(void)
{
stack_node_t *s = stack;
int n = 0;
while (s != NULL) {
if (s->node.operation == RPN_OPERATOR_PARENT)
n++;
s = (stack_node_t *)(s->next);
}
return n;
}
void flush_postfix()
{
while (!is_stack_empty())
pop();
/* clear prev and last typed operators */
calc.prev_operator =
calc.last_operator = 0;
}
void start_rpn_engine(void)
{
stack = NULL;
}
void stop_rpn_engine(void)
{
}