#define ARITH(fn, op) \ static inline int \ fn(ns_t * s) \ { \ if (s->top > 0) \ { \ --s->top; \ op(NS_PEEK(s), \ NS_PEEK(s), s->num[s->top+1]); \ return 0; \ } \ else \ { \ fprintf(stderr, "dc: underflow\n"); \ return 1; \ } \ } #define ARITH_ONE(fn, op) \ static inline int \ fn(ns_t * s) \ { \ if (s->top > -1) \ { \ op(NS_PEEK(s), \ NS_PEEK(s)); \ return 0; \ } \ else \ { \ fprintf(stderr, "dc: underflow\n"); \ return 1; \ } \ } #define ARITH_DIV(fn, op) \ static inline int fn(ns_t * s) \ { \ if (s->top > 0) \ { \ if (!(mpf_cmp_ui(NS_PEEK(s), 0) || \ mpf_cmp_ui(s->num[s->top-1], 0))) \ { fprintf(stderr, "dc: divide by 0\n"); return 2; } \ else \ { \ --s->top; op(NS_PEEK(s), NS_PEEK(s), s->num[s->top+1]); \ return 0; \ } \ } \ else \ { fprintf(stderr, "dc: underflow\n"); return 1; } \ } /* handles negative numbers and is multi-presision unlike mpf_exp_ui */ static inline int ns_exp(ns_t * s) { if (s->top > 0) { if (!(mpf_cmp_ui(NS_PEEK(s), 0) || mpf_cmp_ui(s->num[s->top-1], 0))) { fprintf(stderr, "dc: divide by 0\n"); return 2; } else { mpf_t i; mpf_t mpf; if (mpf_cmp_ui(NS_PEEK(s), 0) == 0) { mpf_set_ui(NS_PEEK(s), 1); return 0; } --s->top; mpf_inits(i, mpf, NULL); mpf_set(mpf, NS_PEEK(s)); mpf_set(i, s->num[s->top + 1]); mpf_ceil(i, i); mpf_sub_ui(i, i, 1); if (mpf_cmp_ui(i, 0) > 0) { for (; mpf_cmp_ui(i, 0); mpf_sub_ui(i, i, 1)) { mpf_mul(NS_PEEK(s), NS_PEEK(s), mpf); } } else { for (; mpf_cmp_ui(i, 0); mpf_add_ui(i, i, 1)) { mpf_div(NS_PEEK(s), NS_PEEK(s), mpf); } } mpf_clears(i, mpf, NULL); return 0; } { } } else { fprintf(stderr, "dc: underflow\n"); return 1; } __builtin_unreachable(); } ARITH(ns_add, mpf_add) ARITH(ns_sub, mpf_sub) ARITH(ns_mul, mpf_mul) ARITH_DIV(ns_div, mpf_div) ARITH_DIV(ns_mod, mpf_div) ARITH_ONE(ns_abs, mpf_abs) ARITH_ONE(ns_sqrt, mpf_sqrt) ARITH_ONE(ns_floor, mpf_floor) ARITH_ONE(ns_ceil, mpf_ceil)