[BACK]Return to pexpr.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / demos

Annotation of OpenXM_contrib/gmp/demos/pexpr.c, Revision 1.1.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>