Annotation of OpenXM_contrib/gmp/demos/pexpr.c, Revision 1.1
1.1 ! maekawa 1: /* Program for computing integer expressions using the GNU Multiple Precision
! 2: Arithmetic Library.
! 3:
! 4: Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
! 5:
! 6: This program is free software; you can redistribute it and/or modify it under
! 7: the terms of the GNU General Public License as published by the Free Software
! 8: Foundation; either version 2 of the License, or (at your option) any later
! 9: version.
! 10:
! 11: This program is distributed in the hope that it will be useful, but WITHOUT ANY
! 12: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
! 13: PARTICULAR PURPOSE. See the GNU General Public License for more details.
! 14:
! 15: You should have received a copy of the GNU General Public License along with
! 16: this program; if not, write to the Free Software Foundation, Inc., 59 Temple
! 17: Place - Suite 330, Boston, MA 02111-1307, USA. */
! 18:
! 19:
! 20: /* This expressions evaluator works by building an expression tree (using a
! 21: recursive descent parser) which is then evaluated. The expression tree is
! 22: useful since we want to optimize certain expressions (like a^b % c).
! 23:
! 24: Usage: pexpr [options] expr ...
! 25: (Assuming you called the executable `pexpr' of course.)
! 26:
! 27: Command line options:
! 28:
! 29: -b print output in binary
! 30: -o print output in octal
! 31: -d print output in decimal (the default)
! 32: -x print output in hexadecimal
! 33: -<NUM> print output in base NUM
! 34: -t print timing information
! 35: -html output html
! 36: -nosplit do not split long lines each 60th digit
! 37: */
! 38:
! 39: /* Define LIMIT_RESOURCE_USAGE if you want to make sure the program doesn't
! 40: use up extensive resources (cpu, memory). Useful for the GMP demo on the
! 41: GMP web site, since we cannot load the server too much. */
! 42:
! 43: #ifdef LIMIT_RESOURCE_USAGE
! 44: #include <sys/types.h>
! 45: #include <sys/time.h>
! 46: #include <sys/resource.h>
! 47: #endif
! 48:
! 49: #include <string.h>
! 50: #include <stdio.h>
! 51: #include <stdlib.h>
! 52: #include <setjmp.h>
! 53: #include <signal.h>
! 54: #include <ctype.h>
! 55:
! 56: #include "gmp.h"
! 57:
! 58: /* GMP version 1.x compatibility. */
! 59: #if ! (__GNU_MP_VERSION >= 2)
! 60: typedef MP_INT __mpz_struct;
! 61: typedef __mpz_struct mpz_t[1];
! 62: typedef __mpz_struct *mpz_ptr;
! 63: #define mpz_fdiv_q mpz_div
! 64: #define mpz_fdiv_r mpz_mod
! 65: #define mpz_tdiv_q_2exp mpz_div_2exp
! 66: #define mpz_sgn(Z) ((Z)->size < 0 ? -1 : (Z)->size > 0)
! 67: #endif
! 68:
! 69: /* GMP version 2.0 compatibility. */
! 70: #if ! (__GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1)
! 71: #define mpz_swap(a,b) \
! 72: do { __mpz_struct __t; __t = *a; *a = *b; *b = __t;} while (0)
! 73: #endif
! 74:
! 75: jmp_buf errjmpbuf;
! 76:
! 77: enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW,
! 78: AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC,
! 79: LOG, LOG2, FERMAT, MERSENNE, FIBONACCI};
! 80:
! 81: /* Type for the expression tree. */
! 82: struct expr
! 83: {
! 84: enum op_t op;
! 85: union
! 86: {
! 87: struct {struct expr *lhs, *rhs;} ops;
! 88: mpz_t val;
! 89: } operands;
! 90: };
! 91:
! 92: typedef struct expr *expr_t;
! 93:
! 94: void cleanup_and_exit (int);
! 95:
! 96: char *skipspace (char *);
! 97: void makeexp (expr_t *, enum op_t, expr_t, expr_t);
! 98: void free_expr (expr_t);
! 99: char *expr (char *, expr_t *);
! 100: char *term (char *, expr_t *);
! 101: char *power (char *, expr_t *);
! 102: char *factor (char *, expr_t *);
! 103: int match (char *, char *);
! 104: int matchp (char *, char *);
! 105: int cputime (void);
! 106:
! 107: void mpz_eval_expr (mpz_ptr, expr_t);
! 108: void mpz_eval_mod_expr (mpz_ptr, expr_t, mpz_ptr);
! 109:
! 110: char *error;
! 111: int flag_print = 1;
! 112: int print_timing = 0;
! 113: int flag_html = 0;
! 114: int flag_splitup_output = 0;
! 115: char *newline = "";
! 116:
! 117: #ifdef _AIX
! 118: #define sigaltstack sigstack
! 119: #endif
! 120:
! 121: #if !defined(_WIN32) && !defined(__DJGPP__)
! 122: void
! 123: setup_error_handler ()
! 124: {
! 125: struct sigaction act;
! 126: struct sigaltstack sigstk;
! 127:
! 128: /* Set up a stack for signal handling. A typical cause of error is stack
! 129: overflow, and in such situation a signal can not be delivered on the
! 130: overflown stack. */
! 131: sigstk.ss_sp = malloc (SIGSTKSZ);
! 132: #ifndef _AIX
! 133: sigstk.ss_size = SIGSTKSZ;
! 134: sigstk.ss_flags = 0;
! 135: #endif /* ! _AIX */
! 136:
! 137: #ifndef _UNICOS
! 138: if (sigaltstack (&sigstk, 0) < 0)
! 139: perror("sigaltstack");
! 140: #endif
! 141:
! 142: /* Initialize structure for sigaction (called below). */
! 143: act.sa_handler = cleanup_and_exit;
! 144: sigemptyset (&(act.sa_mask));
! 145: act.sa_flags = SA_ONSTACK;
! 146:
! 147: #ifdef LIMIT_RESOURCE_USAGE
! 148: {
! 149: struct rlimit limit;
! 150:
! 151: limit.rlim_cur = limit.rlim_max = 0;
! 152: setrlimit (RLIMIT_CORE, &limit);
! 153:
! 154: limit.rlim_cur = 3;
! 155: limit.rlim_max = 4;
! 156: setrlimit (RLIMIT_CPU, &limit);
! 157:
! 158: limit.rlim_cur = limit.rlim_max = 4 * 1024 * 1024;
! 159: setrlimit (RLIMIT_DATA, &limit);
! 160:
! 161: getrlimit (RLIMIT_STACK, &limit);
! 162: limit.rlim_cur = 1 * 1024 * 1024;
! 163: setrlimit (RLIMIT_STACK, &limit);
! 164:
! 165: sigaction (SIGXCPU, &act, 0);
! 166: }
! 167: #endif /* LIMIT_RESOURCE_USAGE */
! 168:
! 169: sigaction (SIGILL, &act, 0);
! 170: sigaction (SIGSEGV, &act, 0);
! 171: sigaction (SIGBUS, &act, 0);
! 172: sigaction (SIGFPE, &act, 0);
! 173: }
! 174: #endif /* ! _WIN32 && ! __DJGPP__ */
! 175:
! 176: main (int argc, char **argv)
! 177: {
! 178: struct expr *e;
! 179: int i;
! 180: mpz_t r;
! 181: int errcode = 0;
! 182: char *str;
! 183: int base = 10;
! 184:
! 185: #if !defined(_WIN32) && !defined(__DJGPP__)
! 186: setup_error_handler ();
! 187: #endif
! 188:
! 189: mpz_init (r);
! 190:
! 191: while (argc > 1 && argv[1][0] == '-')
! 192: {
! 193: char *arg = argv[1];
! 194:
! 195: if (arg[1] >= '0' && arg[1] <= '9')
! 196: break;
! 197:
! 198: if (arg[1] == 't')
! 199: print_timing = 1;
! 200: else if (arg[1] == 'b' && arg[2] >= '0' && arg[2] <= '9')
! 201: {
! 202: base = atoi (arg + 2);
! 203: if (base < 2 || base > 36)
! 204: {
! 205: fprintf (stderr, "error: invalid output base\n");
! 206: exit (-1);
! 207: }
! 208: }
! 209: else if (arg[1] == 'b' && arg[2] == 0)
! 210: base = 2;
! 211: else if (arg[1] == 'x' && arg[2] == 0)
! 212: base = 16;
! 213: else if (arg[1] == 'o' && arg[2] == 0)
! 214: base = 8;
! 215: else if (arg[1] == 'd' && arg[2] == 0)
! 216: base = 10;
! 217: else if (strcmp (arg, "-html") == 0)
! 218: {
! 219: flag_html = 1;
! 220: newline = "<BR>";
! 221: }
! 222: else if (strcmp (arg, "-split") == 0)
! 223: {
! 224: flag_splitup_output = 1;
! 225: }
! 226: else if (strcmp (arg, "-noprint") == 0)
! 227: {
! 228: flag_print = 0;
! 229: }
! 230: else
! 231: {
! 232: fprintf (stderr, "error: unknown option `%s'\n", arg);
! 233: exit (-1);
! 234: }
! 235: argv++;
! 236: argc--;
! 237: }
! 238:
! 239: for (i = 1; i < argc; i++)
! 240: {
! 241: int s;
! 242: int jmpval;
! 243:
! 244: /* Set up error handler for parsing expression. */
! 245: jmpval = setjmp (errjmpbuf);
! 246: if (jmpval != 0)
! 247: {
! 248: fprintf (stderr, "error: %s%s\n", error, newline);
! 249: fprintf (stderr, " %s%s\n", argv[i], newline);
! 250: if (! flag_html)
! 251: {
! 252: /* ??? Dunno how to align expression position with arrow in
! 253: HTML ??? */
! 254: fprintf (stderr, " ");
! 255: for (s = jmpval - (long) argv[i]; --s >= 0; )
! 256: putc (' ', stderr);
! 257: fprintf (stderr, "^\n");
! 258: }
! 259:
! 260: errcode |= 1;
! 261: continue;
! 262: }
! 263:
! 264: str = expr (argv[i], &e);
! 265:
! 266: if (str[0] != 0)
! 267: {
! 268: fprintf (stderr,
! 269: "error: garbage where end of expression expected%s\n",
! 270: newline);
! 271: fprintf (stderr, " %s%s\n", argv[i], newline);
! 272: if (! flag_html)
! 273: {
! 274: /* ??? Dunno how to align expression position with arrow in
! 275: HTML ??? */
! 276: fprintf (stderr, " ");
! 277: for (s = str - argv[i]; --s; )
! 278: putc (' ', stderr);
! 279: fprintf (stderr, "^\n");
! 280: }
! 281:
! 282: errcode |= 1;
! 283: free_expr (e);
! 284: continue;
! 285: }
! 286:
! 287: /* Set up error handler for evaluating expression. */
! 288: if (setjmp (errjmpbuf))
! 289: {
! 290: fprintf (stderr, "error: %s%s\n", error, newline);
! 291: fprintf (stderr, " %s%s\n", argv[i], newline);
! 292: if (! flag_html)
! 293: {
! 294: /* ??? Dunno how to align expression position with arrow in
! 295: HTML ??? */
! 296: fprintf (stderr, " ");
! 297: for (s = str - argv[i]; --s >= 0; )
! 298: putc (' ', stderr);
! 299: fprintf (stderr, "^\n");
! 300: }
! 301:
! 302: errcode |= 2;
! 303: continue;
! 304: }
! 305:
! 306: {
! 307: int t0;
! 308:
! 309: if (print_timing)
! 310: t0 = cputime ();
! 311:
! 312: mpz_eval_expr (r, e);
! 313:
! 314: if (print_timing)
! 315: printf ("computation took %d ms%s\n", cputime () - t0, newline);
! 316: }
! 317:
! 318: if (flag_print)
! 319: {
! 320: size_t out_len;
! 321: char *tmp, *s;
! 322: int t0;
! 323:
! 324: out_len = mpz_sizeinbase (r, base) + 1;
! 325: tmp = malloc (out_len);
! 326:
! 327: if (print_timing)
! 328: t0 = cputime ();
! 329:
! 330: if (print_timing)
! 331: /* Print first half of message... */
! 332: printf ("output conversion ");
! 333:
! 334: mpz_get_str (tmp, -base, r);
! 335:
! 336: if (print_timing)
! 337: /* ...print 2nd half of message unless we caught a time limit
! 338: and therefore longjmp'ed */
! 339: printf ("took %d ms%s\n", cputime () - t0, newline);
! 340:
! 341: out_len = strlen (tmp);
! 342: if (flag_splitup_output)
! 343: {
! 344: for (s = tmp; out_len > 60; s += 60)
! 345: {
! 346: fwrite (s, 1, 60, stdout);
! 347: printf ("%s\n", newline);
! 348: out_len -= 60;
! 349: }
! 350:
! 351: fwrite (s, 1, out_len, stdout);
! 352: }
! 353: else
! 354: {
! 355: fwrite (tmp, 1, out_len, stdout);
! 356: }
! 357:
! 358: free (tmp);
! 359: printf ("%s\n", newline);
! 360: }
! 361: else
! 362: {
! 363: printf ("result is approximately %ld digits%s\n",
! 364: (long) mpz_sizeinbase (r, 10), newline);
! 365: }
! 366:
! 367: free_expr (e);
! 368: }
! 369:
! 370: exit (errcode);
! 371: }
! 372:
! 373: char *
! 374: expr (char *str, expr_t *e)
! 375: {
! 376: expr_t e2;
! 377:
! 378: str = skipspace (str);
! 379: if (str[0] == '+')
! 380: {
! 381: str = term (str + 1, e);
! 382: }
! 383: else if (str[0] == '-')
! 384: {
! 385: str = term (str + 1, e);
! 386: makeexp (e, NEG, *e, NULL);
! 387: }
! 388: else if (str[0] == '~')
! 389: {
! 390: str = term (str + 1, e);
! 391: makeexp (e, NOT, *e, NULL);
! 392: }
! 393: else
! 394: {
! 395: str = term (str, e);
! 396: }
! 397:
! 398: for (;;)
! 399: {
! 400: str = skipspace (str);
! 401: switch (str[0])
! 402: {
! 403: case 'p':
! 404: if (match ("plus", str))
! 405: {
! 406: str = term (str + 4, &e2);
! 407: makeexp (e, PLUS, *e, e2);
! 408: }
! 409: else
! 410: return str;
! 411: break;
! 412: case 'm':
! 413: if (match ("minus", str))
! 414: {
! 415: str = term (str + 5, &e2);
! 416: makeexp (e, MINUS, *e, e2);
! 417: }
! 418: else
! 419: return str;
! 420: break;
! 421: case '+':
! 422: str = term (str + 1, &e2);
! 423: makeexp (e, PLUS, *e, e2);
! 424: break;
! 425: case '-':
! 426: str = term (str + 1, &e2);
! 427: makeexp (e, MINUS, *e, e2);
! 428: break;
! 429: default:
! 430: return str;
! 431: }
! 432: }
! 433: }
! 434:
! 435: char *
! 436: term (char *str, expr_t *e)
! 437: {
! 438: expr_t e2;
! 439:
! 440: str = power (str, e);
! 441: for (;;)
! 442: {
! 443: str = skipspace (str);
! 444: switch (str[0])
! 445: {
! 446: case 'm':
! 447: if (match ("mul", str))
! 448: {
! 449: str = power (str + 3, &e2);
! 450: makeexp (e, MULT, *e, e2);
! 451: break;
! 452: }
! 453: if (match ("mod", str))
! 454: {
! 455: str = power (str + 3, &e2);
! 456: makeexp (e, MOD, *e, e2);
! 457: break;
! 458: }
! 459: return str;
! 460: case 'd':
! 461: if (match ("div", str))
! 462: {
! 463: str = power (str + 3, &e2);
! 464: makeexp (e, DIV, *e, e2);
! 465: break;
! 466: }
! 467: return str;
! 468: case 'r':
! 469: if (match ("rem", str))
! 470: {
! 471: str = power (str + 3, &e2);
! 472: makeexp (e, REM, *e, e2);
! 473: break;
! 474: }
! 475: return str;
! 476: case 'i':
! 477: if (match ("invmod", str))
! 478: {
! 479: str = power (str + 6, &e2);
! 480: makeexp (e, REM, *e, e2);
! 481: break;
! 482: }
! 483: return str;
! 484: case 't':
! 485: if (match ("times", str))
! 486: {
! 487: str = power (str + 5, &e2);
! 488: makeexp (e, MULT, *e, e2);
! 489: break;
! 490: }
! 491: if (match ("thru", str))
! 492: {
! 493: str = power (str + 4, &e2);
! 494: makeexp (e, DIV, *e, e2);
! 495: break;
! 496: }
! 497: if (match ("through", str))
! 498: {
! 499: str = power (str + 7, &e2);
! 500: makeexp (e, DIV, *e, e2);
! 501: break;
! 502: }
! 503: return str;
! 504: case '*':
! 505: str = power (str + 1, &e2);
! 506: makeexp (e, MULT, *e, e2);
! 507: break;
! 508: case '/':
! 509: str = power (str + 1, &e2);
! 510: makeexp (e, DIV, *e, e2);
! 511: break;
! 512: case '%':
! 513: str = power (str + 1, &e2);
! 514: makeexp (e, MOD, *e, e2);
! 515: break;
! 516: default:
! 517: return str;
! 518: }
! 519: }
! 520: }
! 521:
! 522: char *
! 523: power (char *str, expr_t *e)
! 524: {
! 525: expr_t e2;
! 526:
! 527: str = factor (str, e);
! 528: while (str[0] == '!')
! 529: {
! 530: str++;
! 531: makeexp (e, FAC, *e, NULL);
! 532: }
! 533: str = skipspace (str);
! 534: if (str[0] == '^')
! 535: {
! 536: str = power (str + 1, &e2);
! 537: makeexp (e, POW, *e, e2);
! 538: }
! 539: return str;
! 540: }
! 541:
! 542: int
! 543: match (char *s, char *str)
! 544: {
! 545: char *ostr = str;
! 546: int i;
! 547:
! 548: for (i = 0; s[i] != 0; i++)
! 549: {
! 550: if (str[i] != s[i])
! 551: return 0;
! 552: }
! 553: str = skipspace (str + i);
! 554: return str - ostr;
! 555: }
! 556:
! 557: int
! 558: matchp (char *s, char *str)
! 559: {
! 560: char *ostr = str;
! 561: int i;
! 562:
! 563: for (i = 0; s[i] != 0; i++)
! 564: {
! 565: if (str[i] != s[i])
! 566: return 0;
! 567: }
! 568: str = skipspace (str + i);
! 569: if (str[0] == '(')
! 570: return str - ostr + 1;
! 571: return 0;
! 572: }
! 573:
! 574: struct functions
! 575: {
! 576: char *spelling;
! 577: enum op_t op;
! 578: int arity; /* 1 or 2 means real arity; 0 means arbitrary. */
! 579: };
! 580:
! 581: struct functions fns[] =
! 582: {
! 583: {"sqrt", SQRT, 1},
! 584: #if __GNU_MP_VERSION >= 2
! 585: {"root", ROOT, 2},
! 586: {"popc", POPCNT, 1},
! 587: #endif
! 588: {"gcd", GCD, 0},
! 589: #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
! 590: {"lcm", LCM, 0},
! 591: #endif
! 592: {"and", AND, 0},
! 593: {"ior", IOR, 0},
! 594: #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
! 595: {"xor", XOR, 0},
! 596: #endif
! 597: {"plus", PLUS, 0},
! 598: {"minus", MINUS, 2},
! 599: {"mul", MULT, 0},
! 600: {"div", DIV, 2},
! 601: {"mod", MOD, 2},
! 602: {"rem", REM, 2},
! 603: #if __GNU_MP_VERSION >= 2
! 604: {"invmod", INVMOD, 2},
! 605: #endif
! 606: {"log", LOG, 2},
! 607: {"log2", LOG2, 1},
! 608: {"F", FERMAT, 1},
! 609: {"M", MERSENNE, 1},
! 610: {"fib", FIBONACCI, 1},
! 611: {"Fib", FIBONACCI, 1},
! 612: {"", NOP, 0}
! 613: };
! 614:
! 615: char *
! 616: factor (char *str, expr_t *e)
! 617: {
! 618: expr_t e1, e2;
! 619:
! 620: str = skipspace (str);
! 621:
! 622: if (isalpha (str[0]))
! 623: {
! 624: int i;
! 625: int cnt;
! 626:
! 627: for (i = 0; fns[i].op != NOP; i++)
! 628: {
! 629: if (fns[i].arity == 1)
! 630: {
! 631: cnt = matchp (fns[i].spelling, str);
! 632: if (cnt != 0)
! 633: {
! 634: str = expr (str + cnt, &e1);
! 635: str = skipspace (str);
! 636: if (str[0] != ')')
! 637: {
! 638: error = "expected `)'";
! 639: longjmp (errjmpbuf, (int) (long) str);
! 640: }
! 641: makeexp (e, fns[i].op, e1, NULL);
! 642: return str + 1;
! 643: }
! 644: }
! 645: }
! 646:
! 647: for (i = 0; fns[i].op != NOP; i++)
! 648: {
! 649: if (fns[i].arity != 1)
! 650: {
! 651: cnt = matchp (fns[i].spelling, str);
! 652: if (cnt != 0)
! 653: {
! 654: str = expr (str + cnt, &e1);
! 655: str = skipspace (str);
! 656:
! 657: if (str[0] != ',')
! 658: {
! 659: error = "expected `,' and another operand";
! 660: longjmp (errjmpbuf, (int) (long) str);
! 661: }
! 662:
! 663: str = skipspace (str + 1);
! 664: str = expr (str, &e2);
! 665: str = skipspace (str);
! 666:
! 667: if (fns[i].arity == 0)
! 668: {
! 669: while (str[0] == ',')
! 670: {
! 671: makeexp (&e1, fns[i].op, e1, e2);
! 672: str = skipspace (str + 1);
! 673: str = expr (str, &e2);
! 674: str = skipspace (str);
! 675: }
! 676: }
! 677:
! 678: if (str[0] != ')')
! 679: {
! 680: error = "expected `)'";
! 681: longjmp (errjmpbuf, (int) (long) str);
! 682: }
! 683:
! 684: makeexp (e, fns[i].op, e1, e2);
! 685: return str + 1;
! 686: }
! 687: }
! 688: }
! 689: }
! 690:
! 691: if (str[0] == '(')
! 692: {
! 693: str = expr (str + 1, e);
! 694: str = skipspace (str);
! 695: if (str[0] != ')')
! 696: {
! 697: error = "expected `)'";
! 698: longjmp (errjmpbuf, (int) (long) str);
! 699: }
! 700: str++;
! 701: }
! 702: else if (str[0] >= '0' && str[0] <= '9')
! 703: {
! 704: expr_t res;
! 705: char *s, *sc;
! 706:
! 707: res = malloc (sizeof (struct expr));
! 708: res -> op = LIT;
! 709: mpz_init (res->operands.val);
! 710:
! 711: s = str;
! 712: while (isalnum (str[0]))
! 713: str++;
! 714: sc = malloc (str - s + 1);
! 715: memcpy (sc, s, str - s);
! 716: sc[str - s] = 0;
! 717:
! 718: mpz_set_str (res->operands.val, sc, 0);
! 719: *e = res;
! 720: free (sc);
! 721: }
! 722: else
! 723: {
! 724: error = "operand expected";
! 725: longjmp (errjmpbuf, (int) (long) str);
! 726: }
! 727: return str;
! 728: }
! 729:
! 730: char *
! 731: skipspace (char *str)
! 732: {
! 733: while (str[0] == ' ')
! 734: str++;
! 735: return str;
! 736: }
! 737:
! 738: /* Make a new expression with operation OP and right hand side
! 739: RHS and left hand side lhs. Put the result in R. */
! 740: void
! 741: makeexp (expr_t *r, enum op_t op, expr_t lhs, expr_t rhs)
! 742: {
! 743: expr_t res;
! 744: res = malloc (sizeof (struct expr));
! 745: res -> op = op;
! 746: res -> operands.ops.lhs = lhs;
! 747: res -> operands.ops.rhs = rhs;
! 748: *r = res;
! 749: return;
! 750: }
! 751:
! 752: /* Free the memory used by expression E. */
! 753: void
! 754: free_expr (expr_t e)
! 755: {
! 756: if (e->op != LIT)
! 757: {
! 758: free_expr (e->operands.ops.lhs);
! 759: if (e->operands.ops.rhs != NULL)
! 760: free_expr (e->operands.ops.rhs);
! 761: }
! 762: else
! 763: {
! 764: mpz_clear (e->operands.val);
! 765: }
! 766: }
! 767:
! 768: /* Evaluate the expression E and put the result in R. */
! 769: void
! 770: mpz_eval_expr (mpz_ptr r, expr_t e)
! 771: {
! 772: mpz_t lhs, rhs;
! 773:
! 774: switch (e->op)
! 775: {
! 776: case LIT:
! 777: mpz_set (r, e->operands.val);
! 778: return;
! 779: case PLUS:
! 780: mpz_init (lhs); mpz_init (rhs);
! 781: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 782: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 783: mpz_add (r, lhs, rhs);
! 784: mpz_clear (lhs); mpz_clear (rhs);
! 785: return;
! 786: case MINUS:
! 787: mpz_init (lhs); mpz_init (rhs);
! 788: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 789: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 790: mpz_sub (r, lhs, rhs);
! 791: mpz_clear (lhs); mpz_clear (rhs);
! 792: return;
! 793: case MULT:
! 794: mpz_init (lhs); mpz_init (rhs);
! 795: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 796: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 797: mpz_mul (r, lhs, rhs);
! 798: mpz_clear (lhs); mpz_clear (rhs);
! 799: return;
! 800: case DIV:
! 801: mpz_init (lhs); mpz_init (rhs);
! 802: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 803: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 804: mpz_fdiv_q (r, lhs, rhs);
! 805: mpz_clear (lhs); mpz_clear (rhs);
! 806: return;
! 807: case MOD:
! 808: mpz_init (rhs);
! 809: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 810: mpz_abs (rhs, rhs);
! 811: mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs);
! 812: mpz_clear (rhs);
! 813: return;
! 814: case REM:
! 815: /* Check if lhs operand is POW expression and optimize for that case. */
! 816: if (e->operands.ops.lhs->op == POW)
! 817: {
! 818: mpz_t powlhs, powrhs;
! 819: mpz_init (powlhs);
! 820: mpz_init (powrhs);
! 821: mpz_init (rhs);
! 822: mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs);
! 823: mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs);
! 824: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 825: mpz_powm (r, powlhs, powrhs, rhs);
! 826: if (mpz_cmp_si (rhs, 0L) < 0)
! 827: mpz_neg (r, r);
! 828: mpz_clear (powlhs);
! 829: mpz_clear (powrhs);
! 830: mpz_clear (rhs);
! 831: return;
! 832: }
! 833:
! 834: mpz_init (lhs); mpz_init (rhs);
! 835: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 836: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 837: mpz_fdiv_r (r, lhs, rhs);
! 838: mpz_clear (lhs); mpz_clear (rhs);
! 839: return;
! 840: #if __GNU_MP_VERSION >= 2
! 841: case INVMOD:
! 842: mpz_init (lhs); mpz_init (rhs);
! 843: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 844: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 845: mpz_invert (r, lhs, rhs);
! 846: mpz_clear (lhs); mpz_clear (rhs);
! 847: return;
! 848: #endif
! 849: case POW:
! 850: mpz_init (lhs); mpz_init (rhs);
! 851: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 852: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 853: if (mpz_cmp_si (rhs, 0L) == 0)
! 854: /* x^0 is 1 */
! 855: mpz_set_ui (r, 1L);
! 856: else if (mpz_cmp_si (lhs, 0L) == 0)
! 857: /* 0^y (where y != 0) is 0 */
! 858: mpz_set_ui (r, 0L);
! 859: else if (mpz_cmp_ui (lhs, 1L) == 0)
! 860: /* 1^y is 1 */
! 861: mpz_set_ui (r, 1L);
! 862: else if (mpz_cmp_si (lhs, -1L) == 0)
! 863: /* (-1)^y just depends on whether y is even or odd */
! 864: mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L);
! 865: else if (mpz_cmp_si (rhs, 0L) < 0)
! 866: /* x^(-n) is 0 */
! 867: mpz_set_ui (r, 0L);
! 868: else
! 869: {
! 870: unsigned long int cnt;
! 871: unsigned long int y;
! 872: /* error if exponent does not fit into an unsigned long int. */
! 873: if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
! 874: goto pow_err;
! 875:
! 876: y = mpz_get_ui (rhs);
! 877: /* x^y == (x/(2^c))^y * 2^(c*y) */
! 878: #if __GNU_MP_VERSION >= 2
! 879: cnt = mpz_scan1 (lhs, 0);
! 880: #else
! 881: cnt = 0;
! 882: #endif
! 883: if (cnt != 0)
! 884: {
! 885: if (y * cnt / cnt != y)
! 886: goto pow_err;
! 887: mpz_tdiv_q_2exp (lhs, lhs, cnt);
! 888: mpz_pow_ui (r, lhs, y);
! 889: mpz_mul_2exp (r, r, y * cnt);
! 890: }
! 891: else
! 892: mpz_pow_ui (r, lhs, y);
! 893: }
! 894: mpz_clear (lhs); mpz_clear (rhs);
! 895: return;
! 896: pow_err:
! 897: error = "result of `pow' operator too large";
! 898: mpz_clear (lhs); mpz_clear (rhs);
! 899: longjmp (errjmpbuf, 1);
! 900: case GCD:
! 901: mpz_init (lhs); mpz_init (rhs);
! 902: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 903: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 904: mpz_gcd (r, lhs, rhs);
! 905: mpz_clear (lhs); mpz_clear (rhs);
! 906: return;
! 907: #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
! 908: case LCM:
! 909: mpz_init (lhs); mpz_init (rhs);
! 910: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 911: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 912: mpz_lcm (r, lhs, rhs);
! 913: mpz_clear (lhs); mpz_clear (rhs);
! 914: return;
! 915: #endif
! 916: case AND:
! 917: mpz_init (lhs); mpz_init (rhs);
! 918: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 919: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 920: mpz_and (r, lhs, rhs);
! 921: mpz_clear (lhs); mpz_clear (rhs);
! 922: return;
! 923: case IOR:
! 924: mpz_init (lhs); mpz_init (rhs);
! 925: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 926: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 927: mpz_ior (r, lhs, rhs);
! 928: mpz_clear (lhs); mpz_clear (rhs);
! 929: return;
! 930: #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
! 931: case XOR:
! 932: mpz_init (lhs); mpz_init (rhs);
! 933: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 934: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 935: mpz_xor (r, lhs, rhs);
! 936: mpz_clear (lhs); mpz_clear (rhs);
! 937: return;
! 938: #endif
! 939: case NEG:
! 940: mpz_eval_expr (r, e->operands.ops.lhs);
! 941: mpz_neg (r, r);
! 942: return;
! 943: case NOT:
! 944: mpz_eval_expr (r, e->operands.ops.lhs);
! 945: mpz_com (r, r);
! 946: return;
! 947: case SQRT:
! 948: mpz_init (lhs);
! 949: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 950: if (mpz_sgn (lhs) < 0)
! 951: {
! 952: error = "cannot take square root of negative numbers";
! 953: mpz_clear (lhs);
! 954: longjmp (errjmpbuf, 1);
! 955: }
! 956: mpz_sqrt (r, lhs);
! 957: return;
! 958: #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
! 959: case ROOT:
! 960: mpz_init (lhs); mpz_init (rhs);
! 961: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 962: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 963: if (mpz_sgn (rhs) <= 0)
! 964: {
! 965: error = "cannot take non-positive root orders";
! 966: mpz_clear (lhs); mpz_clear (rhs);
! 967: longjmp (errjmpbuf, 1);
! 968: }
! 969: if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0)
! 970: {
! 971: error = "cannot take even root orders of negative numbers";
! 972: mpz_clear (lhs); mpz_clear (rhs);
! 973: longjmp (errjmpbuf, 1);
! 974: }
! 975:
! 976: {
! 977: unsigned long int nth = mpz_get_ui (rhs);
! 978: if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
! 979: {
! 980: /* If we are asked to take an awfully large root order, cheat and
! 981: ask for the largest order we can pass to mpz_root. This saves
! 982: some error prone special cases. */
! 983: nth = ~(unsigned long int) 0;
! 984: }
! 985: mpz_root (r, lhs, nth);
! 986: }
! 987: mpz_clear (lhs); mpz_clear (rhs);
! 988: return;
! 989: #endif
! 990: case FAC:
! 991: mpz_eval_expr (r, e->operands.ops.lhs);
! 992: if (mpz_size (r) > 1)
! 993: {
! 994: error = "result of `!' operator too large";
! 995: longjmp (errjmpbuf, 1);
! 996: }
! 997: mpz_fac_ui (r, mpz_get_ui (r));
! 998: return;
! 999: #if __GNU_MP_VERSION >= 2
! 1000: case POPCNT:
! 1001: mpz_eval_expr (r, e->operands.ops.lhs);
! 1002: { unsigned long int cnt;
! 1003: cnt = mpz_popcount (r);
! 1004: mpz_set_ui (r, cnt);
! 1005: }
! 1006: return;
! 1007: #endif
! 1008: case LOG2:
! 1009: mpz_eval_expr (r, e->operands.ops.lhs);
! 1010: { unsigned long int cnt;
! 1011: if (mpz_sgn (r) <= 0)
! 1012: {
! 1013: error = "logarithm of non-positive number";
! 1014: longjmp (errjmpbuf, 1);
! 1015: }
! 1016: cnt = mpz_sizeinbase (r, 2);
! 1017: mpz_set_ui (r, cnt - 1);
! 1018: }
! 1019: return;
! 1020: case LOG:
! 1021: { unsigned long int cnt;
! 1022: mpz_init (lhs); mpz_init (rhs);
! 1023: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 1024: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 1025: if (mpz_sgn (lhs) <= 0)
! 1026: {
! 1027: error = "logarithm of non-positive number";
! 1028: mpz_clear (lhs); mpz_clear (rhs);
! 1029: longjmp (errjmpbuf, 1);
! 1030: }
! 1031: if (mpz_cmp_ui (rhs, 256) >= 0)
! 1032: {
! 1033: error = "logarithm base too large";
! 1034: mpz_clear (lhs); mpz_clear (rhs);
! 1035: longjmp (errjmpbuf, 1);
! 1036: }
! 1037: cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs));
! 1038: mpz_set_ui (r, cnt - 1);
! 1039: mpz_clear (lhs); mpz_clear (rhs);
! 1040: }
! 1041: return;
! 1042: case FERMAT:
! 1043: {
! 1044: unsigned long int t;
! 1045: mpz_init (lhs);
! 1046: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 1047: t = (unsigned long int) 1 << mpz_get_ui (lhs);
! 1048: if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0)
! 1049: {
! 1050: error = "too large Mersenne number index";
! 1051: mpz_clear (lhs);
! 1052: longjmp (errjmpbuf, 1);
! 1053: }
! 1054: mpz_set_ui (r, 1);
! 1055: mpz_mul_2exp (r, r, t);
! 1056: mpz_add_ui (r, r, 1);
! 1057: mpz_clear (lhs);
! 1058: }
! 1059: return;
! 1060: case MERSENNE:
! 1061: mpz_init (lhs);
! 1062: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 1063: if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0)
! 1064: {
! 1065: error = "too large Mersenne number index";
! 1066: mpz_clear (lhs);
! 1067: longjmp (errjmpbuf, 1);
! 1068: }
! 1069: mpz_set_ui (r, 1);
! 1070: mpz_mul_2exp (r, r, mpz_get_ui (lhs));
! 1071: mpz_sub_ui (r, r, 1);
! 1072: mpz_clear (lhs);
! 1073: return;
! 1074: case FIBONACCI:
! 1075: { mpz_t t;
! 1076: unsigned long int n, i;
! 1077: mpz_init (lhs);
! 1078: mpz_eval_expr (lhs, e->operands.ops.lhs);
! 1079: if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
! 1080: {
! 1081: error = "Fibonacci index out of range";
! 1082: mpz_clear (lhs);
! 1083: longjmp (errjmpbuf, 1);
! 1084: }
! 1085: n = mpz_get_ui (lhs);
! 1086: mpz_clear (lhs);
! 1087:
! 1088: #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
! 1089: mpz_fib_ui (r, n);
! 1090: #else
! 1091: mpz_init_set_ui (t, 1);
! 1092: mpz_set_ui (r, 1);
! 1093:
! 1094: if (n <= 2)
! 1095: mpz_set_ui (r, 1);
! 1096: else
! 1097: {
! 1098: for (i = 3; i <= n; i++)
! 1099: {
! 1100: mpz_add (t, t, r);
! 1101: mpz_swap (t, r);
! 1102: }
! 1103: }
! 1104: mpz_clear (t);
! 1105: #endif
! 1106: }
! 1107: return;
! 1108: default:
! 1109: abort ();
! 1110: }
! 1111: }
! 1112:
! 1113: /* Evaluate the expression E modulo MOD and put the result in R. */
! 1114: void
! 1115: mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod)
! 1116: {
! 1117: mpz_t lhs, rhs;
! 1118:
! 1119: switch (e->op)
! 1120: {
! 1121: case POW:
! 1122: mpz_init (lhs); mpz_init (rhs);
! 1123: mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
! 1124: mpz_eval_expr (rhs, e->operands.ops.rhs);
! 1125: mpz_powm (r, lhs, rhs, mod);
! 1126: mpz_clear (lhs); mpz_clear (rhs);
! 1127: return;
! 1128: case PLUS:
! 1129: mpz_init (lhs); mpz_init (rhs);
! 1130: mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
! 1131: mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
! 1132: mpz_add (r, lhs, rhs);
! 1133: if (mpz_cmp_si (r, 0L) < 0)
! 1134: mpz_add (r, r, mod);
! 1135: else if (mpz_cmp (r, mod) >= 0)
! 1136: mpz_sub (r, r, mod);
! 1137: mpz_clear (lhs); mpz_clear (rhs);
! 1138: return;
! 1139: case MINUS:
! 1140: mpz_init (lhs); mpz_init (rhs);
! 1141: mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
! 1142: mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
! 1143: mpz_sub (r, lhs, rhs);
! 1144: if (mpz_cmp_si (r, 0L) < 0)
! 1145: mpz_add (r, r, mod);
! 1146: else if (mpz_cmp (r, mod) >= 0)
! 1147: mpz_sub (r, r, mod);
! 1148: mpz_clear (lhs); mpz_clear (rhs);
! 1149: return;
! 1150: case MULT:
! 1151: mpz_init (lhs); mpz_init (rhs);
! 1152: mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
! 1153: mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
! 1154: mpz_mul (r, lhs, rhs);
! 1155: mpz_mod (r, r, mod);
! 1156: mpz_clear (lhs); mpz_clear (rhs);
! 1157: return;
! 1158: default:
! 1159: mpz_init (lhs);
! 1160: mpz_eval_expr (lhs, e);
! 1161: mpz_mod (r, lhs, mod);
! 1162: mpz_clear (lhs);
! 1163: return;
! 1164: }
! 1165: }
! 1166:
! 1167: void
! 1168: cleanup_and_exit (int sig)
! 1169: {
! 1170: #ifdef LIMIT_RESOURCE_USAGE
! 1171: if (sig == SIGXCPU)
! 1172: printf ("expression took too long time to evaluate%s\n", newline);
! 1173: else if (sig == SIGFPE)
! 1174: printf ("divide by zero%s\n", newline);
! 1175: else
! 1176: #endif
! 1177: printf ("expression required too much memory to evaluate%s\n", newline);
! 1178: exit (-2);
! 1179: }
! 1180:
! 1181: /* Return user CPU time measured in milliseconds. */
! 1182:
! 1183: #if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
! 1184: #include <time.h>
! 1185:
! 1186: int
! 1187: cputime ()
! 1188: {
! 1189: if (CLOCKS_PER_SEC < 100000)
! 1190: return clock () * 1000 / CLOCKS_PER_SEC;
! 1191: return clock () / (CLOCKS_PER_SEC / 1000);
! 1192: }
! 1193: #else
! 1194: #include <sys/types.h>
! 1195: #include <sys/time.h>
! 1196: #include <sys/resource.h>
! 1197:
! 1198: int
! 1199: cputime ()
! 1200: {
! 1201: struct rusage rus;
! 1202:
! 1203: getrusage (0, &rus);
! 1204: return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
! 1205: }
! 1206: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>