AP_T pop(void) { if (!Stack_empty(sp)) return Stack_pop(sp); else { Fmt_fprint(stderr, "?stack underflow\n"); return AP_new(0); } }
T AP_pow(T x, T y, T p) { T z; assert(x); assert(y); assert(y->sign == 1); assert( (!p) || (p->sign==1 && !iszero(p) && !isone(p))); if (iszero(x)) return AP_new(0); if (iszero(y)) return AP_new(1); if (isone(x)) return AP_new((((y)->digits[0]&1) == 0) ? 1 : x->sign); if (p) if (isone(y)) z = AP_mod(x, p); else { T y2 = AP_rshift(y, 1), t = AP_pow(x, y2, p); z = mulmod(t, t, p); AP_free(&y2); AP_free(&t); if (!(((y)->digits[0]&1) == 0)) { z = mulmod(y2 = AP_mod(x, p), t = z, p); AP_free(&y2); AP_free(&t); } } else if (isone(y)) z = AP_addi(x, 0); else { T y2 = AP_rshift(y, 1), t = AP_pow(x, y2, NULL); z = AP_mul(t, t); AP_free(&y2); AP_free(&t); if (!(((y)->digits[0]&1) == 0)) { z = AP_mul(x, t = z); AP_free(&t); } } return z; }
T AP_rshift(T x, int s) { assert(x); assert(s >= 0); if (s >= 8*x->ndigits) return AP_new(0); else { T z = mk(x->ndigits - s/8); XP_rshift(z->size, z->digits, x->ndigits, x->digits, s, 0); normalize(z, z->size); z->sign = iszero(z) ? 1 : x->sign; return z; } }
T AP_fromstr(const char *str, int base, char **end) { T z; const char *p = str; char *endp, sign = '\0'; int carry; assert(p); assert(base >= 2 && base <= 36); while (*p && isspace(*p)) p++; if (*p == '-' || *p == '+') sign = *p++; { const char *start; int k, n = 0; for ( ; *p == '0' && p[1] == '0'; p++) ; start = p; for ( ; ( ('0' <= *p && *p <= '9' && *p < '0' + base) || ('a' <= *p && *p <= 'z' && *p < 'a' + base - 10) || ('A' <= *p && *p <= 'Z' && *p < 'A' + base - 10)); p++) n++; for (k = 1; (1<<k) < base; k++) ; z = mk(((k*n + 7)&~7)/8); p = start; } carry = XP_fromstr(z->size, z->digits, p, base, &endp); assert(carry == 0); normalize(z, z->size); if (endp == p) { endp = (char *)str; z = AP_new(0); } else z->sign = iszero(z) || sign != '-' ? 1 : -1; if (end) *end = (char *)endp; return z; }
int main(int argc, char *argv[]) { int c; sp = Stack_new(); Fmt_register('D', AP_fmt); while ((c = getchar()) != EOF) switch (c) { case ' ': case '\t': case '\n': case '\f': case '\r': break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { char buf[512]; { int i = 0; for ( ; c != EOF && isdigit(c); c = getchar(), i++) if (i < (int)sizeof (buf) - 1) buf[i] = c; if (i > (int)sizeof (buf) - 1) { i = (int)sizeof (buf) - 1; Fmt_fprint(stderr, "?integer constant exceeds %d digits\n", i); } buf[i] = 0; if (c != EOF) ungetc(c, stdin); } Stack_push(sp, AP_fromstr(buf, 10, NULL)); break; } case '+': { AP_T y = pop(), x = pop(); Stack_push(sp, AP_add(x, y)); AP_free(&x); AP_free(&y); break; } case '-': { AP_T y = pop(), x = pop(); Stack_push(sp, AP_sub(x, y)); AP_free(&x); AP_free(&y); break; } case '*': { AP_T y = pop(), x = pop(); Stack_push(sp, AP_mul(x, y)); AP_free(&x); AP_free(&y); break; } case '/': { AP_T y = pop(), x = pop(); if (AP_cmpi(y, 0) == 0) { Fmt_fprint(stderr, "?/ by 0\n"); Stack_push(sp, AP_new(0)); } else Stack_push(sp, AP_div(x, y)); AP_free(&x); AP_free(&y); break; } case '%': { AP_T y = pop(), x = pop(); if (AP_cmpi(y, 0) == 0) { Fmt_fprint(stderr, "?%% by 0\n"); Stack_push(sp, AP_new(0)); } else Stack_push(sp, AP_mod(x, y)); AP_free(&x); AP_free(&y); break; } case '^': { AP_T y = pop(), x = pop(); if (AP_cmpi(y, 0) <= 0) { Fmt_fprint(stderr, "?nonpositive power\n"); Stack_push(sp, AP_new(0)); } else Stack_push(sp, AP_pow(x, y, NULL)); AP_free(&x); AP_free(&y); break; } case 'd': { AP_T x = pop(); Stack_push(sp, x); Stack_push(sp, AP_addi(x, 0)); break; } case 'p': { AP_T x = pop(); Fmt_print("%D\n", x); Stack_push(sp, x); break; } case 'f': if (!Stack_empty(sp)) { Stack_T tmp = Stack_new(); while (!Stack_empty(sp)) { AP_T x = pop(); Fmt_print("%D\n", x); Stack_push(tmp, x); } while (!Stack_empty(tmp)) Stack_push(sp, Stack_pop(tmp)); Stack_free(&tmp); } break; case '~': { AP_T x = pop(); Stack_push(sp, AP_neg(x)); AP_free(&x); break; } case 'c': while (!Stack_empty(sp)) { AP_T x = Stack_pop(sp); AP_free(&x); } break; case 'q': while (!Stack_empty(sp)) { AP_T x = Stack_pop(sp); AP_free(&x); } Stack_free(&sp); return EXIT_SUCCESS; default: if (isprint(c)) Fmt_fprint(stderr, "?'%c'", c); else Fmt_fprint(stderr, "?'\\%03o'", c); Fmt_fprint(stderr, " is unimplemented\n"); break; } while (!Stack_empty(sp)) { AP_T x = Stack_pop(sp); AP_free(&x); } Stack_free(&sp); return EXIT_SUCCESS; }