|
Packit |
5c3484 |
/* Program for computing integer expressions using the GNU Multiple Precision
|
|
Packit |
5c3484 |
Arithmetic Library.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Copyright 1997, 1999-2002, 2005, 2008, 2012, 2015 Free Software Foundation, Inc.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
This program is free software; you can redistribute it and/or modify it under
|
|
Packit |
5c3484 |
the terms of the GNU General Public License as published by the Free Software
|
|
Packit |
5c3484 |
Foundation; either version 3 of the License, or (at your option) any later
|
|
Packit |
5c3484 |
version.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
Packit |
5c3484 |
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
Packit |
5c3484 |
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
You should have received a copy of the GNU General Public License along with
|
|
Packit |
5c3484 |
this program. If not, see https://www.gnu.org/licenses/. */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* This expressions evaluator works by building an expression tree (using a
|
|
Packit |
5c3484 |
recursive descent parser) which is then evaluated. The expression tree is
|
|
Packit |
5c3484 |
useful since we want to optimize certain expressions (like a^b % c).
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Usage: pexpr [options] expr ...
|
|
Packit |
5c3484 |
(Assuming you called the executable `pexpr' of course.)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Command line options:
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
-b print output in binary
|
|
Packit |
5c3484 |
-o print output in octal
|
|
Packit |
5c3484 |
-d print output in decimal (the default)
|
|
Packit |
5c3484 |
-x print output in hexadecimal
|
|
Packit |
5c3484 |
-b<NUM> print output in base NUM
|
|
Packit |
5c3484 |
-t print timing information
|
|
Packit |
5c3484 |
-html output html
|
|
Packit |
5c3484 |
-wml output wml
|
|
Packit |
5c3484 |
-split split long lines each 80th digit
|
|
Packit |
5c3484 |
*/
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Define LIMIT_RESOURCE_USAGE if you want to make sure the program doesn't
|
|
Packit |
5c3484 |
use up extensive resources (cpu, memory). Useful for the GMP demo on the
|
|
Packit |
5c3484 |
GMP web site, since we cannot load the server too much. */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#include "pexpr-config.h"
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#include <string.h>
|
|
Packit |
5c3484 |
#include <stdio.h>
|
|
Packit |
5c3484 |
#include <stdlib.h>
|
|
Packit |
5c3484 |
#include <setjmp.h>
|
|
Packit |
5c3484 |
#include <signal.h>
|
|
Packit |
5c3484 |
#include <ctype.h>
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#include <time.h>
|
|
Packit |
5c3484 |
#include <sys/types.h>
|
|
Packit |
5c3484 |
#include <sys/time.h>
|
|
Packit |
5c3484 |
#if HAVE_SYS_RESOURCE_H
|
|
Packit |
5c3484 |
#include <sys/resource.h>
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#include "gmp.h"
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* SunOS 4 and HPUX 9 don't define a canonical SIGSTKSZ, use a default. */
|
|
Packit |
5c3484 |
#ifndef SIGSTKSZ
|
|
Packit |
5c3484 |
#define SIGSTKSZ 4096
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#define TIME(t,func) \
|
|
Packit |
5c3484 |
do { int __t0, __tmp; \
|
|
Packit |
5c3484 |
__t0 = cputime (); \
|
|
Packit |
5c3484 |
{func;} \
|
|
Packit |
5c3484 |
__tmp = cputime () - __t0; \
|
|
Packit |
5c3484 |
(t) = __tmp; \
|
|
Packit |
5c3484 |
} while (0)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* GMP version 1.x compatibility. */
|
|
Packit |
5c3484 |
#if ! (__GNU_MP_VERSION >= 2)
|
|
Packit |
5c3484 |
typedef MP_INT __mpz_struct;
|
|
Packit |
5c3484 |
typedef __mpz_struct mpz_t[1];
|
|
Packit |
5c3484 |
typedef __mpz_struct *mpz_ptr;
|
|
Packit |
5c3484 |
#define mpz_fdiv_q mpz_div
|
|
Packit |
5c3484 |
#define mpz_fdiv_r mpz_mod
|
|
Packit |
5c3484 |
#define mpz_tdiv_q_2exp mpz_div_2exp
|
|
Packit |
5c3484 |
#define mpz_sgn(Z) ((Z)->size < 0 ? -1 : (Z)->size > 0)
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* GMP version 2.0 compatibility. */
|
|
Packit |
5c3484 |
#if ! (__GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1)
|
|
Packit |
5c3484 |
#define mpz_swap(a,b) \
|
|
Packit |
5c3484 |
do { __mpz_struct __t; __t = *a; *a = *b; *b = __t;} while (0)
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
jmp_buf errjmpbuf;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW,
|
|
Packit |
5c3484 |
AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC,
|
|
Packit |
5c3484 |
LOG, LOG2, FERMAT, MERSENNE, FIBONACCI, RANDOM, NEXTPRIME, BINOM,
|
|
Packit |
5c3484 |
TIMING};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Type for the expression tree. */
|
|
Packit |
5c3484 |
struct expr
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
enum op_t op;
|
|
Packit |
5c3484 |
union
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
struct {struct expr *lhs, *rhs;} ops;
|
|
Packit |
5c3484 |
mpz_t val;
|
|
Packit |
5c3484 |
} operands;
|
|
Packit |
5c3484 |
};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
typedef struct expr *expr_t;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
void cleanup_and_exit (int);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
char *skipspace (char *);
|
|
Packit |
5c3484 |
void makeexp (expr_t *, enum op_t, expr_t, expr_t);
|
|
Packit |
5c3484 |
void free_expr (expr_t);
|
|
Packit |
5c3484 |
char *expr (char *, expr_t *);
|
|
Packit |
5c3484 |
char *term (char *, expr_t *);
|
|
Packit |
5c3484 |
char *power (char *, expr_t *);
|
|
Packit |
5c3484 |
char *factor (char *, expr_t *);
|
|
Packit |
5c3484 |
int match (char *, char *);
|
|
Packit |
5c3484 |
int matchp (char *, char *);
|
|
Packit |
5c3484 |
int cputime (void);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
void mpz_eval_expr (mpz_ptr, expr_t);
|
|
Packit |
5c3484 |
void mpz_eval_mod_expr (mpz_ptr, expr_t, mpz_ptr);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
char *error;
|
|
Packit |
5c3484 |
int flag_print = 1;
|
|
Packit |
5c3484 |
int print_timing = 0;
|
|
Packit |
5c3484 |
int flag_html = 0;
|
|
Packit |
5c3484 |
int flag_wml = 0;
|
|
Packit |
5c3484 |
int flag_splitup_output = 0;
|
|
Packit |
5c3484 |
char *newline = "";
|
|
Packit |
5c3484 |
gmp_randstate_t rstate;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* cputime() returns user CPU time measured in milliseconds. */
|
|
Packit |
5c3484 |
#if ! HAVE_CPUTIME
|
|
Packit |
5c3484 |
#if HAVE_GETRUSAGE
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
cputime (void)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
struct rusage rus;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
getrusage (0, &rus;;
|
|
Packit |
5c3484 |
return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
#if HAVE_CLOCK
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
cputime (void)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (CLOCKS_PER_SEC < 100000)
|
|
Packit |
5c3484 |
return clock () * 1000 / CLOCKS_PER_SEC;
|
|
Packit |
5c3484 |
return clock () / (CLOCKS_PER_SEC / 1000);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
cputime (void)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
return 0;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
stack_downwards_helper (char *xp)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
char y;
|
|
Packit |
5c3484 |
return &y < xp;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
stack_downwards_p (void)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
char x;
|
|
Packit |
5c3484 |
return stack_downwards_helper (&x);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
void
|
|
Packit |
5c3484 |
setup_error_handler (void)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
#if HAVE_SIGACTION
|
|
Packit |
5c3484 |
struct sigaction act;
|
|
Packit |
5c3484 |
act.sa_handler = cleanup_and_exit;
|
|
Packit |
5c3484 |
sigemptyset (&(act.sa_mask));
|
|
Packit |
5c3484 |
#define SIGNAL(sig) sigaction (sig, &act, NULL)
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
struct { int sa_flags; } act;
|
|
Packit |
5c3484 |
#define SIGNAL(sig) signal (sig, cleanup_and_exit)
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
act.sa_flags = 0;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Set up a stack for signal handling. A typical cause of error is stack
|
|
Packit |
5c3484 |
overflow, and in such situation a signal can not be delivered on the
|
|
Packit |
5c3484 |
overflown stack. */
|
|
Packit |
5c3484 |
#if HAVE_SIGALTSTACK
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* AIX uses stack_t, MacOS uses struct sigaltstack, various other
|
|
Packit |
5c3484 |
systems have both. */
|
|
Packit |
5c3484 |
#if HAVE_STACK_T
|
|
Packit |
5c3484 |
stack_t s;
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
struct sigaltstack s;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
s.ss_sp = malloc (SIGSTKSZ);
|
|
Packit |
5c3484 |
s.ss_size = SIGSTKSZ;
|
|
Packit |
5c3484 |
s.ss_flags = 0;
|
|
Packit |
5c3484 |
if (sigaltstack (&s, NULL) != 0)
|
|
Packit |
5c3484 |
perror("sigaltstack");
|
|
Packit |
5c3484 |
act.sa_flags = SA_ONSTACK;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
#if HAVE_SIGSTACK
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
struct sigstack s;
|
|
Packit |
5c3484 |
s.ss_sp = malloc (SIGSTKSZ);
|
|
Packit |
5c3484 |
if (stack_downwards_p ())
|
|
Packit |
5c3484 |
s.ss_sp += SIGSTKSZ;
|
|
Packit |
5c3484 |
s.ss_onstack = 0;
|
|
Packit |
5c3484 |
if (sigstack (&s, NULL) != 0)
|
|
Packit |
5c3484 |
perror("sigstack");
|
|
Packit |
5c3484 |
act.sa_flags = SA_ONSTACK;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#ifdef LIMIT_RESOURCE_USAGE
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
struct rlimit limit;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
limit.rlim_cur = limit.rlim_max = 0;
|
|
Packit |
5c3484 |
setrlimit (RLIMIT_CORE, &limit);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
limit.rlim_cur = 3;
|
|
Packit |
5c3484 |
limit.rlim_max = 4;
|
|
Packit |
5c3484 |
setrlimit (RLIMIT_CPU, &limit);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024;
|
|
Packit |
5c3484 |
setrlimit (RLIMIT_DATA, &limit);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
getrlimit (RLIMIT_STACK, &limit);
|
|
Packit |
5c3484 |
limit.rlim_cur = 4 * 1024 * 1024;
|
|
Packit |
5c3484 |
setrlimit (RLIMIT_STACK, &limit);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
SIGNAL (SIGXCPU);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
#endif /* LIMIT_RESOURCE_USAGE */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
SIGNAL (SIGILL);
|
|
Packit |
5c3484 |
SIGNAL (SIGSEGV);
|
|
Packit |
5c3484 |
#ifdef SIGBUS /* not in mingw */
|
|
Packit |
5c3484 |
SIGNAL (SIGBUS);
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
SIGNAL (SIGFPE);
|
|
Packit |
5c3484 |
SIGNAL (SIGABRT);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
main (int argc, char **argv)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
struct expr *e;
|
|
Packit |
5c3484 |
int i;
|
|
Packit |
5c3484 |
mpz_t r;
|
|
Packit |
5c3484 |
int errcode = 0;
|
|
Packit |
5c3484 |
char *str;
|
|
Packit |
5c3484 |
int base = 10;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
setup_error_handler ();
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
gmp_randinit (rstate, GMP_RAND_ALG_LC, 128);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
#if HAVE_GETTIMEOFDAY
|
|
Packit |
5c3484 |
struct timeval tv;
|
|
Packit |
5c3484 |
gettimeofday (&tv, NULL);
|
|
Packit |
5c3484 |
gmp_randseed_ui (rstate, tv.tv_sec + tv.tv_usec);
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
time_t t;
|
|
Packit |
5c3484 |
time (&t);
|
|
Packit |
5c3484 |
gmp_randseed_ui (rstate, t);
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpz_init (r);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
while (argc > 1 && argv[1][0] == '-')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
char *arg = argv[1];
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (arg[1] >= '0' && arg[1] <= '9')
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (arg[1] == 't')
|
|
Packit |
5c3484 |
print_timing = 1;
|
|
Packit |
5c3484 |
else if (arg[1] == 'b' && arg[2] >= '0' && arg[2] <= '9')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
base = atoi (arg + 2);
|
|
Packit |
5c3484 |
if (base < 2 || base > 62)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
fprintf (stderr, "error: invalid output base\n");
|
|
Packit |
5c3484 |
exit (-1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (arg[1] == 'b' && arg[2] == 0)
|
|
Packit |
5c3484 |
base = 2;
|
|
Packit |
5c3484 |
else if (arg[1] == 'x' && arg[2] == 0)
|
|
Packit |
5c3484 |
base = 16;
|
|
Packit |
5c3484 |
else if (arg[1] == 'X' && arg[2] == 0)
|
|
Packit |
5c3484 |
base = -16;
|
|
Packit |
5c3484 |
else if (arg[1] == 'o' && arg[2] == 0)
|
|
Packit |
5c3484 |
base = 8;
|
|
Packit |
5c3484 |
else if (arg[1] == 'd' && arg[2] == 0)
|
|
Packit |
5c3484 |
base = 10;
|
|
Packit |
5c3484 |
else if (arg[1] == 'v' && arg[2] == 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
printf ("pexpr linked to gmp %s\n", __gmp_version);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (strcmp (arg, "-html") == 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
flag_html = 1;
|
|
Packit |
5c3484 |
newline = " ";
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (strcmp (arg, "-wml") == 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
flag_wml = 1;
|
|
Packit |
5c3484 |
newline = " ";
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (strcmp (arg, "-split") == 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
flag_splitup_output = 1;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (strcmp (arg, "-noprint") == 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
flag_print = 0;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
fprintf (stderr, "error: unknown option `%s'\n", arg);
|
|
Packit |
5c3484 |
exit (-1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
argv++;
|
|
Packit |
5c3484 |
argc--;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
for (i = 1; i < argc; i++)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int s;
|
|
Packit |
5c3484 |
int jmpval;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Set up error handler for parsing expression. */
|
|
Packit |
5c3484 |
jmpval = setjmp (errjmpbuf);
|
|
Packit |
5c3484 |
if (jmpval != 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
fprintf (stderr, "error: %s%s\n", error, newline);
|
|
Packit |
5c3484 |
fprintf (stderr, " %s%s\n", argv[i], newline);
|
|
Packit |
5c3484 |
if (! flag_html)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* ??? Dunno how to align expression position with arrow in
|
|
Packit |
5c3484 |
HTML ??? */
|
|
Packit |
5c3484 |
fprintf (stderr, " ");
|
|
Packit |
5c3484 |
for (s = jmpval - (long) argv[i]; --s >= 0; )
|
|
Packit |
5c3484 |
putc (' ', stderr);
|
|
Packit |
5c3484 |
fprintf (stderr, "^\n");
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
errcode |= 1;
|
|
Packit |
5c3484 |
continue;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
str = expr (argv[i], &e);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (str[0] != 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
fprintf (stderr,
|
|
Packit |
5c3484 |
"error: garbage where end of expression expected%s\n",
|
|
Packit |
5c3484 |
newline);
|
|
Packit |
5c3484 |
fprintf (stderr, " %s%s\n", argv[i], newline);
|
|
Packit |
5c3484 |
if (! flag_html)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* ??? Dunno how to align expression position with arrow in
|
|
Packit |
5c3484 |
HTML ??? */
|
|
Packit |
5c3484 |
fprintf (stderr, " ");
|
|
Packit |
5c3484 |
for (s = str - argv[i]; --s; )
|
|
Packit |
5c3484 |
putc (' ', stderr);
|
|
Packit |
5c3484 |
fprintf (stderr, "^\n");
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
errcode |= 1;
|
|
Packit |
5c3484 |
free_expr (e);
|
|
Packit |
5c3484 |
continue;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Set up error handler for evaluating expression. */
|
|
Packit |
5c3484 |
if (setjmp (errjmpbuf))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
fprintf (stderr, "error: %s%s\n", error, newline);
|
|
Packit |
5c3484 |
fprintf (stderr, " %s%s\n", argv[i], newline);
|
|
Packit |
5c3484 |
if (! flag_html)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* ??? Dunno how to align expression position with arrow in
|
|
Packit |
5c3484 |
HTML ??? */
|
|
Packit |
5c3484 |
fprintf (stderr, " ");
|
|
Packit |
5c3484 |
for (s = str - argv[i]; --s >= 0; )
|
|
Packit |
5c3484 |
putc (' ', stderr);
|
|
Packit |
5c3484 |
fprintf (stderr, "^\n");
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
errcode |= 2;
|
|
Packit |
5c3484 |
continue;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (print_timing)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int t;
|
|
Packit |
5c3484 |
TIME (t, mpz_eval_expr (r, e));
|
|
Packit |
5c3484 |
printf ("computation took %d ms%s\n", t, newline);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
mpz_eval_expr (r, e);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (flag_print)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
size_t out_len;
|
|
Packit |
5c3484 |
char *tmp, *s;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
out_len = mpz_sizeinbase (r, base >= 0 ? base : -base) + 2;
|
|
Packit |
5c3484 |
#ifdef LIMIT_RESOURCE_USAGE
|
|
Packit |
5c3484 |
if (out_len > 100000)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
printf ("result is about %ld digits, not printing it%s\n",
|
|
Packit |
5c3484 |
(long) out_len - 3, newline);
|
|
Packit |
5c3484 |
exit (-2);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
tmp = malloc (out_len);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (print_timing)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int t;
|
|
Packit |
5c3484 |
printf ("output conversion ");
|
|
Packit |
5c3484 |
TIME (t, mpz_get_str (tmp, base, r));
|
|
Packit |
5c3484 |
printf ("took %d ms%s\n", t, newline);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
mpz_get_str (tmp, base, r);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
out_len = strlen (tmp);
|
|
Packit |
5c3484 |
if (flag_splitup_output)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
for (s = tmp; out_len > 80; s += 80)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
fwrite (s, 1, 80, stdout);
|
|
Packit |
5c3484 |
printf ("%s\n", newline);
|
|
Packit |
5c3484 |
out_len -= 80;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
fwrite (s, 1, out_len, stdout);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
fwrite (tmp, 1, out_len, stdout);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
free (tmp);
|
|
Packit |
5c3484 |
printf ("%s\n", newline);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
printf ("result is approximately %ld digits%s\n",
|
|
Packit |
5c3484 |
(long) mpz_sizeinbase (r, base >= 0 ? base : -base),
|
|
Packit |
5c3484 |
newline);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
free_expr (e);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpz_clear (r);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
exit (errcode);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
char *
|
|
Packit |
5c3484 |
expr (char *str, expr_t *e)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
expr_t e2;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
if (str[0] == '+')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = term (str + 1, e);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (str[0] == '-')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = term (str + 1, e);
|
|
Packit |
5c3484 |
makeexp (e, NEG, *e, NULL);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (str[0] == '~')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = term (str + 1, e);
|
|
Packit |
5c3484 |
makeexp (e, NOT, *e, NULL);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = term (str, e);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
for (;;)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
switch (str[0])
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
case 'p':
|
|
Packit |
5c3484 |
if (match ("plus", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = term (str + 4, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, PLUS, *e, e2);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'm':
|
|
Packit |
5c3484 |
if (match ("minus", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = term (str + 5, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, MINUS, *e, e2);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case '+':
|
|
Packit |
5c3484 |
str = term (str + 1, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, PLUS, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case '-':
|
|
Packit |
5c3484 |
str = term (str + 1, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, MINUS, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
char *
|
|
Packit |
5c3484 |
term (char *str, expr_t *e)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
expr_t e2;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
str = power (str, e);
|
|
Packit |
5c3484 |
for (;;)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
switch (str[0])
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
case 'm':
|
|
Packit |
5c3484 |
if (match ("mul", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = power (str + 3, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, MULT, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
if (match ("mod", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = power (str + 3, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, MOD, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
case 'd':
|
|
Packit |
5c3484 |
if (match ("div", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = power (str + 3, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, DIV, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
case 'r':
|
|
Packit |
5c3484 |
if (match ("rem", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = power (str + 3, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, REM, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
case 'i':
|
|
Packit |
5c3484 |
if (match ("invmod", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = power (str + 6, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, REM, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
case 't':
|
|
Packit |
5c3484 |
if (match ("times", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = power (str + 5, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, MULT, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
if (match ("thru", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = power (str + 4, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, DIV, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
if (match ("through", str))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = power (str + 7, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, DIV, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
case '*':
|
|
Packit |
5c3484 |
str = power (str + 1, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, MULT, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case '/':
|
|
Packit |
5c3484 |
str = power (str + 1, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, DIV, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case '%':
|
|
Packit |
5c3484 |
str = power (str + 1, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, MOD, *e, e2);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
char *
|
|
Packit |
5c3484 |
power (char *str, expr_t *e)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
expr_t e2;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
str = factor (str, e);
|
|
Packit |
5c3484 |
while (str[0] == '!')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str++;
|
|
Packit |
5c3484 |
makeexp (e, FAC, *e, NULL);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
if (str[0] == '^')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = power (str + 1, &e2;;
|
|
Packit |
5c3484 |
makeexp (e, POW, *e, e2);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
match (char *s, char *str)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
char *ostr = str;
|
|
Packit |
5c3484 |
int i;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
for (i = 0; s[i] != 0; i++)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (str[i] != s[i])
|
|
Packit |
5c3484 |
return 0;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
str = skipspace (str + i);
|
|
Packit |
5c3484 |
return str - ostr;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
matchp (char *s, char *str)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
char *ostr = str;
|
|
Packit |
5c3484 |
int i;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
for (i = 0; s[i] != 0; i++)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (str[i] != s[i])
|
|
Packit |
5c3484 |
return 0;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
str = skipspace (str + i);
|
|
Packit |
5c3484 |
if (str[0] == '(')
|
|
Packit |
5c3484 |
return str - ostr + 1;
|
|
Packit |
5c3484 |
return 0;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
struct functions
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
char *spelling;
|
|
Packit |
5c3484 |
enum op_t op;
|
|
Packit |
5c3484 |
int arity; /* 1 or 2 means real arity; 0 means arbitrary. */
|
|
Packit |
5c3484 |
};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
struct functions fns[] =
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
{"sqrt", SQRT, 1},
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION >= 2
|
|
Packit |
5c3484 |
{"root", ROOT, 2},
|
|
Packit |
5c3484 |
{"popc", POPCNT, 1},
|
|
Packit |
5c3484 |
{"hamdist", HAMDIST, 2},
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
{"gcd", GCD, 0},
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
|
|
Packit |
5c3484 |
{"lcm", LCM, 0},
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
{"and", AND, 0},
|
|
Packit |
5c3484 |
{"ior", IOR, 0},
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
|
|
Packit |
5c3484 |
{"xor", XOR, 0},
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
{"plus", PLUS, 0},
|
|
Packit |
5c3484 |
{"pow", POW, 2},
|
|
Packit |
5c3484 |
{"minus", MINUS, 2},
|
|
Packit |
5c3484 |
{"mul", MULT, 0},
|
|
Packit |
5c3484 |
{"div", DIV, 2},
|
|
Packit |
5c3484 |
{"mod", MOD, 2},
|
|
Packit |
5c3484 |
{"rem", REM, 2},
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION >= 2
|
|
Packit |
5c3484 |
{"invmod", INVMOD, 2},
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
{"log", LOG, 2},
|
|
Packit |
5c3484 |
{"log2", LOG2, 1},
|
|
Packit |
5c3484 |
{"F", FERMAT, 1},
|
|
Packit |
5c3484 |
{"M", MERSENNE, 1},
|
|
Packit |
5c3484 |
{"fib", FIBONACCI, 1},
|
|
Packit |
5c3484 |
{"Fib", FIBONACCI, 1},
|
|
Packit |
5c3484 |
{"random", RANDOM, 1},
|
|
Packit |
5c3484 |
{"nextprime", NEXTPRIME, 1},
|
|
Packit |
5c3484 |
{"binom", BINOM, 2},
|
|
Packit |
5c3484 |
{"binomial", BINOM, 2},
|
|
Packit |
5c3484 |
{"fac", FAC, 1},
|
|
Packit |
5c3484 |
{"fact", FAC, 1},
|
|
Packit |
5c3484 |
{"factorial", FAC, 1},
|
|
Packit |
5c3484 |
{"time", TIMING, 1},
|
|
Packit |
5c3484 |
{"", NOP, 0}
|
|
Packit |
5c3484 |
};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
char *
|
|
Packit |
5c3484 |
factor (char *str, expr_t *e)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
expr_t e1, e2;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (isalpha (str[0]))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int i;
|
|
Packit |
5c3484 |
int cnt;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
for (i = 0; fns[i].op != NOP; i++)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (fns[i].arity == 1)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
cnt = matchp (fns[i].spelling, str);
|
|
Packit |
5c3484 |
if (cnt != 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = expr (str + cnt, &e1;;
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
if (str[0] != ')')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "expected `)'";
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, (int) (long) str);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
makeexp (e, fns[i].op, e1, NULL);
|
|
Packit |
5c3484 |
return str + 1;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
for (i = 0; fns[i].op != NOP; i++)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (fns[i].arity != 1)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
cnt = matchp (fns[i].spelling, str);
|
|
Packit |
5c3484 |
if (cnt != 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = expr (str + cnt, &e1;;
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (str[0] != ',')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "expected `,' and another operand";
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, (int) (long) str);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
str = skipspace (str + 1);
|
|
Packit |
5c3484 |
str = expr (str, &e2;;
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (fns[i].arity == 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
while (str[0] == ',')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
makeexp (&e1, fns[i].op, e1, e2);
|
|
Packit |
5c3484 |
str = skipspace (str + 1);
|
|
Packit |
5c3484 |
str = expr (str, &e2;;
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (str[0] != ')')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "expected `)'";
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, (int) (long) str);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
makeexp (e, fns[i].op, e1, e2);
|
|
Packit |
5c3484 |
return str + 1;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (str[0] == '(')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
str = expr (str + 1, e);
|
|
Packit |
5c3484 |
str = skipspace (str);
|
|
Packit |
5c3484 |
if (str[0] != ')')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "expected `)'";
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, (int) (long) str);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
str++;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (str[0] >= '0' && str[0] <= '9')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
expr_t res;
|
|
Packit |
5c3484 |
char *s, *sc;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
res = malloc (sizeof (struct expr));
|
|
Packit |
5c3484 |
res -> op = LIT;
|
|
Packit |
5c3484 |
mpz_init (res->operands.val);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
s = str;
|
|
Packit |
5c3484 |
while (isalnum (str[0]))
|
|
Packit |
5c3484 |
str++;
|
|
Packit |
5c3484 |
sc = malloc (str - s + 1);
|
|
Packit |
5c3484 |
memcpy (sc, s, str - s);
|
|
Packit |
5c3484 |
sc[str - s] = 0;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpz_set_str (res->operands.val, sc, 0);
|
|
Packit |
5c3484 |
*e = res;
|
|
Packit |
5c3484 |
free (sc);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "operand expected";
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, (int) (long) str);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
char *
|
|
Packit |
5c3484 |
skipspace (char *str)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
while (str[0] == ' ')
|
|
Packit |
5c3484 |
str++;
|
|
Packit |
5c3484 |
return str;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Make a new expression with operation OP and right hand side
|
|
Packit |
5c3484 |
RHS and left hand side lhs. Put the result in R. */
|
|
Packit |
5c3484 |
void
|
|
Packit |
5c3484 |
makeexp (expr_t *r, enum op_t op, expr_t lhs, expr_t rhs)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
expr_t res;
|
|
Packit |
5c3484 |
res = malloc (sizeof (struct expr));
|
|
Packit |
5c3484 |
res -> op = op;
|
|
Packit |
5c3484 |
res -> operands.ops.lhs = lhs;
|
|
Packit |
5c3484 |
res -> operands.ops.rhs = rhs;
|
|
Packit |
5c3484 |
*r = res;
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Free the memory used by expression E. */
|
|
Packit |
5c3484 |
void
|
|
Packit |
5c3484 |
free_expr (expr_t e)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (e->op != LIT)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
free_expr (e->operands.ops.lhs);
|
|
Packit |
5c3484 |
if (e->operands.ops.rhs != NULL)
|
|
Packit |
5c3484 |
free_expr (e->operands.ops.rhs);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
mpz_clear (e->operands.val);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Evaluate the expression E and put the result in R. */
|
|
Packit |
5c3484 |
void
|
|
Packit |
5c3484 |
mpz_eval_expr (mpz_ptr r, expr_t e)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
mpz_t lhs, rhs;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
switch (e->op)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
case LIT:
|
|
Packit |
5c3484 |
mpz_set (r, e->operands.val);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case PLUS:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_add (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case MINUS:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_sub (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case MULT:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_mul (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case DIV:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_fdiv_q (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case MOD:
|
|
Packit |
5c3484 |
mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_abs (rhs, rhs);
|
|
Packit |
5c3484 |
mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case REM:
|
|
Packit |
5c3484 |
/* Check if lhs operand is POW expression and optimize for that case. */
|
|
Packit |
5c3484 |
if (e->operands.ops.lhs->op == POW)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
mpz_t powlhs, powrhs;
|
|
Packit |
5c3484 |
mpz_init (powlhs);
|
|
Packit |
5c3484 |
mpz_init (powrhs);
|
|
Packit |
5c3484 |
mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_powm (r, powlhs, powrhs, rhs);
|
|
Packit |
5c3484 |
if (mpz_cmp_si (rhs, 0L) < 0)
|
|
Packit |
5c3484 |
mpz_neg (r, r);
|
|
Packit |
5c3484 |
mpz_clear (powlhs);
|
|
Packit |
5c3484 |
mpz_clear (powrhs);
|
|
Packit |
5c3484 |
mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_fdiv_r (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION >= 2
|
|
Packit |
5c3484 |
case INVMOD:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_invert (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case POW:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
if (mpz_cmpabs_ui (lhs, 1) <= 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* For 0^rhs and 1^rhs, we just need to verify that
|
|
Packit |
5c3484 |
rhs is well-defined. For (-1)^rhs we need to
|
|
Packit |
5c3484 |
determine (rhs mod 2). For simplicity, compute
|
|
Packit |
5c3484 |
(rhs mod 2) for all three cases. */
|
|
Packit |
5c3484 |
expr_t two, et;
|
|
Packit |
5c3484 |
two = malloc (sizeof (struct expr));
|
|
Packit |
5c3484 |
two -> op = LIT;
|
|
Packit |
5c3484 |
mpz_init_set_ui (two->operands.val, 2L);
|
|
Packit |
5c3484 |
makeexp (&et, MOD, e->operands.ops.rhs, two);
|
|
Packit |
5c3484 |
e->operands.ops.rhs = et;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
if (mpz_cmp_si (rhs, 0L) == 0)
|
|
Packit |
5c3484 |
/* x^0 is 1 */
|
|
Packit |
5c3484 |
mpz_set_ui (r, 1L);
|
|
Packit |
5c3484 |
else if (mpz_cmp_si (lhs, 0L) == 0)
|
|
Packit |
5c3484 |
/* 0^y (where y != 0) is 0 */
|
|
Packit |
5c3484 |
mpz_set_ui (r, 0L);
|
|
Packit |
5c3484 |
else if (mpz_cmp_ui (lhs, 1L) == 0)
|
|
Packit |
5c3484 |
/* 1^y is 1 */
|
|
Packit |
5c3484 |
mpz_set_ui (r, 1L);
|
|
Packit |
5c3484 |
else if (mpz_cmp_si (lhs, -1L) == 0)
|
|
Packit |
5c3484 |
/* (-1)^y just depends on whether y is even or odd */
|
|
Packit |
5c3484 |
mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L);
|
|
Packit |
5c3484 |
else if (mpz_cmp_si (rhs, 0L) < 0)
|
|
Packit |
5c3484 |
/* x^(-n) is 0 */
|
|
Packit |
5c3484 |
mpz_set_ui (r, 0L);
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
unsigned long int cnt;
|
|
Packit |
5c3484 |
unsigned long int y;
|
|
Packit |
5c3484 |
/* error if exponent does not fit into an unsigned long int. */
|
|
Packit |
5c3484 |
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
|
|
Packit |
5c3484 |
goto pow_err;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
y = mpz_get_ui (rhs);
|
|
Packit |
5c3484 |
/* x^y == (x/(2^c))^y * 2^(c*y) */
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION >= 2
|
|
Packit |
5c3484 |
cnt = mpz_scan1 (lhs, 0);
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
cnt = 0;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
if (cnt != 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (y * cnt / cnt != y)
|
|
Packit |
5c3484 |
goto pow_err;
|
|
Packit |
5c3484 |
mpz_tdiv_q_2exp (lhs, lhs, cnt);
|
|
Packit |
5c3484 |
mpz_pow_ui (r, lhs, y);
|
|
Packit |
5c3484 |
mpz_mul_2exp (r, r, y * cnt);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
mpz_pow_ui (r, lhs, y);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
pow_err:
|
|
Packit |
5c3484 |
error = "result of `pow' operator too large";
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
case GCD:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_gcd (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
|
|
Packit |
5c3484 |
case LCM:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_lcm (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case AND:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_and (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case IOR:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_ior (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
|
|
Packit |
5c3484 |
case XOR:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_xor (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case NEG:
|
|
Packit |
5c3484 |
mpz_eval_expr (r, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_neg (r, r);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case NOT:
|
|
Packit |
5c3484 |
mpz_eval_expr (r, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_com (r, r);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case SQRT:
|
|
Packit |
5c3484 |
mpz_init (lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
if (mpz_sgn (lhs) < 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "cannot take square root of negative numbers";
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
mpz_sqrt (r, lhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
|
|
Packit |
5c3484 |
case ROOT:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
if (mpz_sgn (rhs) <= 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "cannot take non-positive root orders";
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "cannot take even root orders of negative numbers";
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
unsigned long int nth = mpz_get_ui (rhs);
|
|
Packit |
5c3484 |
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* If we are asked to take an awfully large root order, cheat and
|
|
Packit |
5c3484 |
ask for the largest order we can pass to mpz_root. This saves
|
|
Packit |
5c3484 |
some error prone special cases. */
|
|
Packit |
5c3484 |
nth = ~(unsigned long int) 0;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
mpz_root (r, lhs, nth);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case FAC:
|
|
Packit |
5c3484 |
mpz_eval_expr (r, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
if (mpz_size (r) > 1)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "result of `!' operator too large";
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
mpz_fac_ui (r, mpz_get_ui (r));
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION >= 2
|
|
Packit |
5c3484 |
case POPCNT:
|
|
Packit |
5c3484 |
mpz_eval_expr (r, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
{ long int cnt;
|
|
Packit |
5c3484 |
cnt = mpz_popcount (r);
|
|
Packit |
5c3484 |
mpz_set_si (r, cnt);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case HAMDIST:
|
|
Packit |
5c3484 |
{ long int cnt;
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
cnt = mpz_hamdist (lhs, rhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
mpz_set_si (r, cnt);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case LOG2:
|
|
Packit |
5c3484 |
mpz_eval_expr (r, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
{ unsigned long int cnt;
|
|
Packit |
5c3484 |
if (mpz_sgn (r) <= 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "logarithm of non-positive number";
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
cnt = mpz_sizeinbase (r, 2);
|
|
Packit |
5c3484 |
mpz_set_ui (r, cnt - 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case LOG:
|
|
Packit |
5c3484 |
{ unsigned long int cnt;
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
if (mpz_sgn (lhs) <= 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "logarithm of non-positive number";
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
if (mpz_cmp_ui (rhs, 256) >= 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "logarithm base too large";
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs));
|
|
Packit |
5c3484 |
mpz_set_ui (r, cnt - 1);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case FERMAT:
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
unsigned long int t;
|
|
Packit |
5c3484 |
mpz_init (lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
t = (unsigned long int) 1 << mpz_get_ui (lhs);
|
|
Packit |
5c3484 |
if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "too large Mersenne number index";
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
mpz_set_ui (r, 1);
|
|
Packit |
5c3484 |
mpz_mul_2exp (r, r, t);
|
|
Packit |
5c3484 |
mpz_add_ui (r, r, 1);
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case MERSENNE:
|
|
Packit |
5c3484 |
mpz_init (lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "too large Mersenne number index";
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
mpz_set_ui (r, 1);
|
|
Packit |
5c3484 |
mpz_mul_2exp (r, r, mpz_get_ui (lhs));
|
|
Packit |
5c3484 |
mpz_sub_ui (r, r, 1);
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case FIBONACCI:
|
|
Packit |
5c3484 |
{ mpz_t t;
|
|
Packit |
5c3484 |
unsigned long int n, i;
|
|
Packit |
5c3484 |
mpz_init (lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "Fibonacci index out of range";
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
n = mpz_get_ui (lhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
|
|
Packit |
5c3484 |
mpz_fib_ui (r, n);
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
mpz_init_set_ui (t, 1);
|
|
Packit |
5c3484 |
mpz_set_ui (r, 1);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (n <= 2)
|
|
Packit |
5c3484 |
mpz_set_ui (r, 1);
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
for (i = 3; i <= n; i++)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
mpz_add (t, t, r);
|
|
Packit |
5c3484 |
mpz_swap (t, r);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
mpz_clear (t);
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case RANDOM:
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
unsigned long int n;
|
|
Packit |
5c3484 |
mpz_init (lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "random number size out of range";
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
n = mpz_get_ui (lhs);
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
mpz_urandomb (r, rstate, n);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case NEXTPRIME:
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
mpz_eval_expr (r, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_nextprime (r, r);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case BINOM:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
unsigned long int k;
|
|
Packit |
5c3484 |
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
error = "k too large in (n over k) expression";
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
longjmp (errjmpbuf, 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
k = mpz_get_ui (rhs);
|
|
Packit |
5c3484 |
mpz_bin_ui (r, lhs, k);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case TIMING:
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int t0;
|
|
Packit |
5c3484 |
t0 = cputime ();
|
|
Packit |
5c3484 |
mpz_eval_expr (r, e->operands.ops.lhs);
|
|
Packit |
5c3484 |
printf ("time: %d\n", cputime () - t0);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
abort ();
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Evaluate the expression E modulo MOD and put the result in R. */
|
|
Packit |
5c3484 |
void
|
|
Packit |
5c3484 |
mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
mpz_t lhs, rhs;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
switch (e->op)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
case POW:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
|
|
Packit |
5c3484 |
mpz_eval_expr (rhs, e->operands.ops.rhs);
|
|
Packit |
5c3484 |
mpz_powm (r, lhs, rhs, mod);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case PLUS:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
|
|
Packit |
5c3484 |
mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
|
|
Packit |
5c3484 |
mpz_add (r, lhs, rhs);
|
|
Packit |
5c3484 |
if (mpz_cmp_si (r, 0L) < 0)
|
|
Packit |
5c3484 |
mpz_add (r, r, mod);
|
|
Packit |
5c3484 |
else if (mpz_cmp (r, mod) >= 0)
|
|
Packit |
5c3484 |
mpz_sub (r, r, mod);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case MINUS:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
|
|
Packit |
5c3484 |
mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
|
|
Packit |
5c3484 |
mpz_sub (r, lhs, rhs);
|
|
Packit |
5c3484 |
if (mpz_cmp_si (r, 0L) < 0)
|
|
Packit |
5c3484 |
mpz_add (r, r, mod);
|
|
Packit |
5c3484 |
else if (mpz_cmp (r, mod) >= 0)
|
|
Packit |
5c3484 |
mpz_sub (r, r, mod);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
case MULT:
|
|
Packit |
5c3484 |
mpz_init (lhs); mpz_init (rhs);
|
|
Packit |
5c3484 |
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
|
|
Packit |
5c3484 |
mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
|
|
Packit |
5c3484 |
mpz_mul (r, lhs, rhs);
|
|
Packit |
5c3484 |
mpz_mod (r, r, mod);
|
|
Packit |
5c3484 |
mpz_clear (lhs); mpz_clear (rhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
mpz_init (lhs);
|
|
Packit |
5c3484 |
mpz_eval_expr (lhs, e);
|
|
Packit |
5c3484 |
mpz_mod (r, lhs, mod);
|
|
Packit |
5c3484 |
mpz_clear (lhs);
|
|
Packit |
5c3484 |
return;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
void
|
|
Packit |
5c3484 |
cleanup_and_exit (int sig)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
switch (sig) {
|
|
Packit |
5c3484 |
#ifdef LIMIT_RESOURCE_USAGE
|
|
Packit |
5c3484 |
case SIGXCPU:
|
|
Packit |
5c3484 |
printf ("expression took too long to evaluate%s\n", newline);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case SIGFPE:
|
|
Packit |
5c3484 |
printf ("divide by zero%s\n", newline);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
printf ("expression required too much memory to evaluate%s\n", newline);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
exit (-2);
|
|
Packit |
5c3484 |
}
|