static void bmod(void) { struct number *a, *b, *r; BN_CTX *ctx; u_int scale; a = pop_number(); if (a == NULL) return; b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); scale = max(a->scale, b->scale); r->scale = scale; if (BN_is_zero(a->number)) warnx("remainder by zero"); else { normalize(a, scale); normalize(b, scale); ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_mod(r->number, b->number, a->number, ctx)); BN_CTX_free(ctx); } push_number(r); free_number(a); free_number(b); }
void eval(stack **n_stack, stack **o_stack, double *x, double *y){ //Using easier names char op=top_operator(*o_stack); double n1, n2; //Checking the different cases for the top of the stack if(op=='='){ pop_operator(&(*o_stack)); if(pop_operator(&(*o_stack))=='x') *x=top_number(*n_stack); else *y=top_number(*n_stack); } else if(op=='x'){ pop_operator(&(*o_stack)); push_number(*x, &(*n_stack)); } else if(op=='y'){ pop_operator(&(*o_stack)); push_number(*y, &(*n_stack)); } else{//Push the computed result into the n_stack n1=pop_number(&(*n_stack)); n2=pop_number(&(*n_stack)); op=pop_operator(&(*o_stack)); push_number(compute(n1, op, n2), &(*n_stack)); } }
static void bsub(void) { struct number *a, *b, *r; a = pop_number(); if (a == NULL) return; b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); r->scale = max(a->scale, b->scale); if (r->scale > a->scale) normalize(a, r->scale); else if (r->scale > b->scale) normalize(b, r->scale); bn_check(BN_sub(r->number, b->number, a->number)); push_number(r); free_number(a); free_number(b); }
static void bdivmod(void) { struct number *a, *b, *frac, *quotient, *rdiv, *remainder; BN_CTX *ctx; u_int scale; a = pop_number(); if (a == NULL) return; b = pop_number(); if (b == NULL) { push_number(a); return; } rdiv = new_number(); quotient = new_number(); remainder = new_number(); scale = max(a->scale, b->scale); rdiv->scale = 0; remainder->scale = scale; quotient->scale = bmachine.scale; scale = max(a->scale, b->scale); if (BN_is_zero(a->number)) warnx("divide by zero"); else { normalize(a, scale); normalize(b, scale); ctx = BN_CTX_new(); bn_checkp(ctx); /* * Unlike other languages' divmod operations, dc is specified * to return the remainder and the full quotient, rather than * the remainder and the floored quotient. bn(3) has no * function to calculate both. So we'll use BN_div to get the * remainder and floored quotient, then calculate the full * quotient from those. * * quotient = rdiv + remainder / divisor */ bn_check(BN_div(rdiv->number, remainder->number, b->number, a->number, ctx)); frac = div_number(remainder, a, bmachine.scale); normalize(rdiv, bmachine.scale); normalize(remainder, scale); bn_check(BN_add(quotient->number, rdiv->number, frac->number)); free_number(frac); BN_CTX_free(ctx); } push_number(quotient); push_number(remainder); free_number(rdiv); free_number(a); free_number(b); }
static void compare(enum bcode_compare type) { int index, elseindex; struct number *a, *b; bool ok; struct value *v; elseindex = NO_ELSE; index = readreg(); if (readch() == 'e') elseindex = readreg(); else unreadch(); a = pop_number(); if (a == NULL) return; b = pop_number(); if (b == NULL) { push_number(a); return; } ok = compare_numbers(type, a, b); if (!ok && elseindex != NO_ELSE) index = elseindex; if (index >= 0 && (ok || (!ok && elseindex != NO_ELSE))) { v = stack_tos(&bmachine.reg[index]); if (v == NULL) warnx("register '%c' (0%o) is empty", index, index); else { switch(v->type) { case BCODE_NONE: warnx("register '%c' (0%o) is empty", index, index); break; case BCODE_NUMBER: warn("eval called with non-string argument"); break; case BCODE_STRING: eval_string(bstrdup(v->u.string)); break; } } } }
static void load_array(void) { struct number *inumber, *n; struct stack *stack; struct value *v; struct value copy; u_long idx; int reg; reg = readreg(); if (reg >= 0) { inumber = pop_number(); if (inumber == NULL) return; idx = get_ulong(inumber); if (BN_is_negative(inumber->number)) warnx("negative idx"); else if (idx == ULONG_MAX || idx > MAX_ARRAY_INDEX) warnx("idx too big"); else { stack = &bmachine.reg[reg]; v = frame_retrieve(stack, idx); if (v == NULL || v->type == BCODE_NONE) { n = new_number(); bn_check(BN_zero(n->number)); push_number(n); } else push(stack_dup_value(v, ©)); } free_number(inumber); } }
static void load_array(void) { int reg; struct number *inumber, *n; u_long index; struct stack *stack; struct value *v, copy; reg = readreg(); if (reg >= 0) { inumber = pop_number(); if (inumber == NULL) return; index = get_ulong(inumber); if (BN_cmp(inumber->number, &zero) < 0) warnx("negative index"); else if (index == BN_MASK2 || index > MAX_ARRAY_INDEX) warnx("index too big"); else { stack = &bmachine.reg[reg]; v = frame_retrieve(stack, index); if (v == NULL) { n = new_number(); bn_check(BN_zero(n->number)); push_number(n); } else push(stack_dup_value(v, ©)); } free_number(inumber); } }
static void store_array(void) { struct number *inumber; struct value *value; struct stack *stack; u_long idx; int reg; reg = readreg(); if (reg >= 0) { inumber = pop_number(); if (inumber == NULL) return; value = pop(); if (value == NULL) { free_number(inumber); return; } idx = get_ulong(inumber); if (BN_is_negative(inumber->number)) { warnx("negative idx"); stack_free_value(value); } else if (idx == ULONG_MAX || idx > MAX_ARRAY_INDEX) { warnx("idx too big"); stack_free_value(value); } else { stack = &bmachine.reg[reg]; frame_assign(stack, idx, value); } free_number(inumber); } }
static void store_array(void) { int reg; struct number *inumber; u_long index; struct value *value; struct stack *stack; reg = readreg(); if (reg >= 0) { inumber = pop_number(); if (inumber == NULL) return; value = pop(); if (value == NULL) { free_number(inumber); return; } index = get_ulong(inumber); if (BN_cmp(inumber->number, &zero) < 0) { warnx("negative index"); stack_free_value(value); } else if (index == BN_MASK2 || index > MAX_ARRAY_INDEX) { warnx("index too big"); stack_free_value(value); } else { stack = &bmachine.reg[reg]; frame_assign(stack, index, value); } free_number(inumber); } }
static void lesseq_numbers(void) { struct number *a, *b, *r; a = pop_number(); if (a == NULL) return; b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); bn_check(BN_set_word(r->number, compare_numbers(BCODE_NOT_GREATER, a, b) ? 1 : 0)); push_number(r); }
static void equal_numbers(void) { struct number *a, *b, *r; a = pop_number(); if (a == NULL) { return; } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); bn_check(BN_set_word(r->number, compare_numbers(BCODE_EQUAL, a, b) ? 1 : 0)); push_number(r); }
static void bdiv(void) { struct number *a, *b, *r; a = pop_number(); if (a == NULL) return; b = pop_number(); if (b == NULL) { push_number(a); return; } r = div_number(b, a, bmachine.scale); push_number(r); free_number(a); free_number(b); }
static void bdivmod(void) { struct number *a, *b; struct number *rdiv, *rmod; u_int scale; BN_CTX *ctx; a = pop_number(); if (a == NULL) { return; } b = pop_number(); if (b == NULL) { push_number(a); return; } rdiv = new_number(); rmod = new_number(); rdiv->scale = bmachine.scale; rmod->scale = max(b->scale, a->scale + bmachine.scale); scale = max(a->scale, b->scale); if (BN_is_zero(a->number)) warnx("divide by zero"); else { normalize(a, scale); normalize(b, scale + bmachine.scale); ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_div(rdiv->number, rmod->number, b->number, a->number, ctx)); BN_CTX_free(ctx); } push_number(rdiv); push_number(rmod); free_number(a); free_number(b); }
static void not(void) { struct number *a; a = pop_number(); if (a == NULL) return; a->scale = 0; bn_check(BN_set_word(a->number, BN_get_word(a->number) ? 0 : 1)); push_number(a); }
static void bmul(void) { struct number *a, *b, *r; a = pop_number(); if (a == NULL) return; b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); bmul_number(r, a, b, bmachine.scale); push_number(r); free_number(a); free_number(b); }
static void bmul(void) { struct number *a, *b; struct number *r; a = pop_number(); if (a == NULL) { return; } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); bmul_number(r, a, b); push_number(r); free_number(a); free_number(b); }
static void bdiv(void) { struct number *a, *b, *r; BN_CTX *ctx; u_int scale; a = pop_number(); if (a == NULL) { return; } b = pop_number(); if (b == NULL) { push_number(a); return; } r = new_number(); r->scale = bmachine.scale; scale = max(a->scale, b->scale); if (BN_is_zero(a->number)) warnx("divide by zero"); else { normalize(a, scale); normalize(b, scale + r->scale); ctx = BN_CTX_new(); bn_checkp(ctx); bn_check(BN_div(r->number, NULL, b->number, a->number, ctx)); BN_CTX_free(ctx); } push_number(r); free_number(a); free_number(b); }
static void set_obase(void) { struct number *n; u_long base; n = pop_number(); if (n != NULL) { base = get_ulong(n); if (base != ULONG_MAX && base > 1 && base <= UINT_MAX) bmachine.obase = (u_int)base; else warnx("output base must be a number greater than 1"); free_number(n); } }
static void set_obase(void) { struct number *n; u_long base; n = pop_number(); if (n != NULL) { base = get_ulong(n); if (base != BN_MASK2 && base > 1) bmachine.obase = base; else warnx("output base must be a number greater than 1"); free_number(n); } }
static void bsqrt(void) { struct number *n; struct number *r; BIGNUM *x, *y; u_int scale, onecount; BN_CTX *ctx; onecount = 0; n = pop_number(); if (n == NULL) { return; } if (BN_is_zero(n->number)) { r = new_number(); push_number(r); } else if (BN_is_negative(n->number)) warnx("square root of negative number"); else { scale = max(bmachine.scale, n->scale); normalize(n, 2*scale); x = BN_dup(n->number); bn_checkp(x); bn_check(BN_rshift(x, x, BN_num_bits(x)/2)); y = BN_new(); bn_checkp(y); ctx = BN_CTX_new(); bn_checkp(ctx); for (;;) { bn_checkp(BN_copy(y, x)); bn_check(BN_div(x, NULL, n->number, x, ctx)); bn_check(BN_add(x, x, y)); bn_check(BN_rshift1(x, x)); if (bsqrt_stop(x, y, &onecount)) break; } r = bmalloc(sizeof(*r)); r->scale = scale; r->number = y; BN_free(x); BN_CTX_free(ctx); push_number(r); } free_number(n); }
static void set_ibase(void) { struct number *n; u_long base; n = pop_number(); if (n != NULL) { base = get_ulong(n); if (base != ULONG_MAX && 2 <= base && base <= 16) bmachine.ibase = (u_int)base; else warnx("input base must be a number between 2 and 16 " "(inclusive)"); free_number(n); } }
static void set_scale(void) { struct number *n; u_long scale; n = pop_number(); if (n != NULL) { if (BN_is_negative(n->number)) warnx("scale must be a nonnegative number"); else { scale = get_ulong(n); if (scale != ULONG_MAX && scale <= UINT_MAX) bmachine.scale = (u_int)scale; else warnx("scale too large"); } free_number(n); } }
static void set_scale(void) { struct number *n; u_long scale; n = pop_number(); if (n != NULL) { if (BN_cmp(n->number, &zero) < 0) warnx("scale must be a nonnegative number"); else { scale = get_ulong(n); if (scale != BN_MASK2) bmachine.scale = scale; else warnx("scale too large"); } free_number(n); } }
static void quitN(void) { struct number *n; u_long i; n = pop_number(); if (n == NULL) return; i = get_ulong(n); if (i == BN_MASK2 || i == 0) warnx("Q command requires a number >= 1"); else if (bmachine.readsp < i) warnx("Q command argument exceeded string execution depth"); else { while (i-- > 0) { src_free(); bmachine.readsp--; } } }
static void skipN(void) { struct number *n; u_long i; n = pop_number(); if (n == NULL) return; i = get_ulong(n); if (i == ULONG_MAX) warnx("J command requires a number >= 0"); else if (i > 0 && bmachine.readsp < i) warnx("J command argument exceeded string execution depth"); else { while (i-- > 0) { src_free(); bmachine.readsp--; } skip_until_mark(); } }
static void bexp(void) { struct number *a, *p; struct number *r; bool neg; u_int rscale; p = pop_number(); if (p == NULL) return; a = pop_number(); if (a == NULL) { push_number(p); return; } if (p->scale != 0) { BIGNUM *i, *f; i = BN_new(); bn_checkp(i); f = BN_new(); bn_checkp(f); split_number(p, i, f); if (!BN_is_zero(f)) warnx("Runtime warning: non-zero fractional part in exponent"); BN_free(i); BN_free(f); } normalize(p, 0); neg = false; if (BN_is_negative(p->number)) { neg = true; negate(p); rscale = bmachine.scale; } else { /* Posix bc says min(a.scale * b, max(a.scale, scale) */ u_long b; u_int m; b = BN_get_word(p->number); m = max(a->scale, bmachine.scale); rscale = a->scale * (u_int)b; if (rscale > m || (a->scale > 0 && (b == ULONG_MAX || b > UINT_MAX))) rscale = m; } if (BN_is_zero(p->number)) { r = new_number(); bn_check(BN_one(r->number)); normalize(r, rscale); } else { u_int ascale, mscale; ascale = a->scale; while (!BN_is_bit_set(p->number, 0)) { ascale *= 2; bmul_number(a, a, a, ascale); bn_check(BN_rshift1(p->number, p->number)); } r = dup_number(a); bn_check(BN_rshift1(p->number, p->number)); mscale = ascale; while (!BN_is_zero(p->number)) { ascale *= 2; bmul_number(a, a, a, ascale); if (BN_is_bit_set(p->number, 0)) { mscale += ascale; bmul_number(r, r, a, mscale); } bn_check(BN_rshift1(p->number, p->number)); } if (neg) { BN_CTX *ctx; BIGNUM *one; one = BN_new(); bn_checkp(one); bn_check(BN_one(one)); ctx = BN_CTX_new(); bn_checkp(ctx); scale_number(one, r->scale + rscale); if (BN_is_zero(r->number)) warnx("divide by zero"); else bn_check(BN_div(r->number, NULL, one, r->number, ctx)); BN_free(one); BN_CTX_free(ctx); r->scale = rscale; } else normalize(r, rscale); } push_number(r); free_number(a); free_number(p); }
static int rpn_eval(const token* t) { double o1, o2; switch (t->type) { case MATHOP_NUMBER: return push_number(t->value); case MATHOP_ADD: return pop_number(&o2) || pop_number(&o1) || push_number(o1 + o2); case MATHOP_SUB: return pop_number(&o2) || pop_number(&o1) || push_number(o1 - o2); case MATHOP_MUL: return pop_number(&o2) || pop_number(&o1) || push_number(o1 * o2); case MATHOP_DIV: return pop_number(&o2) || pop_number(&o1) || push_number(o1 / o2); case MATHOP_NEG: return pop_number(&o1) || push_number(-o1); case MATHOP_DROP: return pop_number(&o1); case MATHOP_DUP: if(pop_number(&o1)) return -1; return push_number(o1) || push_number(o1); case MATHOP_SWAP: return pop_number(&o2) || pop_number(&o1) || push_number(o2) || push_number(o1); case MATHOP_MOD: return pop_number(&o2) || pop_number(&o1) || push_number(fmod(o1,o2)); case MATHOP_POW: return pop_number(&o2) || pop_number(&o1) || push_number(pow(o1,o2)); case MATHOP_EXP: return pop_number(&o1) || push_number(exp(o1)); case MATHOP_LOG10: return pop_number(&o1) || push_number(log10(o1)); case MATHOP_LN: return pop_number(&o1) || push_number(log(o1)); case MATHOP_ABS: return pop_number(&o1) || push_number(fabs(o1)); case MATHOP_SQRT: return pop_number(&o1) || push_number(sqrt(o1)); case MATHOP_CBRT: return pop_number(&o1) || push_number(cbrt(o1)); case MATHOP_FLOOR: return pop_number(&o1) || push_number(floor(o1)); case MATHOP_CEIL: return pop_number(&o1) || push_number(ceil(o1)); case MATHOP_ROUND: return pop_number(&o1) || push_number(round(o1)); case MATHOP_NEARBYINT: return pop_number(&o1) || push_number(nearbyint(o1)); case MATHOP_TRUNC: return pop_number(&o1) || push_number(trunc(o1)); case MATHOP_E: return push_number(M_E); case MATHOP_PI: return push_number(M_PI); default: LM_WARN("Invalid RPN token type\n"); return -1; } }
float operator()(cell_ptr& l) { return static_cast<float>(pop_number(l)); }
static void bexp(void) { struct number *a, *p; struct number *r; bool neg; u_int scale; p = pop_number(); if (p == NULL) { return; } a = pop_number(); if (a == NULL) { push_number(p); return; } if (p->scale != 0) warnx("Runtime warning: non-zero scale in exponent"); normalize(p, 0); neg = false; if (BN_cmp(p->number, &zero) < 0) { neg = true; negate(p); scale = bmachine.scale; } else { /* Posix bc says min(a.scale * b, max(a.scale, scale) */ u_long b; u_int m; b = BN_get_word(p->number); m = max(a->scale, bmachine.scale); scale = a->scale * (u_int)b; if (scale > m || (a->scale > 0 && (b == BN_MASK2 || b > UINT_MAX))) scale = m; } if (BN_is_zero(p->number)) { r = new_number(); bn_check(BN_one(r->number)); normalize(r, scale); } else { while (!BN_is_bit_set(p->number, 0)) { bmul_number(a, a, a); bn_check(BN_rshift1(p->number, p->number)); } r = dup_number(a); normalize(r, scale); bn_check(BN_rshift1(p->number, p->number)); while (!BN_is_zero(p->number)) { bmul_number(a, a, a); if (BN_is_bit_set(p->number, 0)) bmul_number(r, r, a); bn_check(BN_rshift1(p->number, p->number)); } if (neg) { BN_CTX *ctx; BIGNUM *one; one = BN_new(); bn_checkp(one); bn_check(BN_one(one)); ctx = BN_CTX_new(); bn_checkp(ctx); scale_number(one, r->scale + scale); normalize(r, scale); bn_check(BN_div(r->number, NULL, one, r->number, ctx)); BN_free(one); BN_CTX_free(ctx); } else normalize(r, scale); } push_number(r); free_number(a); free_number(p); }
double operator()(cell_ptr& l) { return static_cast<double>(pop_number(l)); }