Revert "Remove gmp from AOS"

This reverts commit f37c97684f0910a3f241394549392f00145ab0f7.

We need gmp for SymEngine for symbolicmanipultion in C++

Change-Id: Ia13216d1715cf96944f7b4f422b7a799f921d4a4
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/third_party/gmp/demos/Makefile.am b/third_party/gmp/demos/Makefile.am
new file mode 100644
index 0000000..64010a6
--- /dev/null
+++ b/third_party/gmp/demos/Makefile.am
@@ -0,0 +1,50 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2000-2002, 2012 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+SUBDIRS = calc expr
+EXTRA_DIST = perl primes.h
+
+AM_CPPFLAGS = -I$(top_srcdir)
+LDADD = $(top_builddir)/libgmp.la
+
+qcn_LDADD = $(LDADD) $(LIBM)
+primes_LDADD = $(LDADD) $(LIBM)
+
+# None of these programs are built by default, but "make <whatever>" will
+# build them once libgmp.la is built.
+#
+EXTRA_PROGRAMS = factorize isprime pexpr primes qcn
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+
+allprogs: $(EXTRA_PROGRAMS)
+	cd calc; $(MAKE) $(AM_MAKEFLAGS) allprogs
+	cd expr; $(MAKE) $(AM_MAKEFLAGS) allprogs
diff --git a/third_party/gmp/demos/Makefile.in b/third_party/gmp/demos/Makefile.in
new file mode 100644
index 0000000..276c96e
--- /dev/null
+++ b/third_party/gmp/demos/Makefile.in
@@ -0,0 +1,785 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2000-2002, 2012 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = factorize$(EXEEXT) isprime$(EXEEXT) pexpr$(EXEEXT) \
+	primes$(EXEEXT) qcn$(EXEEXT)
+subdir = demos
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = pexpr-config.h
+CONFIG_CLEAN_VPATH_FILES =
+factorize_SOURCES = factorize.c
+factorize_OBJECTS = factorize.$(OBJEXT)
+factorize_LDADD = $(LDADD)
+factorize_DEPENDENCIES = $(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+isprime_SOURCES = isprime.c
+isprime_OBJECTS = isprime.$(OBJEXT)
+isprime_LDADD = $(LDADD)
+isprime_DEPENDENCIES = $(top_builddir)/libgmp.la
+pexpr_SOURCES = pexpr.c
+pexpr_OBJECTS = pexpr.$(OBJEXT)
+pexpr_LDADD = $(LDADD)
+pexpr_DEPENDENCIES = $(top_builddir)/libgmp.la
+primes_SOURCES = primes.c
+primes_OBJECTS = primes.$(OBJEXT)
+am__DEPENDENCIES_1 =
+primes_DEPENDENCIES = $(LDADD) $(am__DEPENDENCIES_1)
+qcn_SOURCES = qcn.c
+qcn_OBJECTS = qcn.$(OBJEXT)
+qcn_DEPENDENCIES = $(LDADD) $(am__DEPENDENCIES_1)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = factorize.c isprime.c pexpr.c primes.c qcn.c
+DIST_SOURCES = factorize.c isprime.c pexpr.c primes.c qcn.c
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/pexpr-config-h.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = calc expr
+EXTRA_DIST = perl primes.h
+AM_CPPFLAGS = -I$(top_srcdir)
+LDADD = $(top_builddir)/libgmp.la
+qcn_LDADD = $(LDADD) $(LIBM)
+primes_LDADD = $(LDADD) $(LIBM)
+CLEANFILES = $(EXTRA_PROGRAMS)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps demos/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps demos/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+pexpr-config.h: $(top_builddir)/config.status $(srcdir)/pexpr-config-h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+factorize$(EXEEXT): $(factorize_OBJECTS) $(factorize_DEPENDENCIES) $(EXTRA_factorize_DEPENDENCIES) 
+	@rm -f factorize$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(factorize_OBJECTS) $(factorize_LDADD) $(LIBS)
+
+isprime$(EXEEXT): $(isprime_OBJECTS) $(isprime_DEPENDENCIES) $(EXTRA_isprime_DEPENDENCIES) 
+	@rm -f isprime$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(isprime_OBJECTS) $(isprime_LDADD) $(LIBS)
+
+pexpr$(EXEEXT): $(pexpr_OBJECTS) $(pexpr_DEPENDENCIES) $(EXTRA_pexpr_DEPENDENCIES) 
+	@rm -f pexpr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(pexpr_OBJECTS) $(pexpr_LDADD) $(LIBS)
+
+primes$(EXEEXT): $(primes_OBJECTS) $(primes_DEPENDENCIES) $(EXTRA_primes_DEPENDENCIES) 
+	@rm -f primes$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(primes_OBJECTS) $(primes_LDADD) $(LIBS)
+
+qcn$(EXEEXT): $(qcn_OBJECTS) $(qcn_DEPENDENCIES) $(EXTRA_qcn_DEPENDENCIES) 
+	@rm -f qcn$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(qcn_OBJECTS) $(qcn_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+	check-am clean clean-generic clean-libtool cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+allprogs: $(EXTRA_PROGRAMS)
+	cd calc; $(MAKE) $(AM_MAKEFLAGS) allprogs
+	cd expr; $(MAKE) $(AM_MAKEFLAGS) allprogs
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/demos/calc/Makefile.am b/third_party/gmp/demos/calc/Makefile.am
new file mode 100644
index 0000000..1cb5335
--- /dev/null
+++ b/third_party/gmp/demos/calc/Makefile.am
@@ -0,0 +1,47 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2000-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir)
+
+# $(LEXLIB) is not actually needed for flex (which means the distributed
+# calclex.c), but it's included here for the benefit of anyone rebuilding
+# with some other lex.
+#
+LDADD = $(top_builddir)/libgmp.la $(LIBREADLINE) $(LIBCURSES) $(LEXLIB)
+
+EXTRA_PROGRAMS = calc
+AM_YFLAGS = -d
+calc_SOURCES = calc.y calclex.l calcread.c calc-common.h
+BUILT_SOURCES = calc.h
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+
+allprogs: $(EXTRA_PROGRAMS)
diff --git a/third_party/gmp/demos/calc/Makefile.in b/third_party/gmp/demos/calc/Makefile.in
new file mode 100644
index 0000000..5feb9a8
--- /dev/null
+++ b/third_party/gmp/demos/calc/Makefile.in
@@ -0,0 +1,677 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2000-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = calc$(EXEEXT)
+subdir = demos/calc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = calc-config.h
+CONFIG_CLEAN_VPATH_FILES =
+am_calc_OBJECTS = calc.$(OBJEXT) calclex.$(OBJEXT) calcread.$(OBJEXT)
+calc_OBJECTS = $(am_calc_OBJECTS)
+calc_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+calc_DEPENDENCIES = $(top_builddir)/libgmp.la $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
+LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
+AM_V_LEX = $(am__v_LEX_@AM_V@)
+am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@)
+am__v_LEX_0 = @echo "  LEX     " $@;
+am__v_LEX_1 = 
+YLWRAP = $(top_srcdir)/ylwrap
+@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
+am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
+		   -e s/c++$$/h++/ -e s/c$$/h/
+YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
+AM_V_YACC = $(am__v_YACC_@AM_V@)
+am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
+am__v_YACC_0 = @echo "  YACC    " $@;
+am__v_YACC_1 = 
+SOURCES = $(calc_SOURCES)
+DIST_SOURCES = $(calc_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/calc-config-h.in \
+	$(top_srcdir)/ylwrap README calc.c calc.h calclex.c
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir)
+
+# $(LEXLIB) is not actually needed for flex (which means the distributed
+# calclex.c), but it's included here for the benefit of anyone rebuilding
+# with some other lex.
+#
+LDADD = $(top_builddir)/libgmp.la $(LIBREADLINE) $(LIBCURSES) $(LEXLIB)
+AM_YFLAGS = -d
+calc_SOURCES = calc.y calclex.l calcread.c calc-common.h
+BUILT_SOURCES = calc.h
+CLEANFILES = $(EXTRA_PROGRAMS)
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps demos/calc/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps demos/calc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+calc-config.h: $(top_builddir)/config.status $(srcdir)/calc-config-h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+calc.h: calc.c
+	@if test ! -f $@; then rm -f calc.c; else :; fi
+	@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) calc.c; else :; fi
+
+calc$(EXEEXT): $(calc_OBJECTS) $(calc_DEPENDENCIES) $(EXTRA_calc_DEPENDENCIES) 
+	@rm -f calc$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(calc_OBJECTS) $(calc_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+.l.c:
+	$(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.y.c:
+	$(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-rm -f calc.c
+	-rm -f calc.h
+	-rm -f calclex.c
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags ctags-am distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+allprogs: $(EXTRA_PROGRAMS)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/demos/calc/README b/third_party/gmp/demos/calc/README
new file mode 100644
index 0000000..660394e
--- /dev/null
+++ b/third_party/gmp/demos/calc/README
@@ -0,0 +1,65 @@
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.
+
+
+
+
+                   DEMONSTRATION CALCULATOR PROGRAM
+
+
+This is a simple program, meant only to show one way to use GMP with yacc
+and lex to make a calculator.  Usage and comments on the implementation can
+be found in calc.y.
+
+Within a GMP build tree, the generated Makefile can be used to build the
+program,
+
+	make calc
+
+(or on a DOS system, "make calc.exe").
+
+Elsewhere, once GMP has been installed, the program can be compiled with for
+instance
+
+	gcc calc.c calclex.c -lgmp -o calc
+
+Or if GNU readline is used then
+
+	gcc calc.c calclex.c calcread.c -lgmp -lreadline -o calc
+
+(again, on a DOS system "-o calc.exe").
+
+Readline support can be enabled or disabled in calc-config.h.  That file is
+created by the GMP ./configure based on the --with-readline option.  The
+default is --with-readline=detect, which means to use readline if available.
+"yes" can be used to force it to be used, or "no" to not use it.
+
+The supplied calc.c was generated by GNU bison, but a standard yacc should
+work too.
+
+The supplied calclex.c was generated by GNU flex, but a standard lex should
+work too.  The readline support may or may not work with a standard lex (see
+comments with input() in calcread.c).  Note also that a standard lex will
+require its library "-ll" on the compile command line.  "./configure" sets
+this up in the GMP build tree Makefile.
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/demos/calc/calc-common.h b/third_party/gmp/demos/calc/calc-common.h
new file mode 100644
index 0000000..7a91878
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc-common.h
@@ -0,0 +1,35 @@
+/* Prototypes etc for calc program.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stddef.h>  /* for size_t */
+#ifndef NO_CALC_H
+#include "calc.h"
+#endif
+#include "calc-config.h"
+
+struct calc_keywords_t {
+  char  *name;
+  int   value;
+};
+
+extern int  calc_option_readline;
+extern int  calc_more_input;
+extern const struct calc_keywords_t  calc_keywords[];
+
+int calc_input (char *buf, size_t max_size);
+void calc_init_readline (void);
diff --git a/third_party/gmp/demos/calc/calc-config-h.in b/third_party/gmp/demos/calc/calc-config-h.in
new file mode 100644
index 0000000..42cdd44
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc-config-h.in
@@ -0,0 +1,21 @@
+/* Templates for calc program configuration.   -*- mode:c -*-
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Define if GNU readline should be used. */
+#define WITH_READLINE @WITH_READLINE_01@
diff --git a/third_party/gmp/demos/calc/calc.c b/third_party/gmp/demos/calc/calc.c
new file mode 100644
index 0000000..cc653a2
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc.c
@@ -0,0 +1,1148 @@
+/* original parser id follows */
+/* yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93" */
+/* (use YYMAJOR/YYMINOR for ifdefs dependent on parser version) */
+
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define YYPATCH 20170201
+
+#define YYEMPTY        (-1)
+#define yyclearin      (yychar = YYEMPTY)
+#define yyerrok        (yyerrflag = 0)
+#define YYRECOVERING() (yyerrflag != 0)
+#define YYENOMEM       (-2)
+#define YYEOF          0
+#define YYPREFIX "yy"
+
+#define YYPURE 0
+
+#line 2 "../../../gmp/demos/calc/calc.y"
+/* A simple integer desk calculator using yacc and gmp.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* This is a simple program, meant only to show one way to use GMP for this
+   sort of thing.  There's few features, and error checking is minimal.
+   Standard input is read, calc_help() below shows the inputs accepted.
+
+   Expressions are evaluated as they're read.  If user defined functions
+   were wanted it'd be necessary to build a parse tree like pexpr.c does, or
+   a list of operations for a stack based evaluator.  That would also make
+   it possible to detect and optimize evaluations "mod m" like pexpr.c does.
+
+   A stack is used for intermediate values in the expression evaluation,
+   separate from the yacc parser stack.  This is simple, makes error
+   recovery easy, minimizes the junk around mpz calls in the rules, and
+   saves initializing or clearing "mpz_t"s during a calculation.  A
+   disadvantage though is that variables must be copied to the stack to be
+   worked on.  A more sophisticated calculator or language system might be
+   able to avoid that when executing a compiled or semi-compiled form.
+
+   Avoiding repeated initializing and clearing of "mpz_t"s is important.  In
+   this program the time spent parsing is obviously much greater than any
+   possible saving from this, but a proper calculator or language should
+   take some trouble over it.  Don't be surprised if an init/clear takes 3
+   or more times as long as a 10 limb addition, depending on the system (see
+   the mpz_init_realloc_clear example in tune/README).  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp.h"
+#define NO_CALC_H /* because it conflicts with normal calc.c stuff */
+#include "calc-common.h"
+
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+
+void
+calc_help (void)
+{
+  printf ("Examples:\n");
+  printf ("    2+3*4        expressions are evaluated\n");
+  printf ("    x=5^6        variables a to z can be set and used\n");
+  printf ("Operators:\n");
+  printf ("    + - *        arithmetic\n");
+  printf ("    / %%          division and remainder (rounding towards negative infinity)\n");
+  printf ("    ^            exponentiation\n");
+  printf ("    !            factorial\n");
+  printf ("    << >>        left and right shifts\n");
+  printf ("    <= >= >      \\ comparisons, giving 1 if true, 0 if false\n");
+  printf ("    == != <      /\n");
+  printf ("    && ||        logical and/or, giving 1 if true, 0 if false\n");
+  printf ("Functions:\n");
+  printf ("    abs(n)       absolute value\n");
+  printf ("    bin(n,m)     binomial coefficient\n");
+  printf ("    fib(n)       fibonacci number\n");
+  printf ("    gcd(a,b,..)  greatest common divisor\n");
+  printf ("    kron(a,b)    kronecker symbol\n");
+  printf ("    lcm(a,b,..)  least common multiple\n");
+  printf ("    lucnum(n)    lucas number\n");
+  printf ("    nextprime(n) next prime after n\n");
+  printf ("    powm(b,e,m)  modulo powering, b^e%%m\n");
+  printf ("    root(n,r)    r-th root\n");
+  printf ("    sqrt(n)      square root\n");
+  printf ("Other:\n");
+  printf ("    hex          \\ set hex or decimal for input and output\n");
+  printf ("    decimal      /   (\"0x\" can be used for hex too)\n");
+  printf ("    quit         exit program (EOF works too)\n");
+  printf ("    ;            statements are separated with a ; or newline\n");
+  printf ("    \\            continue expressions with \\ before newline\n");
+  printf ("    # xxx        comments are # though to newline\n");
+  printf ("Hex numbers must be entered in upper case, to distinguish them from the\n");
+  printf ("variables a to f (like in bc).\n");
+}
+
+
+int  ibase = 0;
+int  obase = 10;
+
+
+/* The stack is a fixed size, which means there's a limit on the nesting
+   allowed in expressions.  A more sophisticated program could let it grow
+   dynamically.  */
+
+mpz_t    stack[100];
+mpz_ptr  sp = stack[0];
+
+#define CHECK_OVERFLOW()                                                  \
+  if (sp >= stack[numberof(stack)])	/* FIXME */			\
+    {                                                                     \
+      fprintf (stderr,                                                    \
+               "Value stack overflow, too much nesting in expression\n"); \
+      YYERROR;                                                            \
+    }
+
+#define CHECK_EMPTY()                                                   \
+  if (sp != stack[0])                                                   \
+    {                                                                   \
+      fprintf (stderr, "Oops, expected the value stack to be empty\n"); \
+      sp = stack[0];                                                    \
+    }
+
+
+mpz_t  variable[26];
+
+#define CHECK_VARIABLE(var)                                             \
+  if ((var) < 0 || (var) >= numberof (variable))                        \
+    {                                                                   \
+      fprintf (stderr, "Oops, bad variable somehow: %d\n", var);        \
+      YYERROR;                                                          \
+    }
+
+
+#define CHECK_UI(name,z)                        \
+  if (! mpz_fits_ulong_p (z))                   \
+    {                                           \
+      fprintf (stderr, "%s too big\n", name);   \
+      YYERROR;                                  \
+    }
+
+#ifdef YYSTYPE
+#undef  YYSTYPE_IS_DECLARED
+#define YYSTYPE_IS_DECLARED 1
+#endif
+#ifndef YYSTYPE_IS_DECLARED
+#define YYSTYPE_IS_DECLARED 1
+#line 142 "../../../gmp/demos/calc/calc.y"
+typedef union {
+  char  *str;
+  int   var;
+} YYSTYPE;
+#endif /* !YYSTYPE_IS_DECLARED */
+#line 172 "calc.c"
+
+/* compatibility with bison */
+#ifdef YYPARSE_PARAM
+/* compatibility with FreeBSD */
+# ifdef YYPARSE_PARAM_TYPE
+#  define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM)
+# else
+#  define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM)
+# endif
+#else
+# define YYPARSE_DECL() yyparse(void)
+#endif
+
+/* Parameters sent to lex. */
+#ifdef YYLEX_PARAM
+# define YYLEX_DECL() yylex(void *YYLEX_PARAM)
+# define YYLEX yylex(YYLEX_PARAM)
+#else
+# define YYLEX_DECL() yylex(void)
+# define YYLEX yylex()
+#endif
+
+/* Parameters sent to yyerror. */
+#ifndef YYERROR_DECL
+#define YYERROR_DECL() yyerror(const char *s)
+#endif
+#ifndef YYERROR_CALL
+#define YYERROR_CALL(msg) yyerror(msg)
+#endif
+
+extern int YYPARSE_DECL();
+
+#define EOS 257
+#define BAD 258
+#define HELP 259
+#define HEX 260
+#define DECIMAL 261
+#define QUIT 262
+#define ABS 263
+#define BIN 264
+#define FIB 265
+#define GCD 266
+#define KRON 267
+#define LCM 268
+#define LUCNUM 269
+#define NEXTPRIME 270
+#define POWM 271
+#define ROOT 272
+#define SQRT 273
+#define NUMBER 274
+#define VARIABLE 275
+#define LOR 276
+#define LAND 277
+#define EQ 278
+#define NE 279
+#define LE 280
+#define GE 281
+#define LSHIFT 282
+#define RSHIFT 283
+#define UMINUS 284
+#define YYERRCODE 256
+typedef int YYINT;
+static const YYINT yylhs[] = {                           -1,
+    0,    0,    2,    2,    2,    1,    1,    1,    1,    1,
+    1,    1,    3,    3,    3,    3,    3,    3,    3,    3,
+    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+    3,    3,    3,    3,    4,    4,    5,    5,
+};
+static const YYINT yylen[] = {                            2,
+    1,    2,    2,    3,    2,    0,    1,    3,    1,    1,
+    1,    1,    3,    3,    3,    3,    3,    3,    3,    3,
+    3,    2,    2,    3,    3,    3,    3,    3,    3,    3,
+    3,    4,    6,    4,    4,    6,    4,    4,    4,    8,
+    6,    4,    1,    1,    1,    3,    1,    3,
+};
+static const YYINT yydefred[] = {                         0,
+    0,    9,   10,   11,   12,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   44,    0,    0,    0,
+    0,    0,    0,    0,    5,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,   43,    0,    0,
+    3,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   22,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,   13,    4,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,   32,    0,   34,   35,    0,    0,   37,    0,   38,
+   39,    0,    0,   42,    0,    0,    0,    0,    0,    0,
+   33,   36,    0,   41,    0,   40,
+};
+static const YYINT yydgoto[] = {                         21,
+   22,   23,   24,   64,   67,
+};
+static const YYINT yysindex[] = {                       742,
+ -257,    0,    0,    0,    0,  -22,  -20,  -17,   -5,    5,
+   18,   20,   22,   25,   28,   29,    0,  -54,  808,  808,
+    0, -244,  786,  667,    0,  808,  808,  808,  808,  808,
+  808,  808,  808,  808,  808,  808,  808,    0,  -27,  203,
+    0, -217,  808,  808,  808,  808,  808,  808,  808,  808,
+  808,  808,  808,  808,  808,  808,  808,  808,    0,  454,
+  465,  487,  667,  -33,  498,  667,  -16,  520,  531,  542,
+  564,  586,  667,    0,    0,  678,  929,  -28,  -28,  -28,
+  -28,  -28,  -28,  -21,  -21,   -6,   -6,  -27,  -27,  -27,
+  -27,    0,  808,    0,    0,  808,  808,    0,  808,    0,
+    0,  808,  808,    0,  597,  667,  608,  667,  619,  645,
+    0,    0,  808,    0,  656,    0,
+};
+static const YYINT yyrindex[] = {                         2,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    1,    0,    0,
+    0,   50,    2,    3,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   10,    0,
+    0,   71,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,  -12,    0,    0,  -11,    0,    0,    0,    0,
+    0,    0,    4,    0,    0,  193,   64,  166,  178,  182,
+  187,  189,  191,  139,  151,  112,  124,   37,   49,   76,
+   85,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   -2,    0,   15,    0,    0,
+    0,    0,    0,    0,    0,    0,
+};
+static const YYINT yygindex[] = {                         0,
+   52,    0, 1065,    0,    0,
+};
+#define YYTABLESIZE 1212
+static const YYINT yytable[] = {                         25,
+   43,    6,    7,    8,   59,   59,   37,   95,   57,   23,
+   96,   59,   41,   55,   53,   57,   54,   26,   56,   27,
+   55,   53,   28,   54,   98,   56,   59,   99,   45,   47,
+   57,   45,   47,   43,   29,   55,   16,   43,   46,   75,
+   56,   46,   43,   43,   30,   43,   23,   43,   17,    1,
+   23,   23,   23,   23,   23,   48,   23,   31,   48,   32,
+   43,   33,   43,   30,   34,   58,   58,   35,   36,   23,
+    2,   23,   58,   16,   42,   18,    0,   16,   16,   16,
+   16,   16,    0,   16,   19,   17,    0,   58,    0,   17,
+   17,   17,   17,   17,   43,   17,   16,    0,   16,    0,
+    0,    0,    0,    0,   30,    0,    0,   30,   17,    0,
+   17,   14,   18,    0,    0,    0,   18,   18,   18,   18,
+   18,   19,   18,   15,    0,   19,   19,   19,   19,   19,
+    0,   19,    0,    0,    0,   18,    0,   18,   20,    0,
+    0,    0,    0,    0,   19,    0,   19,    0,    0,    0,
+   21,    0,   14,    0,   14,   14,   14,    0,    0,    0,
+    0,    0,    0,    0,   15,   24,   15,   15,   15,    0,
+    0,   14,    0,   14,    0,    0,    0,   29,    0,   20,
+    0,   26,   20,   15,    0,   15,   27,    0,   25,    0,
+   28,   21,   31,    0,   21,    0,    0,    0,   20,    0,
+   20,    0,    0,    0,    0,    0,   24,    0,    0,   24,
+   21,    0,   21,    0,    0,    0,    0,    0,   29,    0,
+    0,   29,   26,    0,    0,   26,    0,   27,    0,   25,
+   27,   28,   25,   31,   28,   59,   31,    0,    0,   57,
+    0,    0,    0,   74,   55,   53,    0,   54,    0,   56,
+    0,    0,    0,   51,   52,    0,    0,   43,    6,    7,
+    8,    0,   45,    0,   46,    0,   23,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   43,   43,   43,   43,
+   43,   43,   43,   43,    0,   23,   23,   23,   23,   23,
+   23,   23,   23,   16,    0,    0,   58,    0,    0,    0,
+    0,    0,    0,    0,    0,   17,    0,    0,    0,    0,
+    0,    0,   16,   16,   16,   16,   16,   16,   16,   16,
+   30,    0,    0,    0,   17,   17,   17,   17,   17,   17,
+   17,   17,   18,    0,    0,    0,    0,    0,    0,   30,
+   30,   19,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,   18,   18,   18,   18,   18,   18,   18,   18,    0,
+   19,   19,   19,   19,   19,   19,   19,   19,   14,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   15,    0,    0,    0,    0,    0,    0,   14,   14,   14,
+   14,   14,   14,   14,   14,   20,    0,    0,    0,   15,
+   15,   15,   15,   15,   15,   15,   15,   21,    0,    0,
+    0,    0,    0,    0,   20,   20,   20,   20,   20,   20,
+   20,   20,   24,    0,    0,    0,   21,   21,   21,   21,
+   21,   21,   21,   21,   29,    0,    0,    0,   26,    0,
+    0,   24,   24,   27,    0,   25,    0,   28,    0,   31,
+    0,    0,    0,   29,   29,    0,    0,   26,   26,    0,
+    0,    0,   27,   27,   25,   25,   28,   28,   31,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   43,   44,
+   47,   48,   49,   50,   51,   52,   59,    0,    0,    0,
+   57,    0,    0,    0,   92,   55,   53,   59,   54,    0,
+   56,   57,    0,    0,    0,    0,   55,   53,   93,   54,
+    0,   56,    0,   45,    0,   46,    0,    0,    0,   59,
+    0,    0,    0,   57,   45,    0,   46,   94,   55,   53,
+   59,   54,    0,   56,   57,    0,    0,    0,    0,   55,
+   53,   97,   54,    0,   56,    0,   45,   58,   46,    0,
+    0,    0,   59,    0,    0,    0,   57,   45,   58,   46,
+  100,   55,   53,   59,   54,    0,   56,   57,    0,    0,
+    0,  101,   55,   53,   59,   54,    0,   56,   57,   45,
+   58,   46,    0,   55,   53,  102,   54,    0,   56,    0,
+   45,   58,   46,    0,    0,    0,   59,    0,    0,    0,
+   57,   45,    0,   46,    0,   55,   53,  103,   54,    0,
+   56,    0,    0,   58,    0,    0,    0,    0,   59,    0,
+    0,    0,   57,   45,   58,   46,  104,   55,   53,   59,
+   54,    0,   56,   57,    0,   58,    0,  111,   55,   53,
+   59,   54,    0,   56,   57,   45,    0,   46,  112,   55,
+   53,   59,   54,    0,   56,   57,   45,   58,   46,    0,
+   55,   53,  113,   54,    0,   56,    0,   45,    0,   46,
+    0,    0,    0,    0,    0,    0,    0,   59,   45,   58,
+   46,   57,    0,    0,    0,  114,   55,   53,   59,   54,
+   58,   56,   57,    0,    0,    0,  116,   55,   53,   59,
+   54,   58,   56,   57,   45,    0,   46,    0,   55,   53,
+   59,   54,   58,   56,   57,   45,    0,   46,    0,   55,
+   53,    0,   54,    0,   56,    0,   45,    0,   46,   43,
+   44,   47,   48,   49,   50,   51,   52,   45,   58,   46,
+   43,   44,   47,   48,   49,   50,   51,   52,    0,   58,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   58,    0,   43,   44,   47,   48,   49,   50,   51,   52,
+    0,   58,    0,   43,   44,   47,   48,   49,   50,   51,
+   52,   20,    0,    0,    0,    0,   19,    0,    0,    0,
+    0,    0,    0,    0,    0,   43,   44,   47,   48,   49,
+   50,   51,   52,    0,    0,    0,   43,   44,   47,   48,
+   49,   50,   51,   52,    0,    0,    0,   43,   44,   47,
+   48,   49,   50,   51,   52,   20,    0,    0,    0,    0,
+   19,    0,    0,    0,    0,    0,    0,    0,    0,   43,
+   44,   47,   48,   49,   50,   51,   52,   20,    0,    0,
+    0,    0,   19,    0,    0,    0,    0,    0,    0,    0,
+    0,   43,   44,   47,   48,   49,   50,   51,   52,    0,
+    0,    0,   43,   44,   47,   48,   49,   50,   51,   52,
+    0,    0,    0,   43,   44,   47,   48,   49,   50,   51,
+   52,    0,    0,    0,   43,   44,   47,   48,   49,   50,
+   51,   52,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   43,   44,   47,   48,   49,   50,   51,   52,    0,    0,
+    0,   43,   44,   47,   48,   49,   50,   51,   52,    0,
+    0,    0,   43,   44,   47,   48,   49,   50,   51,   52,
+    0,    0,    0,    0,   44,   47,   48,   49,   50,   51,
+   52,   59,    0,    0,    0,   57,    0,    0,    0,    0,
+   55,   53,    0,   54,    0,   56,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   45,    0,
+   46,    0,    0,    0,    0,    0,    0,    1,    0,    0,
+    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,
+   12,   13,   14,   15,   16,   17,   18,    0,    0,    0,
+    0,    0,   58,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    2,    3,    4,    5,    6,    7,
+    8,    9,   10,   11,   12,   13,   14,   15,   16,   17,
+   18,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,
+   16,   17,   38,   39,   40,    0,    0,    0,    0,    0,
+   60,   61,   62,   63,   65,   66,   68,   69,   70,   71,
+   72,   73,    0,    0,    0,    0,    0,   76,   77,   78,
+   79,   80,   81,   82,   83,   84,   85,   86,   87,   88,
+   89,   90,   91,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,  105,    0,    0,
+  106,  107,    0,  108,    0,    0,  109,  110,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,  115,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   47,   48,   49,   50,
+   51,   52,
+};
+static const YYINT yycheck[] = {                        257,
+    0,    0,    0,    0,   33,   33,   61,   41,   37,    0,
+   44,   33,  257,   42,   43,   37,   45,   40,   47,   40,
+   42,   43,   40,   45,   41,   47,   33,   44,   41,   41,
+   37,   44,   44,   33,   40,   42,    0,   37,   41,  257,
+   47,   44,   42,   43,   40,   45,   37,   47,    0,    0,
+   41,   42,   43,   44,   45,   41,   47,   40,   44,   40,
+   60,   40,   62,    0,   40,   94,   94,   40,   40,   60,
+    0,   62,   94,   37,   23,    0,   -1,   41,   42,   43,
+   44,   45,   -1,   47,    0,   37,   -1,   94,   -1,   41,
+   42,   43,   44,   45,   94,   47,   60,   -1,   62,   -1,
+   -1,   -1,   -1,   -1,   41,   -1,   -1,   44,   60,   -1,
+   62,    0,   37,   -1,   -1,   -1,   41,   42,   43,   44,
+   45,   37,   47,    0,   -1,   41,   42,   43,   44,   45,
+   -1,   47,   -1,   -1,   -1,   60,   -1,   62,    0,   -1,
+   -1,   -1,   -1,   -1,   60,   -1,   62,   -1,   -1,   -1,
+    0,   -1,   41,   -1,   43,   44,   45,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   41,    0,   43,   44,   45,   -1,
+   -1,   60,   -1,   62,   -1,   -1,   -1,    0,   -1,   41,
+   -1,    0,   44,   60,   -1,   62,    0,   -1,    0,   -1,
+    0,   41,    0,   -1,   44,   -1,   -1,   -1,   60,   -1,
+   62,   -1,   -1,   -1,   -1,   -1,   41,   -1,   -1,   44,
+   60,   -1,   62,   -1,   -1,   -1,   -1,   -1,   41,   -1,
+   -1,   44,   41,   -1,   -1,   44,   -1,   41,   -1,   41,
+   44,   41,   44,   41,   44,   33,   44,   -1,   -1,   37,
+   -1,   -1,   -1,   41,   42,   43,   -1,   45,   -1,   47,
+   -1,   -1,   -1,  282,  283,   -1,   -1,  257,  257,  257,
+  257,   -1,   60,   -1,   62,   -1,  257,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,  276,  277,  278,  279,
+  280,  281,  282,  283,   -1,  276,  277,  278,  279,  280,
+  281,  282,  283,  257,   -1,   -1,   94,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  257,   -1,   -1,   -1,   -1,
+   -1,   -1,  276,  277,  278,  279,  280,  281,  282,  283,
+  257,   -1,   -1,   -1,  276,  277,  278,  279,  280,  281,
+  282,  283,  257,   -1,   -1,   -1,   -1,   -1,   -1,  276,
+  277,  257,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,  276,  277,  278,  279,  280,  281,  282,  283,   -1,
+  276,  277,  278,  279,  280,  281,  282,  283,  257,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+  257,   -1,   -1,   -1,   -1,   -1,   -1,  276,  277,  278,
+  279,  280,  281,  282,  283,  257,   -1,   -1,   -1,  276,
+  277,  278,  279,  280,  281,  282,  283,  257,   -1,   -1,
+   -1,   -1,   -1,   -1,  276,  277,  278,  279,  280,  281,
+  282,  283,  257,   -1,   -1,   -1,  276,  277,  278,  279,
+  280,  281,  282,  283,  257,   -1,   -1,   -1,  257,   -1,
+   -1,  276,  277,  257,   -1,  257,   -1,  257,   -1,  257,
+   -1,   -1,   -1,  276,  277,   -1,   -1,  276,  277,   -1,
+   -1,   -1,  276,  277,  276,  277,  276,  277,  276,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  276,  277,
+  278,  279,  280,  281,  282,  283,   33,   -1,   -1,   -1,
+   37,   -1,   -1,   -1,   41,   42,   43,   33,   45,   -1,
+   47,   37,   -1,   -1,   -1,   -1,   42,   43,   44,   45,
+   -1,   47,   -1,   60,   -1,   62,   -1,   -1,   -1,   33,
+   -1,   -1,   -1,   37,   60,   -1,   62,   41,   42,   43,
+   33,   45,   -1,   47,   37,   -1,   -1,   -1,   -1,   42,
+   43,   44,   45,   -1,   47,   -1,   60,   94,   62,   -1,
+   -1,   -1,   33,   -1,   -1,   -1,   37,   60,   94,   62,
+   41,   42,   43,   33,   45,   -1,   47,   37,   -1,   -1,
+   -1,   41,   42,   43,   33,   45,   -1,   47,   37,   60,
+   94,   62,   -1,   42,   43,   44,   45,   -1,   47,   -1,
+   60,   94,   62,   -1,   -1,   -1,   33,   -1,   -1,   -1,
+   37,   60,   -1,   62,   -1,   42,   43,   44,   45,   -1,
+   47,   -1,   -1,   94,   -1,   -1,   -1,   -1,   33,   -1,
+   -1,   -1,   37,   60,   94,   62,   41,   42,   43,   33,
+   45,   -1,   47,   37,   -1,   94,   -1,   41,   42,   43,
+   33,   45,   -1,   47,   37,   60,   -1,   62,   41,   42,
+   43,   33,   45,   -1,   47,   37,   60,   94,   62,   -1,
+   42,   43,   44,   45,   -1,   47,   -1,   60,   -1,   62,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   33,   60,   94,
+   62,   37,   -1,   -1,   -1,   41,   42,   43,   33,   45,
+   94,   47,   37,   -1,   -1,   -1,   41,   42,   43,   33,
+   45,   94,   47,   37,   60,   -1,   62,   -1,   42,   43,
+   33,   45,   94,   47,   37,   60,   -1,   62,   -1,   42,
+   43,   -1,   45,   -1,   47,   -1,   60,   -1,   62,  276,
+  277,  278,  279,  280,  281,  282,  283,   60,   94,   62,
+  276,  277,  278,  279,  280,  281,  282,  283,   -1,   94,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   94,   -1,  276,  277,  278,  279,  280,  281,  282,  283,
+   -1,   94,   -1,  276,  277,  278,  279,  280,  281,  282,
+  283,   40,   -1,   -1,   -1,   -1,   45,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  276,  277,  278,  279,  280,
+  281,  282,  283,   -1,   -1,   -1,  276,  277,  278,  279,
+  280,  281,  282,  283,   -1,   -1,   -1,  276,  277,  278,
+  279,  280,  281,  282,  283,   40,   -1,   -1,   -1,   -1,
+   45,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  276,
+  277,  278,  279,  280,  281,  282,  283,   40,   -1,   -1,
+   -1,   -1,   45,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,  276,  277,  278,  279,  280,  281,  282,  283,   -1,
+   -1,   -1,  276,  277,  278,  279,  280,  281,  282,  283,
+   -1,   -1,   -1,  276,  277,  278,  279,  280,  281,  282,
+  283,   -1,   -1,   -1,  276,  277,  278,  279,  280,  281,
+  282,  283,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+  276,  277,  278,  279,  280,  281,  282,  283,   -1,   -1,
+   -1,  276,  277,  278,  279,  280,  281,  282,  283,   -1,
+   -1,   -1,  276,  277,  278,  279,  280,  281,  282,  283,
+   -1,   -1,   -1,   -1,  277,  278,  279,  280,  281,  282,
+  283,   33,   -1,   -1,   -1,   37,   -1,   -1,   -1,   -1,
+   42,   43,   -1,   45,   -1,   47,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   60,   -1,
+   62,   -1,   -1,   -1,   -1,   -1,   -1,  256,   -1,   -1,
+  259,  260,  261,  262,  263,  264,  265,  266,  267,  268,
+  269,  270,  271,  272,  273,  274,  275,   -1,   -1,   -1,
+   -1,   -1,   94,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,  259,  260,  261,  262,  263,  264,
+  265,  266,  267,  268,  269,  270,  271,  272,  273,  274,
+  275,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+  263,  264,  265,  266,  267,  268,  269,  270,  271,  272,
+  273,  274,  275,   19,   20,   -1,   -1,   -1,   -1,   -1,
+   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,
+   36,   37,   -1,   -1,   -1,   -1,   -1,   43,   44,   45,
+   46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
+   56,   57,   58,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   93,   -1,   -1,
+   96,   97,   -1,   99,   -1,   -1,  102,  103,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,  113,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,  278,  279,  280,  281,
+  282,  283,
+};
+#define YYFINAL 21
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 284
+#define YYUNDFTOKEN 292
+#define YYTRANSLATE(a) ((a) > YYMAXTOKEN ? YYUNDFTOKEN : (a))
+#if YYDEBUG
+static const char *const yyname[] = {
+
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"'!'",0,0,0,"'%'",0,0,"'('","')'","'*'","'+'","','","'-'",0,"'/'",0,0,0,0,0,0,0,
+0,0,0,0,0,"'<'","'='","'>'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,"'^'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,"EOS","BAD","HELP","HEX","DECIMAL","QUIT","ABS","BIN","FIB",
+"GCD","KRON","LCM","LUCNUM","NEXTPRIME","POWM","ROOT","SQRT","NUMBER",
+"VARIABLE","LOR","LAND","EQ","NE","LE","GE","LSHIFT","RSHIFT","UMINUS",0,0,0,0,
+0,0,0,"illegal-symbol",
+};
+static const char *const yyrule[] = {
+"$accept : top",
+"top : statement",
+"top : statements statement",
+"statements : statement EOS",
+"statements : statements statement EOS",
+"statements : error EOS",
+"statement :",
+"statement : e",
+"statement : VARIABLE '=' e",
+"statement : HELP",
+"statement : HEX",
+"statement : DECIMAL",
+"statement : QUIT",
+"e : '(' e ')'",
+"e : e '+' e",
+"e : e '-' e",
+"e : e '*' e",
+"e : e '/' e",
+"e : e '%' e",
+"e : e '^' e",
+"e : e LSHIFT e",
+"e : e RSHIFT e",
+"e : e '!'",
+"e : '-' e",
+"e : e '<' e",
+"e : e LE e",
+"e : e EQ e",
+"e : e NE e",
+"e : e GE e",
+"e : e '>' e",
+"e : e LAND e",
+"e : e LOR e",
+"e : ABS '(' e ')'",
+"e : BIN '(' e ',' e ')'",
+"e : FIB '(' e ')'",
+"e : GCD '(' gcdlist ')'",
+"e : KRON '(' e ',' e ')'",
+"e : LCM '(' lcmlist ')'",
+"e : LUCNUM '(' e ')'",
+"e : NEXTPRIME '(' e ')'",
+"e : POWM '(' e ',' e ',' e ')'",
+"e : ROOT '(' e ',' e ')'",
+"e : SQRT '(' e ')'",
+"e : VARIABLE",
+"e : NUMBER",
+"gcdlist : e",
+"gcdlist : gcdlist ',' e",
+"lcmlist : e",
+"lcmlist : lcmlist ',' e",
+
+};
+#endif
+
+int      yydebug;
+int      yynerrs;
+
+int      yyerrflag;
+int      yychar;
+YYSTYPE  yyval;
+YYSTYPE  yylval;
+
+/* define the initial stack-sizes */
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH  YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 10000
+#define YYMAXDEPTH  10000
+#endif
+#endif
+
+#define YYINITSTACKSIZE 200
+
+typedef struct {
+    unsigned stacksize;
+    YYINT    *s_base;
+    YYINT    *s_mark;
+    YYINT    *s_last;
+    YYSTYPE  *l_base;
+    YYSTYPE  *l_mark;
+} YYSTACKDATA;
+/* variables for the parser stack */
+static YYSTACKDATA yystack;
+#line 265 "../../../gmp/demos/calc/calc.y"
+
+yyerror (char *s)
+{
+  fprintf (stderr, "%s\n", s);
+}
+
+int calc_option_readline = -1;
+
+int
+main (int argc, char *argv[])
+{
+  int  i;
+
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "--readline") == 0)
+        calc_option_readline = 1;
+      else if (strcmp (argv[i], "--noreadline") == 0)
+        calc_option_readline = 0;
+      else if (strcmp (argv[i], "--help") == 0)
+        {
+          printf ("Usage: calc [--option]...\n");
+          printf ("  --readline    use readline\n");
+          printf ("  --noreadline  don't use readline\n");
+          printf ("  --help        this message\n");
+          printf ("Readline is only available when compiled in,\n");
+          printf ("and in that case it's the default on a tty.\n");
+          exit (0);
+        }
+      else
+        {
+          fprintf (stderr, "Unrecognised option: %s\n", argv[i]);
+          exit (1);
+        }
+    }
+
+#if WITH_READLINE
+  calc_init_readline ();
+#else
+  if (calc_option_readline == 1)
+    {
+      fprintf (stderr, "Readline support not available\n");
+      exit (1);
+    }
+#endif
+
+  for (i = 0; i < numberof (variable); i++)
+    mpz_init (variable[i]);
+
+  for (i = 0; i < numberof (stack); i++)
+    mpz_init (stack[i]);
+
+  return yyparse ();
+}
+#line 710 "calc.c"
+
+#if YYDEBUG
+#include <stdio.h>	/* needed for printf */
+#endif
+
+#include <stdlib.h>	/* needed for malloc, etc */
+#include <string.h>	/* needed for memset */
+
+/* allocate initial stack or double stack size, up to YYMAXDEPTH */
+static int yygrowstack(YYSTACKDATA *data)
+{
+    int i;
+    unsigned newsize;
+    YYINT *newss;
+    YYSTYPE *newvs;
+
+    if ((newsize = data->stacksize) == 0)
+        newsize = YYINITSTACKSIZE;
+    else if (newsize >= YYMAXDEPTH)
+        return YYENOMEM;
+    else if ((newsize *= 2) > YYMAXDEPTH)
+        newsize = YYMAXDEPTH;
+
+    i = (int) (data->s_mark - data->s_base);
+    newss = (YYINT *)realloc(data->s_base, newsize * sizeof(*newss));
+    if (newss == 0)
+        return YYENOMEM;
+
+    data->s_base = newss;
+    data->s_mark = newss + i;
+
+    newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs));
+    if (newvs == 0)
+        return YYENOMEM;
+
+    data->l_base = newvs;
+    data->l_mark = newvs + i;
+
+    data->stacksize = newsize;
+    data->s_last = data->s_base + newsize - 1;
+    return 0;
+}
+
+#if YYPURE || defined(YY_NO_LEAKS)
+static void yyfreestack(YYSTACKDATA *data)
+{
+    free(data->s_base);
+    free(data->l_base);
+    memset(data, 0, sizeof(*data));
+}
+#else
+#define yyfreestack(data) /* nothing */
+#endif
+
+#define YYABORT  goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR  goto yyerrlab
+
+int
+YYPARSE_DECL()
+{
+    int yym, yyn, yystate;
+#if YYDEBUG
+    const char *yys;
+
+    if ((yys = getenv("YYDEBUG")) != 0)
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif
+
+    yym = 0;
+    yyn = 0;
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = YYEMPTY;
+    yystate = 0;
+
+#if YYPURE
+    memset(&yystack, 0, sizeof(yystack));
+#endif
+
+    if (yystack.s_base == NULL && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+    yystack.s_mark = yystack.s_base;
+    yystack.l_mark = yystack.l_base;
+    yystate = 0;
+    *yystack.s_mark = 0;
+
+yyloop:
+    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+    if (yychar < 0)
+    {
+        yychar = YYLEX;
+        if (yychar < 0) yychar = YYEOF;
+#if YYDEBUG
+        if (yydebug)
+        {
+            if ((yys = yyname[YYTRANSLATE(yychar)]) == NULL) yys = yyname[YYUNDFTOKEN];
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if (((yyn = yysindex[yystate]) != 0) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == (YYINT) yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+        yystate = yytable[yyn];
+        *++yystack.s_mark = yytable[yyn];
+        *++yystack.l_mark = yylval;
+        yychar = YYEMPTY;
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if (((yyn = yyrindex[yystate]) != 0) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == (YYINT) yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag != 0) goto yyinrecovery;
+
+    YYERROR_CALL("syntax error");
+
+    goto yyerrlab; /* redundant goto avoids 'unused label' warning */
+yyerrlab:
+    ++yynerrs;
+
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if (((yyn = yysindex[*yystack.s_mark]) != 0) && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == (YYINT) YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]);
+#endif
+                if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+                yystate = yytable[yyn];
+                *++yystack.s_mark = yytable[yyn];
+                *++yystack.l_mark = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yystack.s_mark);
+#endif
+                if (yystack.s_mark <= yystack.s_base) goto yyabort;
+                --yystack.s_mark;
+                --yystack.l_mark;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == YYEOF) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            if ((yys = yyname[YYTRANSLATE(yychar)]) == NULL) yys = yyname[YYUNDFTOKEN];
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = YYEMPTY;
+        goto yyloop;
+    }
+
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    if (yym > 0)
+        yyval = yystack.l_mark[1-yym];
+    else
+        memset(&yyval, 0, sizeof yyval);
+
+    switch (yyn)
+    {
+case 5:
+#line 173 "../../../gmp/demos/calc/calc.y"
+	{ sp = stack[0]; yyerrok; }
+break;
+case 7:
+#line 177 "../../../gmp/demos/calc/calc.y"
+	{
+      mpz_out_str (stdout, obase, sp); putchar ('\n');
+      sp--;
+      CHECK_EMPTY ();
+    }
+break;
+case 8:
+#line 182 "../../../gmp/demos/calc/calc.y"
+	{
+      CHECK_VARIABLE (yystack.l_mark[-2].var);
+      mpz_swap (variable[yystack.l_mark[-2].var], sp);
+      sp--;
+      CHECK_EMPTY ();
+    }
+break;
+case 9:
+#line 188 "../../../gmp/demos/calc/calc.y"
+	{ calc_help (); }
+break;
+case 10:
+#line 189 "../../../gmp/demos/calc/calc.y"
+	{ ibase = 16; obase = -16; }
+break;
+case 11:
+#line 190 "../../../gmp/demos/calc/calc.y"
+	{ ibase = 0;  obase = 10; }
+break;
+case 12:
+#line 191 "../../../gmp/demos/calc/calc.y"
+	{ exit (0); }
+break;
+case 14:
+#line 198 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_add    (sp, sp, sp+1); }
+break;
+case 15:
+#line 199 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_sub    (sp, sp, sp+1); }
+break;
+case 16:
+#line 200 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_mul    (sp, sp, sp+1); }
+break;
+case 17:
+#line 201 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_fdiv_q (sp, sp, sp+1); }
+break;
+case 18:
+#line 202 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_fdiv_r (sp, sp, sp+1); }
+break;
+case 19:
+#line 203 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Exponent", sp);
+                    sp--; mpz_pow_ui (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 20:
+#line 205 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Shift count", sp);
+                    sp--; mpz_mul_2exp (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 21:
+#line 207 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Shift count", sp);
+                    sp--; mpz_fdiv_q_2exp (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 22:
+#line 209 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Factorial", sp);
+                    mpz_fac_ui (sp, mpz_get_ui (sp)); }
+break;
+case 23:
+#line 211 "../../../gmp/demos/calc/calc.y"
+	{ mpz_neg (sp, sp); }
+break;
+case 24:
+#line 213 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <  0); }
+break;
+case 25:
+#line 214 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <= 0); }
+break;
+case 26:
+#line 215 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) == 0); }
+break;
+case 27:
+#line 216 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) != 0); }
+break;
+case 28:
+#line 217 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >= 0); }
+break;
+case 29:
+#line 218 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >  0); }
+break;
+case 30:
+#line 220 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_sgn (sp) && mpz_sgn (sp+1)); }
+break;
+case 31:
+#line 221 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_sgn (sp) || mpz_sgn (sp+1)); }
+break;
+case 32:
+#line 223 "../../../gmp/demos/calc/calc.y"
+	{ mpz_abs (sp, sp); }
+break;
+case 33:
+#line 224 "../../../gmp/demos/calc/calc.y"
+	{ sp--; CHECK_UI ("Binomial base", sp+1);
+                                   mpz_bin_ui (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 34:
+#line 226 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Fibonacci", sp);
+                                   mpz_fib_ui (sp, mpz_get_ui (sp)); }
+break;
+case 36:
+#line 229 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_si (sp,
+                                         mpz_kronecker (sp, sp+1)); }
+break;
+case 38:
+#line 232 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Lucas number", sp);
+                                   mpz_lucnum_ui (sp, mpz_get_ui (sp)); }
+break;
+case 39:
+#line 234 "../../../gmp/demos/calc/calc.y"
+	{ mpz_nextprime (sp, sp); }
+break;
+case 40:
+#line 235 "../../../gmp/demos/calc/calc.y"
+	{ sp -= 2; mpz_powm (sp, sp, sp+1, sp+2); }
+break;
+case 41:
+#line 236 "../../../gmp/demos/calc/calc.y"
+	{ sp--; CHECK_UI ("Nth-root", sp+1);
+                                   mpz_root (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 42:
+#line 238 "../../../gmp/demos/calc/calc.y"
+	{ mpz_sqrt (sp, sp); }
+break;
+case 43:
+#line 240 "../../../gmp/demos/calc/calc.y"
+	{
+        sp++;
+        CHECK_OVERFLOW ();
+        CHECK_VARIABLE (yystack.l_mark[0].var);
+        mpz_set (sp, variable[yystack.l_mark[0].var]);
+      }
+break;
+case 44:
+#line 246 "../../../gmp/demos/calc/calc.y"
+	{
+        sp++;
+        CHECK_OVERFLOW ();
+        if (mpz_set_str (sp, yystack.l_mark[0].str, ibase) != 0)
+          {
+            fprintf (stderr, "Invalid number: %s\n", yystack.l_mark[0].str);
+            YYERROR;
+          }
+      }
+break;
+case 46:
+#line 258 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_gcd (sp, sp, sp+1); }
+break;
+case 48:
+#line 262 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_lcm (sp, sp, sp+1); }
+break;
+#line 1092 "calc.c"
+    }
+    yystack.s_mark -= yym;
+    yystate = *yystack.s_mark;
+    yystack.l_mark -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yystack.s_mark = YYFINAL;
+        *++yystack.l_mark = yyval;
+        if (yychar < 0)
+        {
+            yychar = YYLEX;
+            if (yychar < 0) yychar = YYEOF;
+#if YYDEBUG
+            if (yydebug)
+            {
+                if ((yys = yyname[YYTRANSLATE(yychar)]) == NULL) yys = yyname[YYUNDFTOKEN];
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == YYEOF) goto yyaccept;
+        goto yyloop;
+    }
+    if (((yyn = yygindex[yym]) != 0) && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == (YYINT) yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yystack.s_mark, yystate);
+#endif
+    if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+    *++yystack.s_mark = (YYINT) yystate;
+    *++yystack.l_mark = yyval;
+    goto yyloop;
+
+yyoverflow:
+    YYERROR_CALL("yacc stack overflow");
+
+yyabort:
+    yyfreestack(&yystack);
+    return (1);
+
+yyaccept:
+    yyfreestack(&yystack);
+    return (0);
+}
diff --git a/third_party/gmp/demos/calc/calc.h b/third_party/gmp/demos/calc/calc.h
new file mode 100644
index 0000000..8c48e2a
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc.h
@@ -0,0 +1,40 @@
+#define EOS 257
+#define BAD 258
+#define HELP 259
+#define HEX 260
+#define DECIMAL 261
+#define QUIT 262
+#define ABS 263
+#define BIN 264
+#define FIB 265
+#define GCD 266
+#define KRON 267
+#define LCM 268
+#define LUCNUM 269
+#define NEXTPRIME 270
+#define POWM 271
+#define ROOT 272
+#define SQRT 273
+#define NUMBER 274
+#define VARIABLE 275
+#define LOR 276
+#define LAND 277
+#define EQ 278
+#define NE 279
+#define LE 280
+#define GE 281
+#define LSHIFT 282
+#define RSHIFT 283
+#define UMINUS 284
+#ifdef YYSTYPE
+#undef  YYSTYPE_IS_DECLARED
+#define YYSTYPE_IS_DECLARED 1
+#endif
+#ifndef YYSTYPE_IS_DECLARED
+#define YYSTYPE_IS_DECLARED 1
+typedef union {
+  char  *str;
+  int   var;
+} YYSTYPE;
+#endif /* !YYSTYPE_IS_DECLARED */
+extern YYSTYPE yylval;
diff --git a/third_party/gmp/demos/calc/calc.y b/third_party/gmp/demos/calc/calc.y
new file mode 100644
index 0000000..0fa1206
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc.y
@@ -0,0 +1,318 @@
+%{
+/* A simple integer desk calculator using yacc and gmp.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* This is a simple program, meant only to show one way to use GMP for this
+   sort of thing.  There's few features, and error checking is minimal.
+   Standard input is read, calc_help() below shows the inputs accepted.
+
+   Expressions are evaluated as they're read.  If user defined functions
+   were wanted it'd be necessary to build a parse tree like pexpr.c does, or
+   a list of operations for a stack based evaluator.  That would also make
+   it possible to detect and optimize evaluations "mod m" like pexpr.c does.
+
+   A stack is used for intermediate values in the expression evaluation,
+   separate from the yacc parser stack.  This is simple, makes error
+   recovery easy, minimizes the junk around mpz calls in the rules, and
+   saves initializing or clearing "mpz_t"s during a calculation.  A
+   disadvantage though is that variables must be copied to the stack to be
+   worked on.  A more sophisticated calculator or language system might be
+   able to avoid that when executing a compiled or semi-compiled form.
+
+   Avoiding repeated initializing and clearing of "mpz_t"s is important.  In
+   this program the time spent parsing is obviously much greater than any
+   possible saving from this, but a proper calculator or language should
+   take some trouble over it.  Don't be surprised if an init/clear takes 3
+   or more times as long as a 10 limb addition, depending on the system (see
+   the mpz_init_realloc_clear example in tune/README).  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp.h"
+#define NO_CALC_H /* because it conflicts with normal calc.c stuff */
+#include "calc-common.h"
+
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+
+void
+calc_help (void)
+{
+  printf ("Examples:\n");
+  printf ("    2+3*4        expressions are evaluated\n");
+  printf ("    x=5^6        variables a to z can be set and used\n");
+  printf ("Operators:\n");
+  printf ("    + - *        arithmetic\n");
+  printf ("    / %%          division and remainder (rounding towards negative infinity)\n");
+  printf ("    ^            exponentiation\n");
+  printf ("    !            factorial\n");
+  printf ("    << >>        left and right shifts\n");
+  printf ("    <= >= >      \\ comparisons, giving 1 if true, 0 if false\n");
+  printf ("    == != <      /\n");
+  printf ("    && ||        logical and/or, giving 1 if true, 0 if false\n");
+  printf ("Functions:\n");
+  printf ("    abs(n)       absolute value\n");
+  printf ("    bin(n,m)     binomial coefficient\n");
+  printf ("    fib(n)       fibonacci number\n");
+  printf ("    gcd(a,b,..)  greatest common divisor\n");
+  printf ("    kron(a,b)    kronecker symbol\n");
+  printf ("    lcm(a,b,..)  least common multiple\n");
+  printf ("    lucnum(n)    lucas number\n");
+  printf ("    nextprime(n) next prime after n\n");
+  printf ("    powm(b,e,m)  modulo powering, b^e%%m\n");
+  printf ("    root(n,r)    r-th root\n");
+  printf ("    sqrt(n)      square root\n");
+  printf ("Other:\n");
+  printf ("    hex          \\ set hex or decimal for input and output\n");
+  printf ("    decimal      /   (\"0x\" can be used for hex too)\n");
+  printf ("    quit         exit program (EOF works too)\n");
+  printf ("    ;            statements are separated with a ; or newline\n");
+  printf ("    \\            continue expressions with \\ before newline\n");
+  printf ("    # xxx        comments are # though to newline\n");
+  printf ("Hex numbers must be entered in upper case, to distinguish them from the\n");
+  printf ("variables a to f (like in bc).\n");
+}
+
+
+int  ibase = 0;
+int  obase = 10;
+
+
+/* The stack is a fixed size, which means there's a limit on the nesting
+   allowed in expressions.  A more sophisticated program could let it grow
+   dynamically.  */
+
+mpz_t    stack[100];
+mpz_ptr  sp = stack[0];
+
+#define CHECK_OVERFLOW()                                                  \
+  if (sp >= stack[numberof(stack)])	/* FIXME */			\
+    {                                                                     \
+      fprintf (stderr,                                                    \
+               "Value stack overflow, too much nesting in expression\n"); \
+      YYERROR;                                                            \
+    }
+
+#define CHECK_EMPTY()                                                   \
+  if (sp != stack[0])                                                   \
+    {                                                                   \
+      fprintf (stderr, "Oops, expected the value stack to be empty\n"); \
+      sp = stack[0];                                                    \
+    }
+
+
+mpz_t  variable[26];
+
+#define CHECK_VARIABLE(var)                                             \
+  if ((var) < 0 || (var) >= numberof (variable))                        \
+    {                                                                   \
+      fprintf (stderr, "Oops, bad variable somehow: %d\n", var);        \
+      YYERROR;                                                          \
+    }
+
+
+#define CHECK_UI(name,z)                        \
+  if (! mpz_fits_ulong_p (z))                   \
+    {                                           \
+      fprintf (stderr, "%s too big\n", name);   \
+      YYERROR;                                  \
+    }
+
+%}
+
+%union {
+  char  *str;
+  int   var;
+}
+
+%token EOS BAD
+%token HELP HEX DECIMAL QUIT
+%token ABS BIN FIB GCD KRON LCM LUCNUM NEXTPRIME POWM ROOT SQRT
+%token <str> NUMBER
+%token <var> VARIABLE
+
+/* operators, increasing precedence */
+%left     LOR
+%left     LAND
+%nonassoc '<' '>' EQ NE LE GE
+%left     LSHIFT RSHIFT
+%left     '+' '-'
+%left     '*' '/' '%'
+%nonassoc UMINUS
+%right    '^'
+%nonassoc '!'
+
+%%
+
+top:
+  statement
+  | statements statement;
+
+statements:
+  statement EOS
+  | statements statement EOS
+  | error EOS { sp = stack[0]; yyerrok; };
+
+statement:
+  /* empty */
+  | e {
+      mpz_out_str (stdout, obase, sp); putchar ('\n');
+      sp--;
+      CHECK_EMPTY ();
+    }
+  | VARIABLE '=' e {
+      CHECK_VARIABLE ($1);
+      mpz_swap (variable[$1], sp);
+      sp--;
+      CHECK_EMPTY ();
+    }
+  | HELP    { calc_help (); }
+  | HEX     { ibase = 16; obase = -16; }
+  | DECIMAL { ibase = 0;  obase = 10; }
+  | QUIT    { exit (0); };
+
+/* "e" leaves it's value on the top of the mpz stack.  A rule like "e '+' e"
+   will have done a reduction for the first "e" first and the second "e"
+   second, so the code receives the values in that order on the stack.  */
+e:
+    '(' e ')'     /* value on stack */
+    | e '+' e     { sp--; mpz_add    (sp, sp, sp+1); }
+    | e '-' e     { sp--; mpz_sub    (sp, sp, sp+1); }
+    | e '*' e     { sp--; mpz_mul    (sp, sp, sp+1); }
+    | e '/' e     { sp--; mpz_fdiv_q (sp, sp, sp+1); }
+    | e '%' e     { sp--; mpz_fdiv_r (sp, sp, sp+1); }
+    | e '^' e     { CHECK_UI ("Exponent", sp);
+                    sp--; mpz_pow_ui (sp, sp, mpz_get_ui (sp+1)); }
+    | e LSHIFT e  { CHECK_UI ("Shift count", sp);
+                    sp--; mpz_mul_2exp (sp, sp, mpz_get_ui (sp+1)); }
+    | e RSHIFT e  { CHECK_UI ("Shift count", sp);
+                    sp--; mpz_fdiv_q_2exp (sp, sp, mpz_get_ui (sp+1)); }
+    | e '!'       { CHECK_UI ("Factorial", sp);
+                    mpz_fac_ui (sp, mpz_get_ui (sp)); }
+    | '-' e %prec UMINUS   { mpz_neg (sp, sp); }
+
+    | e '<' e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <  0); }
+    | e LE  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <= 0); }
+    | e EQ  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) == 0); }
+    | e NE  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) != 0); }
+    | e GE  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >= 0); }
+    | e '>' e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >  0); }
+
+    | e LAND e    { sp--; mpz_set_ui (sp, mpz_sgn (sp) && mpz_sgn (sp+1)); }
+    | e LOR e     { sp--; mpz_set_ui (sp, mpz_sgn (sp) || mpz_sgn (sp+1)); }
+
+    | ABS '(' e ')'              { mpz_abs (sp, sp); }
+    | BIN '(' e ',' e ')'        { sp--; CHECK_UI ("Binomial base", sp+1);
+                                   mpz_bin_ui (sp, sp, mpz_get_ui (sp+1)); }
+    | FIB '(' e ')'              { CHECK_UI ("Fibonacci", sp);
+                                   mpz_fib_ui (sp, mpz_get_ui (sp)); }
+    | GCD '(' gcdlist ')'        /* value on stack */
+    | KRON '(' e ',' e ')'       { sp--; mpz_set_si (sp,
+                                         mpz_kronecker (sp, sp+1)); }
+    | LCM '(' lcmlist ')'        /* value on stack */
+    | LUCNUM '(' e ')'           { CHECK_UI ("Lucas number", sp);
+                                   mpz_lucnum_ui (sp, mpz_get_ui (sp)); }
+    | NEXTPRIME '(' e ')'        { mpz_nextprime (sp, sp); }
+    | POWM '(' e ',' e ',' e ')' { sp -= 2; mpz_powm (sp, sp, sp+1, sp+2); }
+    | ROOT '(' e ',' e ')'       { sp--; CHECK_UI ("Nth-root", sp+1);
+                                   mpz_root (sp, sp, mpz_get_ui (sp+1)); }
+    | SQRT '(' e ')'             { mpz_sqrt (sp, sp); }
+
+    | VARIABLE {
+        sp++;
+        CHECK_OVERFLOW ();
+        CHECK_VARIABLE ($1);
+        mpz_set (sp, variable[$1]);
+      }
+    | NUMBER {
+        sp++;
+        CHECK_OVERFLOW ();
+        if (mpz_set_str (sp, $1, ibase) != 0)
+          {
+            fprintf (stderr, "Invalid number: %s\n", $1);
+            YYERROR;
+          }
+      };
+
+gcdlist:
+    e                /* value on stack */
+    | gcdlist ',' e  { sp--; mpz_gcd (sp, sp, sp+1); };
+
+lcmlist:
+    e                /* value on stack */
+    | lcmlist ',' e  { sp--; mpz_lcm (sp, sp, sp+1); };
+
+%%
+
+yyerror (char *s)
+{
+  fprintf (stderr, "%s\n", s);
+}
+
+int calc_option_readline = -1;
+
+int
+main (int argc, char *argv[])
+{
+  int  i;
+
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "--readline") == 0)
+        calc_option_readline = 1;
+      else if (strcmp (argv[i], "--noreadline") == 0)
+        calc_option_readline = 0;
+      else if (strcmp (argv[i], "--help") == 0)
+        {
+          printf ("Usage: calc [--option]...\n");
+          printf ("  --readline    use readline\n");
+          printf ("  --noreadline  don't use readline\n");
+          printf ("  --help        this message\n");
+          printf ("Readline is only available when compiled in,\n");
+          printf ("and in that case it's the default on a tty.\n");
+          exit (0);
+        }
+      else
+        {
+          fprintf (stderr, "Unrecognised option: %s\n", argv[i]);
+          exit (1);
+        }
+    }
+
+#if WITH_READLINE
+  calc_init_readline ();
+#else
+  if (calc_option_readline == 1)
+    {
+      fprintf (stderr, "Readline support not available\n");
+      exit (1);
+    }
+#endif
+
+  for (i = 0; i < numberof (variable); i++)
+    mpz_init (variable[i]);
+
+  for (i = 0; i < numberof (stack); i++)
+    mpz_init (stack[i]);
+
+  return yyparse ();
+}
diff --git a/third_party/gmp/demos/calc/calclex.c b/third_party/gmp/demos/calc/calclex.c
new file mode 100644
index 0000000..7884001
--- /dev/null
+++ b/third_party/gmp/demos/calc/calclex.c
@@ -0,0 +1,1933 @@
+
+#line 3 "calclex.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 37
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+#if defined(__FreeBSD__)
+#ifndef __STDC_LIMIT_MACROS
+#define	__STDC_LIMIT_MACROS
+#endif
+#include <sys/cdefs.h>
+#include <stdint.h>
+#else
+#define	__dead2
+#endif
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined(__FreeBSD__) || \
+    (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	yy_size_t yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+#define yy_current_buffer YY_CURRENT_BUFFER
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars;		/* number of characters read into yy_ch_buf */
+yy_size_t yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file  );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
+void yy_delete_buffer (YY_BUFFER_STATE b  );
+void yy_flush_buffer (YY_BUFFER_STATE b  );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len  );
+
+void *yyalloc (yy_size_t  );
+void *yyrealloc (void *,yy_size_t  );
+void yyfree (void *  );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  ) __dead2;
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	yyleng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 19
+#define YY_END_OF_BUFFER 20
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[39] =
+    {   0,
+        0,    0,   20,   18,    1,    2,    7,    6,    7,   18,
+       16,   16,    2,    7,    7,    7,   16,   17,   18,   18,
+       11,    6,    5,    6,   14,   16,    0,   12,    8,   10,
+        9,   13,   16,   17,    3,   15,    4,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    2,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    1,    5,    1,    6,    7,    1,    6,
+        6,    6,    6,    6,    6,    1,    6,    8,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    1,   10,   11,
+       12,   13,    1,    1,   14,   14,   14,   14,   14,   14,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   16,   15,   15,
+        1,   17,    1,    6,    1,    1,   15,   15,   15,   15,
+
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   16,
+       15,   15,    1,   18,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[19] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    2,    2,    1,
+        1,    1,    1,    2,    3,    2,    1,    1
+    } ;
+
+static yyconst flex_int16_t yy_base[43] =
+    {   0,
+        0,    0,   39,   49,   49,   49,   26,   16,   49,   30,
+       20,   19,   49,    9,   22,   10,    9,    0,   29,   13,
+       49,   23,   49,   24,   49,    0,    0,   49,   49,   49,
+       49,   49,   13,    0,   49,   49,   49,   49,   41,   28,
+       43,   45
+    } ;
+
+static yyconst flex_int16_t yy_def[43] =
+    {   0,
+       38,    1,   38,   38,   38,   38,   38,   39,   38,   38,
+       40,   40,   38,   38,   38,   38,   41,   42,   38,   38,
+       38,   39,   38,   39,   38,   12,   12,   38,   38,   38,
+       38,   38,   41,   42,   38,   38,   38,    0,   38,   38,
+       38,   38
+    } ;
+
+static yyconst flex_int16_t yy_nxt[68] =
+    {   0,
+        4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
+       14,   15,   16,   17,   18,   18,   19,   20,   23,   28,
+       29,   31,   32,   34,   34,   23,   37,   34,   34,   26,
+       36,   35,   24,   30,   38,   27,   25,   21,   38,   24,
+       24,   22,   22,   22,   33,   33,   34,   34,    3,   38,
+       38,   38,   38,   38,   38,   38,   38,   38,   38,   38,
+       38,   38,   38,   38,   38,   38,   38
+    } ;
+
+static yyconst flex_int16_t yy_chk[68] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    8,   14,
+       14,   16,   16,   17,   17,   22,   24,   33,   33,   40,
+       20,   19,    8,   15,   12,   11,   10,    7,    3,   22,
+       24,   39,   39,   39,   41,   41,   42,   42,   38,   38,
+       38,   38,   38,   38,   38,   38,   38,   38,   38,   38,
+       38,   38,   38,   38,   38,   38,   38
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "../../../gmp/demos/calc/calclex.l"
+/* Lexical analyzer for calc program.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+#line 20 "../../../gmp/demos/calc/calclex.l"
+#include <string.h>
+#include "calc-common.h"
+
+
+#if WITH_READLINE
+/* Let GNU flex use readline.  See the calcread.c redefined input() for a
+   way that might work for a standard lex too.  */
+#define YY_INPUT(buf,result,max_size)   \
+  result = calc_input (buf, max_size);
+#endif
+
+
+/* Non-zero when reading the second or subsequent line of an expression,
+   used to give a different prompt when using readline.  */
+int  calc_more_input = 0;
+
+
+const struct calc_keywords_t  calc_keywords[] = {
+  { "abs",       ABS },
+  { "bin",       BIN },
+  { "decimal",   DECIMAL },
+  { "fib",       FIB },
+  { "hex",       HEX },
+  { "help",      HELP },
+  { "gcd",       GCD },
+  { "kron",      KRON },
+  { "lcm",       LCM },
+  { "lucnum",    LUCNUM },
+  { "nextprime", NEXTPRIME },
+  { "powm",      POWM },
+  { "quit",      QUIT },
+  { "root",      ROOT },
+  { "sqrt",      SQRT },
+  { NULL }
+};
+#line 539 "calclex.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *yyget_in (void );
+
+void yyset_in  (FILE * in_str  );
+
+FILE *yyget_out (void );
+
+void yyset_out  (FILE * out_str  );
+
+yy_size_t yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+    static void yyunput (int c,char *buf_ptr  );
+#endif
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	yy_state_type yy_current_state;
+	char *yy_cp, *yy_bp;
+	int yy_act;
+    
+#line 57 "../../../gmp/demos/calc/calclex.l"
+
+
+#line 726 "calclex.c"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			yyensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				yy_create_buffer(yyin,YY_BUF_SIZE );
+		}
+
+		yy_load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of yytext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		do
+			{
+			YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+			if ( yy_accept[yy_current_state] )
+				{
+				(yy_last_accepting_state) = yy_current_state;
+				(yy_last_accepting_cpos) = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 39 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 49 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = (yy_hold_char);
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 59 "../../../gmp/demos/calc/calclex.l"
+{ /* white space is skipped */ }
+	YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 61 "../../../gmp/demos/calc/calclex.l"
+{ /* semicolon or newline separates statements */
+          calc_more_input = 0;
+          return EOS; }
+	YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 64 "../../../gmp/demos/calc/calclex.l"
+{ /* escaped newlines are skipped */ }
+	YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 67 "../../../gmp/demos/calc/calclex.l"
+{
+            /* comment through to escaped newline is skipped */ }
+	YY_BREAK
+case 5:
+/* rule 5 can match eol */
+YY_RULE_SETUP
+#line 69 "../../../gmp/demos/calc/calclex.l"
+{ /* comment through to newline is a separator */
+            calc_more_input = 0;
+            return EOS; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 72 "../../../gmp/demos/calc/calclex.l"
+{   /* comment through to EOF skipped */ }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 75 "../../../gmp/demos/calc/calclex.l"
+{ return yytext[0]; }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 76 "../../../gmp/demos/calc/calclex.l"
+{ return LE; }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 77 "../../../gmp/demos/calc/calclex.l"
+{ return GE; }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 78 "../../../gmp/demos/calc/calclex.l"
+{ return EQ; }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 79 "../../../gmp/demos/calc/calclex.l"
+{ return NE; }
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 80 "../../../gmp/demos/calc/calclex.l"
+{ return LSHIFT; }
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 81 "../../../gmp/demos/calc/calclex.l"
+{ return RSHIFT; }
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 82 "../../../gmp/demos/calc/calclex.l"
+{ return LAND; }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 83 "../../../gmp/demos/calc/calclex.l"
+{ return LOR; }
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 85 "../../../gmp/demos/calc/calclex.l"
+{
+        yylval.str = yytext;
+        return NUMBER; }
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 89 "../../../gmp/demos/calc/calclex.l"
+{
+        int  i;
+
+        for (i = 0; calc_keywords[i].name != NULL; i++)
+          if (strcmp (yytext, calc_keywords[i].name) == 0)
+            return calc_keywords[i].value;
+
+        if (yytext[0] >= 'a' && yytext[0] <= 'z' && yytext[1] == '\0')
+          {
+            yylval.var = yytext[0] - 'a';
+            return VARIABLE;
+          }
+
+        return BAD;
+}
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 105 "../../../gmp/demos/calc/calclex.l"
+{ return BAD; }
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 107 "../../../gmp/demos/calc/calclex.l"
+ECHO;
+	YY_BREAK
+#line 929 "calclex.c"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( yywrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	char *source = (yytext_ptr);
+	int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			yy_size_t num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				yy_size_t new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart(yyin  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	yy_state_type yy_current_state;
+	char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			(yy_last_accepting_state) = yy_current_state;
+			(yy_last_accepting_cpos) = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 39 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	int yy_is_jam;
+    	char *yy_cp = (yy_c_buf_p);
+
+	YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		(yy_last_accepting_state) = yy_current_state;
+		(yy_last_accepting_cpos) = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 39 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 38);
+
+		return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+    static void yyunput (int c, char * yy_bp )
+{
+	char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up yytext */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		yy_size_t number_to_move = (yy_n_chars) + 2;
+		char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+#endif	/* ifndef YY_NO_UNPUT */
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart(yyin );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve yytext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void yyrestart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            yy_create_buffer(yyin,YY_BUF_SIZE );
+	}
+
+	yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+	yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		yypop_buffer_state();
+	 *		yypush_buffer_state(new_buffer);
+     */
+	yyensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	yy_load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * 
+ */
+    void yy_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yyfree((void *) b->yy_ch_buf  );
+
+	yyfree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	yy_flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void yy_flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	yyensure_buffer_stack();
+
+	/* This block is copied from yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from yy_switch_to_buffer. */
+	yy_load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void yypop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	yy_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		yy_load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+	yy_size_t num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+    
+	return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	yy_size_t i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) yyalloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = (yy_hold_char); \
+		(yy_c_buf_p) = yytext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int yyget_lineno  (void)
+{
+        
+    return yylineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *yyget_in  (void)
+{
+        return yyin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *yyget_out  (void)
+{
+        return yyout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+yy_size_t yyget_leng  (void)
+{
+        return yyleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *yyget_text  (void)
+{
+        return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void yyset_lineno (int  line_number )
+{
+    
+    yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE *  in_str )
+{
+        yyin = in_str ;
+}
+
+void yyset_out (FILE *  out_str )
+{
+        yyout = out_str ;
+}
+
+int yyget_debug  (void)
+{
+        return yy_flex_debug;
+}
+
+void yyset_debug (int  bdebug )
+{
+        yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from yylex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * yylex_init()
+     */
+    return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		yy_delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		yypop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	yyfree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * yylex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *yyalloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *yyrealloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 107 "../../../gmp/demos/calc/calclex.l"
+
+
+
+int
+yywrap ()
+{
+  return 1;
+}
+
diff --git a/third_party/gmp/demos/calc/calclex.l b/third_party/gmp/demos/calc/calclex.l
new file mode 100644
index 0000000..44df848
--- /dev/null
+++ b/third_party/gmp/demos/calc/calclex.l
@@ -0,0 +1,113 @@
+/* Lexical analyzer for calc program.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+%{
+#include <string.h>
+#include "calc-common.h"
+
+
+#if WITH_READLINE
+/* Let GNU flex use readline.  See the calcread.c redefined input() for a
+   way that might work for a standard lex too.  */
+#define YY_INPUT(buf,result,max_size)   \
+  result = calc_input (buf, max_size);
+#endif
+
+
+/* Non-zero when reading the second or subsequent line of an expression,
+   used to give a different prompt when using readline.  */
+int  calc_more_input = 0;
+
+
+const struct calc_keywords_t  calc_keywords[] = {
+  { "abs",       ABS },
+  { "bin",       BIN },
+  { "decimal",   DECIMAL },
+  { "fib",       FIB },
+  { "hex",       HEX },
+  { "help",      HELP },
+  { "gcd",       GCD },
+  { "kron",      KRON },
+  { "lcm",       LCM },
+  { "lucnum",    LUCNUM },
+  { "nextprime", NEXTPRIME },
+  { "powm",      POWM },
+  { "quit",      QUIT },
+  { "root",      ROOT },
+  { "sqrt",      SQRT },
+  { NULL }
+};
+%}
+
+%%
+
+[ \t\f] { /* white space is skipped */ }
+
+[;\n]   { /* semicolon or newline separates statements */
+          calc_more_input = 0;
+          return EOS; }
+\\\n    { /* escaped newlines are skipped */ }
+
+
+#(([^\\\n]*)\\)+\n {
+            /* comment through to escaped newline is skipped */ }
+#[^\n]*\n { /* comment through to newline is a separator */
+            calc_more_input = 0;
+            return EOS; }
+#[^\n]* {   /* comment through to EOF skipped */ }
+
+
+[-+*/%()<>^!=,] { return yytext[0]; }
+"<="    { return LE; }
+">="    { return GE; }
+"=="    { return EQ; }
+"!="    { return NE; }
+"<<"    { return LSHIFT; }
+">>"    { return RSHIFT; }
+"&&"    { return LAND; }
+"||"    { return LOR; }
+
+(0[xX])?[0-9A-F]+ {
+        yylval.str = yytext;
+        return NUMBER; }
+
+[a-zA-Z][a-zA-Z0-9]* {
+        int  i;
+
+        for (i = 0; calc_keywords[i].name != NULL; i++)
+          if (strcmp (yytext, calc_keywords[i].name) == 0)
+            return calc_keywords[i].value;
+
+        if (yytext[0] >= 'a' && yytext[0] <= 'z' && yytext[1] == '\0')
+          {
+            yylval.var = yytext[0] - 'a';
+            return VARIABLE;
+          }
+
+        return BAD;
+}
+
+. { return BAD; }
+
+%%
+
+int
+yywrap ()
+{
+  return 1;
+}
diff --git a/third_party/gmp/demos/calc/calcread.c b/third_party/gmp/demos/calc/calcread.c
new file mode 100644
index 0000000..4043368
--- /dev/null
+++ b/third_party/gmp/demos/calc/calcread.c
@@ -0,0 +1,146 @@
+/* Readline support for calc program.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "calc-common.h"
+
+#if WITH_READLINE
+#include <stdio.h>   /* for FILE for old versions of readline/readline.h */
+#include <stdlib.h>  /* for free */
+#include <string.h>  /* for strdup */
+#include <unistd.h>  /* for isatty */
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "gmp.h"
+
+
+/* change this to "#define TRACE(x) x" for a few diagnostics */
+#define TRACE(x)
+
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
+char *
+calc_completion_entry (const char *text, int state)
+{
+  static int  index, len;
+  char  *name;
+
+  if (!state)
+    {
+      index = 0;
+      len = strlen (text);
+    }
+  TRACE (printf ("calc_completion_entry %s %d, index=%d len=%d\n",
+		 text, state, index, len));
+  while ((name = calc_keywords[index].name) != NULL)
+    {
+      index++;
+      if (memcmp (name, text, len) == 0)
+	return (strdup (name));
+    }
+  return NULL;
+}
+
+void
+calc_init_readline (void)
+{
+  /* By default use readline when the input is a tty.  It's a bit contrary
+     to the GNU interface conventions to make the behaviour depend on where
+     the input is coming from, but this is pretty convenient.  */
+  if (calc_option_readline == -1)
+    {
+      calc_option_readline = isatty (fileno (stdin));
+      TRACE (printf ("calc_option_readline %d\n", calc_option_readline));
+    }
+
+  if (calc_option_readline)
+    {
+      printf ("GNU MP demo calculator program, gmp version %s\n", gmp_version);
+      printf ("Type \"help\" for help.\n");
+      rl_readline_name = "gmp-calc";
+      rl_completion_entry_function = calc_completion_entry;
+    }
+}
+
+
+/* This function is supposed to return YY_NULL to indicate EOF, but that
+   constant is only in calclex.c and we don't want to clutter calclex.l with
+   this readline stuff, so instead just hard code 0 for YY_NULL.  That's
+   it's defined value on unix anyway.  */
+
+int
+calc_input (char *buf, size_t max_size)
+{
+  if (calc_option_readline)
+    {
+      static char    *line = NULL;
+      static size_t  line_size = 0;
+      static size_t  upto = 0;
+      size_t         copy_size;
+
+      if (upto >= line_size)
+	{
+	  if (line != NULL)
+	    free (line);
+
+	  line = readline (calc_more_input ? "more> " : "> ");
+	  calc_more_input = 1;
+	  if (line == NULL)
+	    return 0;
+	  TRACE (printf ("readline: %s\n", line));
+
+	  if (line[0] != '\0')
+	    add_history (line);
+
+	  line_size = strlen (line);
+	  line[line_size] = '\n';
+	  line_size++;
+	  upto = 0;
+	}
+
+      copy_size = MIN (line_size-upto, max_size);
+      memcpy (buf, line+upto, copy_size);
+      upto += copy_size;
+      return copy_size;
+    }
+  else
+    {
+      /* not readline */
+      return fread (buf, 1, max_size, stdin);
+    }
+}
+
+
+/* This redefined input() might let a traditional lex use the readline
+   support here.  Apparently POSIX doesn't specify whether an override like
+   this will work, so maybe it'll work or maybe it won't.  This function is
+   also not particularly efficient, but don't worry about that, since flex
+   is the preferred parser.  */
+
+int
+input (void)
+{
+  char  c;
+  if (calc_input (&c, 1) != 1)
+    return EOF;
+  else
+    return (int) c;
+}
+
+#endif /* WITH_READLINE */
diff --git a/third_party/gmp/demos/expr/Makefile.am b/third_party/gmp/demos/expr/Makefile.am
new file mode 100644
index 0000000..252300a
--- /dev/null
+++ b/third_party/gmp/demos/expr/Makefile.am
@@ -0,0 +1,54 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2001-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+
+# FIXME: This is a workaround for a bug in automake 1.8.4.  When the only
+# library is in EXTRA_LIBRARIES, $(ARFLAGS) is used but no default setting
+# for that variable is established.  We give an explicit ARFLAGS=cru the
+# same as generated for lib_LIBRARIES or noinst_LIBRARIES.
+#
+ARFLAGS = cru
+
+EXTRA_LIBRARIES = libexpr.a
+libexpr_a_SOURCES = expr.h expr-impl.h \
+  expr.c exprv.c exprz.c exprza.c exprq.c exprqa.c exprf.c exprfa.c
+
+EXTRA_PROGRAMS = run-expr t-expr
+LDADD = libexpr.a $(top_builddir)/libgmp.la
+t_expr_LDADD = $(top_builddir)/tests/libtests.la $(LDADD)
+
+CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LIBRARIES)
+
+allprogs: $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
diff --git a/third_party/gmp/demos/expr/Makefile.in b/third_party/gmp/demos/expr/Makefile.in
new file mode 100644
index 0000000..354e239
--- /dev/null
+++ b/third_party/gmp/demos/expr/Makefile.in
@@ -0,0 +1,666 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2001-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = run-expr$(EXEEXT) t-expr$(EXEEXT)
+subdir = demos/expr
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo "  AR      " $@;
+am__v_AR_1 = 
+libexpr_a_AR = $(AR) $(ARFLAGS)
+libexpr_a_LIBADD =
+am_libexpr_a_OBJECTS = expr.$(OBJEXT) exprv.$(OBJEXT) exprz.$(OBJEXT) \
+	exprza.$(OBJEXT) exprq.$(OBJEXT) exprqa.$(OBJEXT) \
+	exprf.$(OBJEXT) exprfa.$(OBJEXT)
+libexpr_a_OBJECTS = $(am_libexpr_a_OBJECTS)
+run_expr_SOURCES = run-expr.c
+run_expr_OBJECTS = run-expr.$(OBJEXT)
+run_expr_LDADD = $(LDADD)
+run_expr_DEPENDENCIES = libexpr.a $(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+t_expr_SOURCES = t-expr.c
+t_expr_OBJECTS = t-expr.$(OBJEXT)
+t_expr_DEPENDENCIES = $(top_builddir)/tests/libtests.la $(LDADD)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libexpr_a_SOURCES) run-expr.c t-expr.c
+DIST_SOURCES = $(libexpr_a_SOURCES) run-expr.c t-expr.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+
+# FIXME: This is a workaround for a bug in automake 1.8.4.  When the only
+# library is in EXTRA_LIBRARIES, $(ARFLAGS) is used but no default setting
+# for that variable is established.  We give an explicit ARFLAGS=cru the
+# same as generated for lib_LIBRARIES or noinst_LIBRARIES.
+#
+ARFLAGS = cru
+EXTRA_LIBRARIES = libexpr.a
+libexpr_a_SOURCES = expr.h expr-impl.h \
+  expr.c exprv.c exprz.c exprza.c exprq.c exprqa.c exprf.c exprfa.c
+
+LDADD = libexpr.a $(top_builddir)/libgmp.la
+t_expr_LDADD = $(top_builddir)/tests/libtests.la $(LDADD)
+CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LIBRARIES)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps demos/expr/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps demos/expr/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+libexpr.a: $(libexpr_a_OBJECTS) $(libexpr_a_DEPENDENCIES) $(EXTRA_libexpr_a_DEPENDENCIES) 
+	$(AM_V_at)-rm -f libexpr.a
+	$(AM_V_AR)$(libexpr_a_AR) libexpr.a $(libexpr_a_OBJECTS) $(libexpr_a_LIBADD)
+	$(AM_V_at)$(RANLIB) libexpr.a
+
+run-expr$(EXEEXT): $(run_expr_OBJECTS) $(run_expr_DEPENDENCIES) $(EXTRA_run_expr_DEPENDENCIES) 
+	@rm -f run-expr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(run_expr_OBJECTS) $(run_expr_LDADD) $(LIBS)
+
+t-expr$(EXEEXT): $(t_expr_OBJECTS) $(t_expr_DEPENDENCIES) $(EXTRA_t_expr_DEPENDENCIES) 
+	@rm -f t-expr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_expr_OBJECTS) $(t_expr_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags ctags-am distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+allprogs: $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/demos/expr/README b/third_party/gmp/demos/expr/README
new file mode 100644
index 0000000..a54fe42
--- /dev/null
+++ b/third_party/gmp/demos/expr/README
@@ -0,0 +1,501 @@
+Copyright 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+
+                    GMP EXPRESSION EVALUATION
+                    -------------------------
+
+
+
+THIS CODE IS PRELIMINARY AND MAY BE SUBJECT TO INCOMPATIBLE CHANGES IN
+FUTURE VERSIONS OF GMP.
+
+
+
+The files in this directory implement a simple scheme of string based
+expression parsing and evaluation, supporting mpz, mpq and mpf.
+
+This will be slower than direct GMP library calls, but may be convenient in
+various circumstances, such as while prototyping, or for letting a user
+enter values in symbolic form.  "2**5723-7" for example is a lot easier to
+enter or maintain than the equivalent written out in decimal.
+
+
+
+BUILDING
+
+Nothing in this directory is a normal part of libgmp, and nothing is built
+or installed, but various Makefile rules are available to compile
+everything.
+
+All the functions are available through a little library (there's no shared
+library since upward binary compatibility is not guaranteed).
+
+	make libexpr.a
+
+In a program, prototypes are available using
+
+	#include "expr.h"
+
+run-expr.c is a sample program doing evaluations from the command line.
+
+	make run-expr
+	./run-expr '1+2*3'
+
+t-expr.c is self-test program, it prints nothing if successful.
+
+	make t-expr
+	./t-expr
+
+The expr*.c sources don't depend on gmp-impl.h and can be compiled with just
+a standard installed GMP.  This isn't true of t-expr though, since it uses
+some of the internal tests/libtests.la.
+
+
+
+SIMPLE USAGE
+
+int mpz_expr (mpz_t res, int base, const char *e, ...);
+int mpq_expr (mpq_t res, int base, const char *e, ...);
+int mpf_expr (mpf_t res, int base, const char *e, ...);
+
+These functions evaluate simple arithmetic expressions.  For example,
+
+	mpz_expr (result, 0, "123+456", NULL);
+
+Numbers are parsed by mpz_expr and mpq_expr the same as mpz_set_str with the
+given base.  mpf_expr follows mpf_set_str, but supporting an "0x" prefix for
+hex when base==0.
+
+	mpz_expr (result, 0, "0xAAAA * 0x5555", NULL);
+
+White space, as indicated by <ctype.h> isspace(), is ignored except for the
+purpose of separating tokens.
+
+Variables can be included in expressions by putting them in the stdarg list
+after the string.  "a", "b", "c" etc in the expression string designate
+those values.  For example,
+
+        mpq_t  foo, bar;
+        ...
+	mpq_expr (q, 10, "2/3 + 1/a + b/2", foo, bar, NULL);
+
+Here "a" will be the value from foo and "b" from bar.  Up to 26 variables
+can be included this way.  The NULL must be present to indicate the end of
+the list.
+
+Variables can also be written "$a", "$b" etc.  This is necessary when using
+bases greater than 10 since plain "a", "b" etc will otherwise be interpreted
+as numbers.  For example,
+
+        mpf_t  quux;
+        mpf_expr (f, 16, "F00F@-6 * $a", quux, NULL);
+
+All the standard C operators are available, with the usual precedences, plus
+"**" for exponentiation at the highest precedence (and right associative).
+
+        Operators      Precedence
+         **              220
+         ~ ! - (unary)   210
+         * / %           200
+         + -             190
+         << >>           180
+         <= < >= >       170
+         == !=           160
+         &               150
+         ^               140
+         |               130
+         &&              120
+         ||              110
+         ? :             100/101
+
+Currently only mpz_expr has the bitwise ~ % & ^ and | operators.  The
+precedence numbers are of interest in the advanced usage described below.
+
+Various functions are available too.  For example,
+
+        mpz_expr (res, 10, "gcd(123,456,789) * abs(a)", var, NULL);
+
+The following is the full set of functions,
+
+        mpz_expr
+            abs bin clrbit cmp cmpabs congruent_p divisible_p even_p fib fac
+            gcd hamdist invert jacobi kronecker lcm lucnum max min nextprime
+            odd_p perfect_power_p perfect_square_p popcount powm
+            probab_prime_p root scan0 scan1 setbit sgn sqrt
+
+        mpq_expr
+            abs, cmp, den, max, min, num, sgn
+
+        mpf_expr
+            abs, ceil, cmp, eq, floor, integer_p, max, min, reldiff, sgn,
+            sqrt, trunc
+
+All these are the same as the GMP library functions, except that min and max
+don't exist in the library.  Note also that min, max, gcd and lcm take any
+number of arguments, not just two.
+
+mpf_expr does all calculations to the precision of the destination variable.
+
+
+Expression parsing can succeed or fail.  The return value indicates this,
+and will be one of the following
+
+	MPEXPR_RESULT_OK
+	MPEXPR_RESULT_BAD_VARIABLE
+	MPEXPR_RESULT_BAD_TABLE
+	MPEXPR_RESULT_PARSE_ERROR
+	MPEXPR_RESULT_NOT_UI
+
+BAD_VARIABLE is when a variable is referenced that hasn't been provided.
+For example if "c" is used when only two parameters have been passed.
+BAD_TABLE is applicable to the advanced usage described below.
+
+PARSE_ERROR is a general syntax error, returned for any mal-formed input
+string.
+
+NOT_UI is returned when an attempt is made to use an operand that's bigger
+than an "unsigned long" with a function that's restricted to that range.
+For example "fib" is mpz_fib_ui and only accepts an "unsigned long".
+
+
+
+
+ADVANCED USAGE
+
+int mpz_expr_a (const struct mpexpr_operator_t *table,
+                mpz_ptr res, int base, const char *e, size_t elen,
+                mpz_srcptr var[26])
+int mpq_expr_a (const struct mpexpr_operator_t *table,
+                mpq_ptr res, int base, const char *e, size_t elen,
+                mpq_srcptr var[26])
+int mpf_expr_a (const struct mpexpr_operator_t *table,
+                mpf_ptr res, int base, unsigned long prec,
+                const char *e, size_t elen,
+                mpf_srcptr var[26])
+
+These functions are an advanced interface to expression parsing.
+
+The string is taken as pointer and length.  This makes it possible to parse
+an expression in the middle of somewhere without copying and null
+terminating it.
+
+Variables are an array of 26 pointers to the appropriate operands, or NULL
+for variables that are not available.  Any combination of variables can be
+given, for example just "x" and "y" (var[23] and var[24]) could be set.
+
+Operators and functions are specified with a table.  This makes it possible
+to provide additional operators or functions, or to completely change the
+syntax.  The standard tables used by the simple functions above are
+available as
+
+	const struct mpexpr_operator_t * const mpz_expr_standard_table;
+	const struct mpexpr_operator_t * const mpq_expr_standard_table;
+	const struct mpexpr_operator_t * const mpf_expr_standard_table;
+
+struct mpexpr_operator_t is the following
+
+	struct mpexpr_operator_t {
+	  const char    *name;
+	  mpexpr_fun_t  fun;
+	  int           type;
+	  int           precedence;
+	};
+
+        typedef void (*mpexpr_fun_t) (void);
+
+As an example, the standard mpz_expr table entry for multiplication is as
+follows.  See the source code for the full set of standard entries.
+
+	{ "*", (mpexpr_fun_t) mpz_mul, MPEXPR_TYPE_BINARY, 200 },
+
+"name" is the string to parse, "fun" is the function to call for it, "type"
+indicates what parameters the function takes (among other things), and
+"precedence" sets its operator precedence.
+
+A NULL for "name" indicates the end of the table, so for example an mpf
+table with nothing but addition could be
+
+        struct mpexpr_operator_t  table[] = {
+          { "+", (mpexpr_fun_t) mpf_add, MPEXPR_TYPE_BINARY, 190 },
+          { NULL }
+        };
+
+A special type MPEXPR_TYPE_NEW_TABLE makes it possible to chain from one
+table to another.  For example the following would add a "mod" operator to
+the standard mpz table,
+
+        struct mpexpr_operator_t  table[] = {
+        { "mod", (mpexpr_fun_t) mpz_fdiv_r, MPEXPR_TYPE_BINARY, 125 },
+        { (const char *) mpz_expr_standard_table, NULL, MPEXPR_TYPE_NEW_TABLE }
+        };
+
+Notice the low precedence on "mod", so that for instance "45+26 mod 7"
+parses as "(45+26)mod7".
+
+
+Functions are designated by a precedence of 0.  They always occur as
+"foo(expr)" and so have no need for a precedence level.  mpq_abs in the
+standard mpq table is
+
+	{ "abs", (mpexpr_fun_t) mpq_abs, MPEXPR_TYPE_UNARY },
+
+Functions expecting no arguments as in "foo()" can be given with
+MPEXPR_TYPE_0ARY, or actual constants to be parsed as just "foo" are
+MPEXPR_TYPE_CONSTANT.  For example if a "void mpf_const_pi(mpf_t f)"
+function existed (which it doesn't) it could be,
+
+	{ "pi", (mpexpr_fun_t) mpf_const_pi, MPEXPR_TYPE_CONSTANT },
+
+
+Parsing of operator names is done by seeking the table entry with the
+longest matching name.  So for instance operators "<" and "<=" exist, and
+when presented with "x <= y" the parser matches "<=" because it's longer.
+
+Parsing of function names, on the other hand, is done by requiring a whole
+alphanumeric word to match.  For example presented with "fib2zz(5)" the
+parser will attempt to find a function called "fib2zz".  A function "fib"
+wouldn't be used because it doesn't match the whole word.
+
+The flag MPEXPR_TYPE_WHOLEWORD can be ORed into an operator type to override
+the default parsing style.  Similarly MPEXPR_TYPE_OPERATOR into a function.
+
+
+Binary operators are left associative by default, meaning they're evaluated
+from left to right, so for example "1+2+3" is treated as "(1+2)+3".
+MPEXPR_TYPE_RIGHTASSOC can be ORed into the operator type to work from right
+to left as in "1+(2+3)".  This is generally what's wanted for
+exponentiation, and for example the standard mpz table has
+
+        { "**", (mpexpr_fun_t) mpz_pow_ui,
+          MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC, 220 }
+
+Unary operators are postfix by default.  For example a factorial to be used
+as "123!" might be
+
+	{ "!", (mpexpr_fun_t) mpz_fac_ui, MPEXPR_TYPE_UNARY_UI, 215 }
+
+MPEXPR_TYPE_PREFIX can be ORed into the type to get a prefix operator.  For
+instance negation (unary minus) in the standard mpf table is
+
+	{ "-", (mpexpr_fun_t) mpf_neg,
+          MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX, 210 },
+
+
+The same operator can exist as a prefix unary and a binary, or as a prefix
+and postfix unary, simply by putting two entries in the table.  While
+parsing the context determines which style is sought.  But note that the
+same operator can't be both a postfix unary and a binary, since the parser
+doesn't try to look ahead to decide which ought to be used.
+
+When there's two entries for an operator, both prefix or both postfix (or
+binary), then the first in the table will be used.  This makes it possible
+to override an entry in a standard table, for example to change the function
+it calls, or perhaps its precedence level.  The following would change mpz
+division from tdiv to cdiv,
+
+        struct mpexpr_operator_t  table[] = {
+          { "/", (mpexpr_fun_t) mpz_cdiv_q, MPEXPR_TYPE_BINARY, 200 },
+          { "%", (mpexpr_fun_t) mpz_cdiv_r, MPEXPR_TYPE_BINARY, 200 },
+          { (char *) mpz_expr_standard_table, NULL, MPEXPR_TYPE_NEW_TABLE }
+        };
+
+
+The type field indicates what parameters the given function expects.  The
+following styles of functions are supported.  mpz_t is shown, but of course
+this is mpq_t for mpq_expr_a, mpf_t for mpf_expr_a, etc.
+
+    MPEXPR_TYPE_CONSTANT     void func (mpz_t result);
+
+    MPEXPR_TYPE_0ARY         void func (mpz_t result);
+    MPEXPR_TYPE_I_0ARY       int func (void);
+
+    MPEXPR_TYPE_UNARY        void func (mpz_t result, mpz_t op);
+    MPEXPR_TYPE_UNARY_UI     void func (mpz_t result, unsigned long op);
+    MPEXPR_TYPE_I_UNARY      int func (mpz_t op);
+    MPEXPR_TYPE_I_UNARY_UI   int func (unsigned long op);
+
+    MPEXPR_TYPE_BINARY       void func (mpz_t result, mpz_t op1, mpz_t op2);
+    MPEXPR_TYPE_BINARY_UI    void func (mpz_t result,
+                                        mpz_t op1, unsigned long op2);
+    MPEXPR_TYPE_I_BINARY     int func (mpz_t op1, mpz_t op2);
+    MPEXPR_TYPE_I_BINARY_UI  int func (mpz_t op1, unsigned long op2);
+
+    MPEXPR_TYPE_TERNARY      void func (mpz_t result,
+                                        mpz_t op1, mpz_t op2, mpz_t op3);
+    MPEXPR_TYPE_TERNARY_UI   void func (mpz_t result, mpz_t op1, mpz_t op2,
+                                        unsigned long op3);
+    MPEXPR_TYPE_I_TERNARY    int func (mpz_t op1, mpz_t op2, mpz_t op3);
+    MPEXPR_TYPE_I_TERNARY_UI int func (mpz_t op1, mpz_t op2,
+                                       unsigned long op3);
+
+Notice the pattern of "UI" for the last parameter as an unsigned long, or
+"I" for the result as an "int" return value.
+
+It's important that the declared type for an operator or function matches
+the function pointer given.  Any mismatch will have unpredictable results.
+
+For binary functions, a further type attribute is MPEXPR_TYPE_PAIRWISE which
+indicates that any number of arguments should be accepted, and evaluated by
+applying the given binary function to them pairwise.  This is used by gcd,
+lcm, min and max.  For example the standard mpz gcd is
+
+	{ "gcd", (mpexpr_fun_t) mpz_gcd,
+	  MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE },
+
+Some special types exist for comparison operators (or functions).
+MPEXPR_TYPE_CMP_LT through MPEXPR_TYPE_CMP_GE expect an MPEXPR_TYPE_I_BINARY
+function, returning positive, negative or zero like mpz_cmp and similar.
+For example the standard mpf "!=" operator is
+
+	{ "!=", (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_CMP_NE, 160 },
+
+But there's no obligation to use these types, for instance the standard mpq
+table just uses a plain MPEXPR_TYPE_I_BINARY and mpq_equal for "==".
+
+Further special types MPEXPR_TYPE_MIN and MPEXPR_TYPE_MAX exist to implement
+the min and max functions, and they take a function like mpf_cmp similarly.
+The standard mpf max function is
+
+	{ "max",  (mpexpr_fun_t) mpf_cmp,
+          MPEXPR_TYPE_MAX | MPEXPR_TYPE_PAIRWISE },
+
+These can be used as operators too, for instance the following would be the
+>? operator which is a feature of GNU C++,
+
+	{ ">?", (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_MAX, 175 },
+
+Other special types are used to define "(" ")" parentheses, "," function
+argument separator, "!" through "||" logical booleans, ternary "?"  ":", and
+the "$" which introduces variables.  See the sources for how they should be
+used.
+
+
+User definable operator tables will have various uses.  For example,
+
+  - a subset of the C operators, to be rid of infrequently used things
+  - a more mathematical syntax like "." for multiply, "^" for powering,
+    and "!" for factorial
+  - a boolean evaluator with "^" for AND, "v" for OR
+  - variables introduced with "%" instead of "$"
+  - brackets as "[" and "]" instead of "(" and ")"
+
+The only fixed parts of the parsing are the treatment of numbers, whitespace
+and the two styles of operator/function name recognition.
+
+As a final example, the following would be a complete mpz table implementing
+some operators with a more mathematical syntax.  Notice there's no need to
+preserve the standard precedence values, anything can be used so long as
+they're in the desired relation to each other.  There's also no need to have
+entries in precedence order, but it's convenient to do so to show what comes
+where.
+
+        static const struct mpexpr_operator_t  table[] = {
+	  { "^",   (mpexpr_fun_t) mpz_pow_ui,
+            MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC,           9 },
+
+          { "!",   (mpexpr_fun_t) mpz_fac_ui, MPEXPR_TYPE_UNARY_UI,   8 },
+          { "-",   (mpexpr_fun_t) mpz_neg,
+            MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                   7 },
+
+          { "*",   (mpexpr_fun_t) mpz_mul,    MPEXPR_TYPE_BINARY,     6 },
+          { "/",   (mpexpr_fun_t) mpz_fdiv_q, MPEXPR_TYPE_BINARY,     6 },
+
+          { "+",   (mpexpr_fun_t) mpz_add,    MPEXPR_TYPE_BINARY,     5 },
+          { "-",   (mpexpr_fun_t) mpz_sub,    MPEXPR_TYPE_BINARY,     5 },
+
+          { "mod", (mpexpr_fun_t) mpz_mod,    MPEXPR_TYPE_BINARY,     6 },
+
+          { ")",   NULL,                      MPEXPR_TYPE_CLOSEPAREN, 4 },
+          { "(",   NULL,                      MPEXPR_TYPE_OPENPAREN,  3 },
+          { ",",   NULL,                      MPEXPR_TYPE_ARGSEP,     2 },
+
+          { "$",   NULL,                      MPEXPR_TYPE_VARIABLE,   1 },
+          { NULL }
+        };
+
+
+
+
+INTERNALS
+
+Operator precedence is implemented using a control and data stack, there's
+no C recursion.  When an expression like 1+2*3 is read the "+" is held on
+the control stack and 1 on the data stack until "*" has been parsed and
+applied to 2 and 3.  This happens any time a higher precedence operator
+follows a lower one, or when a right-associative operator like "**" is
+repeated.
+
+Parentheses are handled by making "(" a special prefix unary with a low
+precedence so a whole following expression is read.  The special operator
+")" knows to discard the pending "(".  Function arguments are handled
+similarly, with the function pretending to be a low precedence prefix unary
+operator, and with "," allowed within functions.  The same special ")"
+operator recognises a pending function and will invoke it appropriately.
+
+The ternary "? :" operator is also handled using precedences.  ":" is one
+level higher than "?", so when a valid a?b:c is parsed the ":" finds a "?"
+on the control stack.  It's a parse error for ":" to find anything else.
+
+
+
+FUTURE
+
+The ternary "?:" operator evaluates the "false" side of its pair, which is
+wasteful, though it ought to be harmless.  It'd be better if it could
+evaluate only the "true" side.  Similarly for the logical booleans "&&" and
+"||" if they know their result already.
+
+Functions like MPEXPR_TYPE_BINARY could return a status indicating operand
+out of range or whatever, to get an error back through mpz_expr etc.  That
+would want to be just an option, since plain mpz_add etc have no such
+return.
+
+Could have assignments like "a = b*c" modifying the input variables.
+Assignment could be an operator attribute, making it expect an lvalue.
+There would want to be a standard table without assignments available
+though, so user input could be safely parsed.
+
+The closing parenthesis table entry could specify the type of open paren it
+expects, so that "(" and ")" could match and "[" and "]" match but not a
+mixture of the two.  Currently "[" and "]" can be added, but there's no
+error on writing a mixed expression like "2*(3+4]".  Maybe also there could
+be a way to say that functions can only be written with one or the other
+style of parens.
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/demos/expr/expr-impl.h b/third_party/gmp/demos/expr/expr-impl.h
new file mode 100644
index 0000000..9b6458f
--- /dev/null
+++ b/third_party/gmp/demos/expr/expr-impl.h
@@ -0,0 +1,125 @@
+/* Implementation specifics for expression evaluation.
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include "expr.h"
+
+
+#define isasciidigit(c)   (isascii (c) && isdigit (c))
+#define isasciicsym(c)    (isascii (c) && (isalnum(c) || (c) == '_'))
+
+#define isasciidigit_in_base(c,base)                    \
+  (isascii (c)                                          \
+   && ((isdigit (c) && (c)-'0' < (base))                \
+       || (isupper (c) && (c)-'A'+10 < (base))          \
+       || (islower (c) && (c)-'a'+10 < (base))))
+
+
+union mpX_t {
+  mpz_t   z;
+  mpq_t   q;
+  mpf_t   f;
+};
+
+typedef union mpX_t *mpX_ptr;
+typedef const union mpX_t *mpX_srcptr;
+
+typedef void (*mpexpr_fun_one_t) (mpX_ptr);
+typedef unsigned long (*mpexpr_fun_ui_one_t) (mpX_ptr);
+
+typedef void (*mpexpr_fun_0ary_t) (mpX_ptr);
+typedef int  (*mpexpr_fun_i_0ary_t) (void);
+
+typedef void (*mpexpr_fun_unary_t) (mpX_ptr, mpX_srcptr);
+typedef void (*mpexpr_fun_unary_ui_t) (mpX_ptr, unsigned long);
+typedef int  (*mpexpr_fun_i_unary_t) (mpX_srcptr);
+typedef int  (*mpexpr_fun_i_unary_ui_t) (unsigned long);
+
+typedef void (*mpexpr_fun_binary_t) (mpX_ptr, mpX_srcptr, mpX_srcptr);
+typedef void (*mpexpr_fun_binary_ui_t) (mpX_ptr, mpX_srcptr, unsigned long);
+typedef int  (*mpexpr_fun_i_binary_t) (mpX_srcptr, mpX_srcptr);
+typedef int  (*mpexpr_fun_i_binary_ui_t) (mpX_srcptr, unsigned long);
+
+typedef void (*mpexpr_fun_ternary_t) (mpX_ptr, mpX_srcptr, mpX_srcptr, mpX_srcptr);
+typedef void (*mpexpr_fun_ternary_ui_t) (mpX_ptr, mpX_srcptr, mpX_srcptr, unsigned long);
+typedef int (*mpexpr_fun_i_ternary_t) (mpX_srcptr, mpX_srcptr, mpX_srcptr);
+typedef int (*mpexpr_fun_i_ternary_ui_t) (mpX_srcptr, mpX_srcptr, unsigned long);
+
+typedef size_t (*mpexpr_fun_number_t) (mpX_ptr, const char *str, size_t len, int base);
+typedef void (*mpexpr_fun_swap_t) (mpX_ptr, mpX_ptr);
+typedef unsigned long (*mpexpr_fun_get_ui_t) (mpX_srcptr);
+typedef void (*mpexpr_fun_set_si_t) (mpX_srcptr, long);
+
+struct mpexpr_control_t {
+  const struct mpexpr_operator_t  *op;
+  int                             argcount;
+};
+
+#define MPEXPR_VARIABLES  26
+
+struct mpexpr_parse_t {
+  const struct mpexpr_operator_t  *table;
+
+  mpX_ptr                         res;
+  int                             base;
+  unsigned long                   prec;
+  const char                      *e;
+  size_t                          elen;
+  mpX_srcptr                      *var;
+  int                             error_code;
+
+  int                             token;
+  const struct mpexpr_operator_t  *token_op;
+
+  union mpX_t                     *data_stack;
+  int                             data_top;
+  int                             data_alloc;
+  int                             data_inited;
+
+  struct mpexpr_control_t         *control_stack;
+  int                             control_top;
+  int                             control_alloc;
+
+  mpexpr_fun_0ary_t               mpX_clear;
+  mpexpr_fun_i_unary_t            mpX_ulong_p;
+  mpexpr_fun_get_ui_t             mpX_get_ui;
+  mpexpr_fun_unary_ui_t           mpX_init;
+  mpexpr_fun_number_t             mpX_number;
+  mpexpr_fun_unary_t              mpX_set;
+  mpexpr_fun_unary_t              mpX_set_or_swap;
+  mpexpr_fun_set_si_t             mpX_set_si;
+  mpexpr_fun_swap_t               mpX_swap;
+};
+
+
+int mpexpr_evaluate (struct mpexpr_parse_t *p);
+int mpexpr_va_to_var (void *var[], va_list ap);
+size_t mpexpr_mpz_number (mpz_ptr res, const char *e, size_t elen, int base);
diff --git a/third_party/gmp/demos/expr/expr.c b/third_party/gmp/demos/expr/expr.c
new file mode 100644
index 0000000..42dd796
--- /dev/null
+++ b/third_party/gmp/demos/expr/expr.c
@@ -0,0 +1,834 @@
+/* mpexpr_evaluate -- shared code for simple expression evaluation
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces.  The trace
+   printfs junk up the code a bit, but it's very hard to tell what's going
+   on without them.  Set MPX_TRACE to a suitable output function for the
+   mpz/mpq/mpf being run (if you have the wrong trace function it'll
+   probably segv).  */
+
+#define TRACE(x)
+#define MPX_TRACE  mpz_trace
+
+
+/* A few helper macros copied from gmp-impl.h */
+#define ALLOCATE_FUNC_TYPE(n,type) \
+  ((type *) (*allocate_func) ((n) * sizeof (type)))
+#define ALLOCATE_FUNC_LIMBS(n)   ALLOCATE_FUNC_TYPE (n, mp_limb_t)
+#define REALLOCATE_FUNC_TYPE(p, old_size, new_size, type) \
+  ((type *) (*reallocate_func)                            \
+   (p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
+#define REALLOCATE_FUNC_LIMBS(p, old_size, new_size) \
+  REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
+#define FREE_FUNC_TYPE(p,n,type) (*free_func) (p, (n) * sizeof (type))
+#define FREE_FUNC_LIMBS(p,n)     FREE_FUNC_TYPE (p, n, mp_limb_t)
+#define ASSERT(x)
+
+
+
+/* All the error strings are just for diagnostic traces.  Only the error
+   code is actually returned.  */
+#define ERROR(str,code)                 \
+  {                                     \
+    TRACE (printf ("%s\n", str));       \
+    p->error_code = (code);             \
+    goto done;                          \
+  }
+
+
+#define REALLOC(ptr, alloc, incr, type)                         \
+  do {                                                          \
+    int  new_alloc = (alloc) + (incr);                          \
+    ptr = REALLOCATE_FUNC_TYPE (ptr, alloc, new_alloc, type);   \
+    (alloc) = new_alloc;                                        \
+  } while (0)
+
+
+/* data stack top element */
+#define SP   (p->data_stack + p->data_top)
+
+/* Make sure there's room for another data element above current top.
+   reallocate_func is fetched for when this macro is used in lookahead(). */
+#define DATA_SPACE()                                                    \
+  do {                                                                  \
+    if (p->data_top + 1 >= p->data_alloc)                               \
+      {                                                                 \
+	void *(*reallocate_func) (void *, size_t, size_t);              \
+	mp_get_memory_functions (NULL, &reallocate_func, NULL);         \
+	TRACE (printf ("grow stack from %d\n", p->data_alloc));         \
+	REALLOC (p->data_stack, p->data_alloc, 20, union mpX_t);        \
+      }                                                                 \
+    ASSERT (p->data_top + 1 <= p->data_inited);                         \
+    if (p->data_top + 1 == p->data_inited)                              \
+      {                                                                 \
+	TRACE (printf ("initialize %d\n", p->data_top + 1));            \
+	(*p->mpX_init) (&p->data_stack[p->data_top + 1], p->prec);      \
+	p->data_inited++;                                               \
+      }                                                                 \
+  } while (0)
+
+#define DATA_PUSH()                             \
+  do {                                          \
+    p->data_top++;                              \
+    ASSERT (p->data_top < p->data_alloc);       \
+    ASSERT (p->data_top < p->data_inited);      \
+  } while (0)
+
+/* the last stack entry is never popped, so top>=0 will be true */
+#define DATA_POP(n)             \
+  do {                          \
+    p->data_top -= (n);         \
+    ASSERT (p->data_top >= 0);  \
+  } while (0)
+
+
+/* lookahead() parses the next token.  Return 1 if successful, with some
+   extra data.  Return 0 if fail, with reason in p->error_code.
+
+   "prefix" is MPEXPR_TYPE_PREFIX if an operator with that attribute is
+   preferred, or 0 if an operator without is preferred. */
+
+#define TOKEN_EOF         -1   /* no extra data */
+#define TOKEN_VALUE       -2   /* pushed onto data stack */
+#define TOKEN_OPERATOR    -3   /* stored in p->token_op */
+#define TOKEN_FUNCTION    -4   /* stored in p->token_op */
+
+#define TOKEN_NAME(n)                           \
+  ((n) == TOKEN_EOF ? "TOKEN_EOF"               \
+   : (n) == TOKEN_VALUE ? "TOKEN_VALUE"         \
+   : (n) == TOKEN_OPERATOR ? "TOKEN_OPERATOR"   \
+   : (n) == TOKEN_VALUE ? "TOKEN_FUNCTION"      \
+   : "UNKNOWN TOKEN")
+
+/* Functions default to being parsed as whole words, operators to match just
+   at the start of the string.  The type flags override this. */
+#define WHOLEWORD(op)                           \
+  (op->precedence == 0                          \
+   ? (! (op->type & MPEXPR_TYPE_OPERATOR))      \
+   :   (op->type & MPEXPR_TYPE_WHOLEWORD))
+
+#define isasciispace(c)   (isascii (c) && isspace (c))
+
+static int
+lookahead (struct mpexpr_parse_t *p, int prefix)
+{
+  const struct mpexpr_operator_t  *op, *op_found;
+  size_t  oplen, oplen_found, wlen;
+  int     i;
+
+  /* skip white space */
+  while (p->elen > 0 && isasciispace (*p->e))
+    p->e++, p->elen--;
+
+  if (p->elen == 0)
+    {
+      TRACE (printf ("lookahead EOF\n"));
+      p->token = TOKEN_EOF;
+      return 1;
+    }
+
+  DATA_SPACE ();
+
+  /* Get extent of whole word. */
+  for (wlen = 0; wlen < p->elen; wlen++)
+    if (! isasciicsym (p->e[wlen]))
+      break;
+
+  TRACE (printf ("lookahead at: \"%.*s\" length %u, word %u\n",
+		 (int) p->elen, p->e, p->elen, wlen));
+
+  op_found = NULL;
+  oplen_found = 0;
+  for (op = p->table; op->name != NULL; op++)
+    {
+      if (op->type == MPEXPR_TYPE_NEW_TABLE)
+	{
+	  printf ("new\n");
+	  op = (struct mpexpr_operator_t *) op->name - 1;
+	  continue;
+	}
+
+      oplen = strlen (op->name);
+      if (! ((WHOLEWORD (op) ? wlen == oplen : p->elen >= oplen)
+	     && memcmp (p->e, op->name, oplen) == 0))
+	continue;
+
+      /* Shorter matches don't replace longer previous ones. */
+      if (op_found && oplen < oplen_found)
+	continue;
+
+      /* On a match of equal length to a previous one, the old match isn't
+	 replaced if it has the preferred prefix, and if it doesn't then
+	 it's not replaced if the new one also doesn't.  */
+      if (op_found && oplen == oplen_found
+	  && ((op_found->type & MPEXPR_TYPE_PREFIX) == prefix
+	      || (op->type & MPEXPR_TYPE_PREFIX) != prefix))
+	continue;
+
+      /* This is now either the first match seen, or a longer than previous
+	 match, or an equal to previous one but with a preferred prefix. */
+      op_found = op;
+      oplen_found = oplen;
+    }
+
+  if (op_found)
+    {
+      p->e += oplen_found, p->elen -= oplen_found;
+
+      if (op_found->type == MPEXPR_TYPE_VARIABLE)
+	{
+	  if (p->elen == 0)
+	    ERROR ("end of string expecting a variable",
+		   MPEXPR_RESULT_PARSE_ERROR);
+	  i = p->e[0] - 'a';
+	  if (i < 0 || i >= MPEXPR_VARIABLES)
+	    ERROR ("bad variable name", MPEXPR_RESULT_BAD_VARIABLE);
+	  goto variable;
+	}
+
+      if (op_found->precedence == 0)
+	{
+	  TRACE (printf ("lookahead function: %s\n", op_found->name));
+	  p->token = TOKEN_FUNCTION;
+	  p->token_op = op_found;
+	  return 1;
+	}
+      else
+	{
+	  TRACE (printf ("lookahead operator: %s\n", op_found->name));
+	  p->token = TOKEN_OPERATOR;
+	  p->token_op = op_found;
+	  return 1;
+	}
+    }
+
+  oplen = (*p->mpX_number) (SP+1, p->e, p->elen, p->base);
+  if (oplen != 0)
+    {
+      p->e += oplen, p->elen -= oplen;
+      p->token = TOKEN_VALUE;
+      DATA_PUSH ();
+      TRACE (MPX_TRACE ("lookahead number", SP));
+      return 1;
+    }
+
+  /* Maybe an unprefixed one character variable */
+  i = p->e[0] - 'a';
+  if (wlen == 1 && i >= 0 && i < MPEXPR_VARIABLES)
+    {
+    variable:
+      p->e++, p->elen--;
+      if (p->var[i] == NULL)
+	ERROR ("NULL variable", MPEXPR_RESULT_BAD_VARIABLE);
+      TRACE (printf ("lookahead variable: var[%d] = ", i);
+	     MPX_TRACE ("", p->var[i]));
+      p->token = TOKEN_VALUE;
+      DATA_PUSH ();
+      (*p->mpX_set) (SP, p->var[i]);
+      return 1;
+    }
+
+  ERROR ("no token matched", MPEXPR_RESULT_PARSE_ERROR);
+
+ done:
+  return 0;
+}
+
+
+/* control stack current top element */
+#define CP   (p->control_stack + p->control_top)
+
+/* make sure there's room for another control element above current top */
+#define CONTROL_SPACE()                                                    \
+  do {                                                                     \
+    if (p->control_top + 1 >= p->control_alloc)                            \
+      {                                                                    \
+	TRACE (printf ("grow control stack from %d\n", p->control_alloc)); \
+	REALLOC (p->control_stack, p->control_alloc, 20,                   \
+		 struct mpexpr_control_t);                                 \
+      }                                                                    \
+  } while (0)
+
+/* Push an operator on the control stack, claiming currently to have the
+   given number of args ready.  Local variable "op" is used in case opptr is
+   a reference through CP.  */
+#define CONTROL_PUSH(opptr,args)                        \
+  do {                                                  \
+    const struct mpexpr_operator_t *op = opptr;		\
+    struct mpexpr_control_t *cp;                        \
+    CONTROL_SPACE ();                                   \
+    p->control_top++;                                   \
+    ASSERT (p->control_top < p->control_alloc);         \
+    cp = CP;                                            \
+    cp->op = op;                                        \
+    cp->argcount = (args);                              \
+    TRACE_CONTROL("control stack push:");               \
+  } while (0)
+
+/* The special operator_done is never popped, so top>=0 will hold. */
+#define CONTROL_POP()                           \
+  do {                                          \
+    p->control_top--;                           \
+    ASSERT (p->control_top >= 0);               \
+    TRACE_CONTROL ("control stack pop:");       \
+  } while (0)
+
+#define TRACE_CONTROL(str)                              \
+  TRACE ({                                              \
+    int  i;                                             \
+    printf ("%s depth %d:", str, p->control_top);       \
+    for (i = 0; i <= p->control_top; i++)               \
+      printf (" \"%s\"(%d)",                            \
+	      p->control_stack[i].op->name,             \
+	      p->control_stack[i].argcount);            \
+    printf ("\n");                                      \
+  });
+
+
+#define LOOKAHEAD(prefix)               \
+  do {                                  \
+    if (! lookahead (p, prefix))        \
+      goto done;                        \
+  } while (0)
+
+#define CHECK_UI(n)                                                     \
+  do {                                                                  \
+    if (! (*p->mpX_ulong_p) (n))                                        \
+      ERROR ("operand doesn't fit ulong", MPEXPR_RESULT_NOT_UI);        \
+  } while (0)
+
+#define CHECK_ARGCOUNT(str,n)                                              \
+  do {                                                                     \
+    if (CP->argcount != (n))                                               \
+      {                                                                    \
+	TRACE (printf ("wrong number of arguments for %s, got %d want %d", \
+		       str, CP->argcount, n));                             \
+	ERROR ("", MPEXPR_RESULT_PARSE_ERROR);                             \
+      }                                                                    \
+  } while (0)
+
+
+/* There's two basic states here.  In both p->token is the next token.
+
+   "another_expr" is when a whole expression should be parsed.  This means a
+   literal or variable value possibly followed by an operator, or a function
+   or prefix operator followed by a further whole expression.
+
+   "another_operator" is when an expression has been parsed and its value is
+   on the top of the data stack (SP) and an optional further postfix or
+   infix operator should be parsed.
+
+   In "another_operator" precedences determine whether to push the operator
+   onto the control stack, or instead go to "apply_control" to reduce the
+   operator currently on top of the control stack.
+
+   When an operator has both a prefix and postfix/infix form, a LOOKAHEAD()
+   for "another_expr" will seek the prefix form, a LOOKAHEAD() for
+   "another_operator" will seek the postfix/infix form.  The grammar is
+   simple enough that the next state is known before reading the next token.
+
+   Argument count checking guards against functions consuming the wrong
+   number of operands from the data stack.  The same checks are applied to
+   operators, but will always pass since a UNARY or BINARY will only ever
+   parse with the correct operands.  */
+
+int
+mpexpr_evaluate (struct mpexpr_parse_t *p)
+{
+  void *(*allocate_func) (size_t);
+  void *(*reallocate_func) (void *, size_t, size_t);
+  void (*free_func) (void *, size_t);
+
+  mp_get_memory_functions (&allocate_func, &reallocate_func, &free_func);
+
+  TRACE (printf ("mpexpr_evaluate() base %d \"%.*s\"\n",
+		 p->base, (int) p->elen, p->e));
+
+  /* "done" is a special sentinel at the bottom of the control stack,
+     precedence -1 is lower than any normal operator.  */
+  {
+    static const struct mpexpr_operator_t  operator_done
+      = { "DONE", NULL, MPEXPR_TYPE_DONE, -1 };
+
+    p->control_alloc = 20;
+    p->control_stack = ALLOCATE_FUNC_TYPE (p->control_alloc,
+					   struct mpexpr_control_t);
+    p->control_top = 0;
+    CP->op = &operator_done;
+    CP->argcount = 1;
+  }
+
+  p->data_inited = 0;
+  p->data_alloc = 20;
+  p->data_stack = ALLOCATE_FUNC_TYPE (p->data_alloc, union mpX_t);
+  p->data_top = -1;
+
+  p->error_code = MPEXPR_RESULT_OK;
+
+
+ another_expr_lookahead:
+  LOOKAHEAD (MPEXPR_TYPE_PREFIX);
+  TRACE (printf ("another expr\n"));
+
+  /*another_expr:*/
+  switch (p->token) {
+  case TOKEN_VALUE:
+    goto another_operator_lookahead;
+
+  case TOKEN_OPERATOR:
+    TRACE (printf ("operator %s\n", p->token_op->name));
+    if (! (p->token_op->type & MPEXPR_TYPE_PREFIX))
+      ERROR ("expected a prefix operator", MPEXPR_RESULT_PARSE_ERROR);
+
+    CONTROL_PUSH (p->token_op, 1);
+    goto another_expr_lookahead;
+
+  case TOKEN_FUNCTION:
+    CONTROL_PUSH (p->token_op, 1);
+
+    if (p->token_op->type & MPEXPR_TYPE_CONSTANT)
+      goto apply_control_lookahead;
+
+    LOOKAHEAD (MPEXPR_TYPE_PREFIX);
+    if (! (p->token == TOKEN_OPERATOR
+	   && p->token_op->type == MPEXPR_TYPE_OPENPAREN))
+      ERROR ("expected open paren for function", MPEXPR_RESULT_PARSE_ERROR);
+
+    TRACE (printf ("open paren for function \"%s\"\n", CP->op->name));
+
+    if ((CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) == MPEXPR_TYPE_NARY(0))
+      {
+	LOOKAHEAD (0);
+	if (! (p->token == TOKEN_OPERATOR
+	       && p->token_op->type == MPEXPR_TYPE_CLOSEPAREN))
+	  ERROR ("expected close paren for 0ary function",
+		 MPEXPR_RESULT_PARSE_ERROR);
+	goto apply_control_lookahead;
+      }
+
+    goto another_expr_lookahead;
+  }
+  ERROR ("unrecognised start of expression", MPEXPR_RESULT_PARSE_ERROR);
+
+
+ another_operator_lookahead:
+  LOOKAHEAD (0);
+ another_operator:
+  TRACE (printf ("another operator maybe: %s\n", TOKEN_NAME(p->token)));
+
+  switch (p->token) {
+  case TOKEN_EOF:
+    goto apply_control;
+
+  case TOKEN_OPERATOR:
+    /* The next operator is compared to the one on top of the control stack.
+       If the next is lower precedence, or the same precedence and not
+       right-associative, then reduce using the control stack and look at
+       the next operator again later.  */
+
+#define PRECEDENCE_TEST_REDUCE(tprec,cprec,ttype,ctype)                 \
+    ((tprec) < (cprec)                                                  \
+     || ((tprec) == (cprec) && ! ((ttype) & MPEXPR_TYPE_RIGHTASSOC)))
+
+    if (PRECEDENCE_TEST_REDUCE (p->token_op->precedence, CP->op->precedence,
+				p->token_op->type,       CP->op->type))
+      {
+	TRACE (printf ("defer operator: %s (prec %d vs %d, type 0x%X)\n",
+		       p->token_op->name,
+		       p->token_op->precedence, CP->op->precedence,
+		       p->token_op->type));
+	goto apply_control;
+      }
+
+    /* An argsep is a binary operator, but is never pushed on the control
+       stack, it just accumulates an extra argument for a function. */
+    if (p->token_op->type == MPEXPR_TYPE_ARGSEP)
+      {
+	if (CP->op->precedence != 0)
+	  ERROR ("ARGSEP not in a function call", MPEXPR_RESULT_PARSE_ERROR);
+
+	TRACE (printf ("argsep for function \"%s\"(%d)\n",
+		       CP->op->name, CP->argcount));
+
+#define IS_PAIRWISE(type)                                               \
+	(((type) & (MPEXPR_TYPE_MASK_ARGCOUNT | MPEXPR_TYPE_PAIRWISE))  \
+	 == (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE))
+
+	if (IS_PAIRWISE (CP->op->type) && CP->argcount >= 2)
+	  {
+	    TRACE (printf ("    will reduce pairwise now\n"));
+	    CP->argcount--;
+	    CONTROL_PUSH (CP->op, 2);
+	    goto apply_control;
+	  }
+
+	CP->argcount++;
+	goto another_expr_lookahead;
+      }
+
+    switch (p->token_op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
+    case MPEXPR_TYPE_NARY(1):
+      /* Postfix unary operators can always be applied immediately.  The
+	 easiest way to do this is just push it on the control stack and go
+	 to the normal control stack reduction code. */
+
+      TRACE (printf ("postfix unary operator: %s\n", p->token_op->name));
+      if (p->token_op->type & MPEXPR_TYPE_PREFIX)
+	ERROR ("prefix unary operator used postfix",
+	       MPEXPR_RESULT_PARSE_ERROR);
+      CONTROL_PUSH (p->token_op, 1);
+      goto apply_control_lookahead;
+
+    case MPEXPR_TYPE_NARY(2):
+      CONTROL_PUSH (p->token_op, 2);
+      goto another_expr_lookahead;
+
+    case MPEXPR_TYPE_NARY(3):
+      CONTROL_PUSH (p->token_op, 1);
+      goto another_expr_lookahead;
+    }
+
+    TRACE (printf ("unrecognised operator \"%s\" type: 0x%X",
+		   CP->op->name, CP->op->type));
+    ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
+    break;
+
+  default:
+    TRACE (printf ("expecting an operator, got token %d", p->token));
+    ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
+  }
+
+
+ apply_control_lookahead:
+  LOOKAHEAD (0);
+ apply_control:
+  /* Apply the top element CP of the control stack.  Data values are SP,
+     SP-1, etc.  Result is left as stack top SP after popping consumed
+     values.
+
+     The use of sp as a duplicate of SP will help compilers that can't
+     otherwise recognise the various uses of SP as common subexpressions.  */
+
+  TRACE (printf ("apply control: nested %d, \"%s\" 0x%X, %d args\n",
+		 p->control_top, CP->op->name, CP->op->type, CP->argcount));
+
+  TRACE (printf ("apply 0x%X-ary\n",
+		 CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT));
+  switch (CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
+  case MPEXPR_TYPE_NARY(0):
+    {
+      mpX_ptr  sp;
+      DATA_SPACE ();
+      DATA_PUSH ();
+      sp = SP;
+      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+      case 0:
+	(* (mpexpr_fun_0ary_t) CP->op->fun) (sp);
+	break;
+      case MPEXPR_TYPE_RESULT_INT:
+	(*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_0ary_t) CP->op->fun) ());
+	break;
+      default:
+	ERROR ("unrecognised 0ary argument calling style",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+    }
+    break;
+
+  case MPEXPR_TYPE_NARY(1):
+    {
+      mpX_ptr  sp = SP;
+      CHECK_ARGCOUNT ("unary", 1);
+      TRACE (MPX_TRACE ("before", sp));
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
+      case 0:
+	/* not a special */
+	break;
+
+      case MPEXPR_TYPE_DONE & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special done\n"));
+	goto done;
+
+      case MPEXPR_TYPE_LOGICAL_NOT & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special logical not\n"));
+	(*p->mpX_set_si)
+	  (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) == 0));
+	goto apply_control_done;
+
+      case MPEXPR_TYPE_CLOSEPAREN & MPEXPR_TYPE_MASK_SPECIAL:
+	CONTROL_POP ();
+	if (CP->op->type == MPEXPR_TYPE_OPENPAREN)
+	  {
+	    TRACE (printf ("close paren matching open paren\n"));
+	    CONTROL_POP ();
+	    goto another_operator;
+	  }
+	if (CP->op->precedence == 0)
+	  {
+	    TRACE (printf ("close paren for function\n"));
+	    goto apply_control;
+	  }
+	ERROR ("unexpected close paren", MPEXPR_RESULT_PARSE_ERROR);
+
+      default:
+	TRACE (printf ("unrecognised special unary operator 0x%X",
+		       CP->op->type & MPEXPR_TYPE_MASK_SPECIAL));
+	ERROR ("", MPEXPR_RESULT_BAD_TABLE);
+      }
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+      case 0:
+	(* (mpexpr_fun_unary_t) CP->op->fun) (sp, sp);
+	break;
+      case MPEXPR_TYPE_LAST_UI:
+	CHECK_UI (sp);
+	(* (mpexpr_fun_unary_ui_t) CP->op->fun)
+	  (sp, (*p->mpX_get_ui) (sp));
+	break;
+      case MPEXPR_TYPE_RESULT_INT:
+	(*p->mpX_set_si)
+	  (sp, (long) (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp));
+	break;
+      case MPEXPR_TYPE_RESULT_INT | MPEXPR_TYPE_LAST_UI:
+	CHECK_UI (sp);
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_unary_ui_t) CP->op->fun)
+	   ((*p->mpX_get_ui) (sp)));
+	break;
+      default:
+	ERROR ("unrecognised unary argument calling style",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+    }
+    break;
+
+  case MPEXPR_TYPE_NARY(2):
+    {
+      mpX_ptr  sp;
+
+      /* pairwise functions are allowed to have just one argument */
+      if ((CP->op->type & MPEXPR_TYPE_PAIRWISE)
+	  && CP->op->precedence == 0
+	  && CP->argcount == 1)
+	goto apply_control_done;
+
+      CHECK_ARGCOUNT ("binary", 2);
+      DATA_POP (1);
+      sp = SP;
+      TRACE (MPX_TRACE ("lhs", sp);
+	     MPX_TRACE ("rhs", sp+1));
+
+      if (CP->op->type & MPEXPR_TYPE_MASK_CMP)
+	{
+	  int  type = CP->op->type;
+	  int  cmp = (* (mpexpr_fun_i_binary_t) CP->op->fun)
+	    (sp, sp+1);
+	  (*p->mpX_set_si)
+	    (sp,
+	     (long)
+	     ((  (cmp  < 0) & ((type & MPEXPR_TYPE_MASK_CMP_LT) != 0))
+	      | ((cmp == 0) & ((type & MPEXPR_TYPE_MASK_CMP_EQ) != 0))
+	      | ((cmp  > 0) & ((type & MPEXPR_TYPE_MASK_CMP_GT) != 0))));
+	  goto apply_control_done;
+	}
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
+      case 0:
+	/* not a special */
+	break;
+
+      case MPEXPR_TYPE_QUESTION & MPEXPR_TYPE_MASK_SPECIAL:
+	ERROR ("'?' without ':'", MPEXPR_RESULT_PARSE_ERROR);
+
+      case MPEXPR_TYPE_COLON & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special colon\n"));
+	CONTROL_POP ();
+	if (CP->op->type != MPEXPR_TYPE_QUESTION)
+	  ERROR ("':' without '?'", MPEXPR_RESULT_PARSE_ERROR);
+
+	CP->argcount--;
+	DATA_POP (1);
+	sp--;
+	TRACE (MPX_TRACE ("query", sp);
+	       MPX_TRACE ("true",  sp+1);
+	       MPX_TRACE ("false", sp+2));
+	(*p->mpX_set)
+	  (sp, (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
+	   ? sp+1 : sp+2);
+	goto apply_control_done;
+
+      case MPEXPR_TYPE_LOGICAL_AND & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special logical and\n"));
+	(*p->mpX_set_si)
+	  (sp,
+	   (long)
+	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
+	    && (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
+	goto apply_control_done;
+
+      case MPEXPR_TYPE_LOGICAL_OR & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special logical and\n"));
+	(*p->mpX_set_si)
+	  (sp,
+	   (long)
+	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
+	    || (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
+	goto apply_control_done;
+
+      case MPEXPR_TYPE_MAX & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special max\n"));
+	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) < 0)
+	  (*p->mpX_swap) (sp, sp+1);
+	goto apply_control_done;
+      case MPEXPR_TYPE_MIN & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special min\n"));
+	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) > 0)
+	  (*p->mpX_swap) (sp, sp+1);
+	goto apply_control_done;
+
+      default:
+	ERROR ("unrecognised special binary operator",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+      case 0:
+	(* (mpexpr_fun_binary_t) CP->op->fun) (sp, sp, sp+1);
+	break;
+      case MPEXPR_TYPE_LAST_UI:
+	CHECK_UI (sp+1);
+	(* (mpexpr_fun_binary_ui_t) CP->op->fun)
+	  (sp, sp, (*p->mpX_get_ui) (sp+1));
+	break;
+      case MPEXPR_TYPE_RESULT_INT:
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1));
+	break;
+      case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
+	CHECK_UI (sp+1);
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_binary_ui_t) CP->op->fun)
+	   (sp, (*p->mpX_get_ui) (sp+1)));
+	break;
+      default:
+	ERROR ("unrecognised binary argument calling style",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+    }
+    break;
+
+  case MPEXPR_TYPE_NARY(3):
+    {
+      mpX_ptr  sp;
+
+      CHECK_ARGCOUNT ("ternary", 3);
+      DATA_POP (2);
+      sp = SP;
+      TRACE (MPX_TRACE ("arg1", sp);
+	     MPX_TRACE ("arg2", sp+1);
+	     MPX_TRACE ("arg3", sp+1));
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+      case 0:
+	(* (mpexpr_fun_ternary_t) CP->op->fun) (sp, sp, sp+1, sp+2);
+	break;
+      case MPEXPR_TYPE_LAST_UI:
+	CHECK_UI (sp+2);
+	(* (mpexpr_fun_ternary_ui_t) CP->op->fun)
+	  (sp, sp, sp+1, (*p->mpX_get_ui) (sp+2));
+	break;
+      case MPEXPR_TYPE_RESULT_INT:
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_ternary_t) CP->op->fun)
+	   (sp, sp+1, sp+2));
+	break;
+      case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
+	CHECK_UI (sp+2);
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_ternary_ui_t) CP->op->fun)
+	   (sp, sp+1, (*p->mpX_get_ui) (sp+2)));
+	break;
+      default:
+	ERROR ("unrecognised binary argument calling style",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+    }
+    break;
+
+  default:
+    TRACE (printf ("unrecognised operator type: 0x%X\n", CP->op->type));
+    ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
+  }
+
+ apply_control_done:
+  TRACE (MPX_TRACE ("result", SP));
+  CONTROL_POP ();
+  goto another_operator;
+
+ done:
+  if (p->error_code == MPEXPR_RESULT_OK)
+    {
+      if (p->data_top != 0)
+	{
+	  TRACE (printf ("data stack want top at 0, got %d\n", p->data_top));
+	  p->error_code = MPEXPR_RESULT_PARSE_ERROR;
+	}
+      else
+	(*p->mpX_set_or_swap) (p->res, SP);
+    }
+
+  {
+    int  i;
+    for (i = 0; i < p->data_inited; i++)
+      {
+	TRACE (printf ("clear %d\n", i));
+	(*p->mpX_clear) (p->data_stack+i);
+      }
+  }
+
+  FREE_FUNC_TYPE (p->data_stack, p->data_alloc, union mpX_t);
+  FREE_FUNC_TYPE (p->control_stack, p->control_alloc, struct mpexpr_control_t);
+
+  return p->error_code;
+}
diff --git a/third_party/gmp/demos/expr/expr.h b/third_party/gmp/demos/expr/expr.h
new file mode 100644
index 0000000..d3b7c77
--- /dev/null
+++ b/third_party/gmp/demos/expr/expr.h
@@ -0,0 +1,142 @@
+/* Header for expression evaluation.
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#ifndef __EXPR_H__
+#define __EXPR_H__
+
+#define MPEXPR_RESULT_OK            0
+#define MPEXPR_RESULT_BAD_VARIABLE  1
+#define MPEXPR_RESULT_BAD_TABLE     2
+#define MPEXPR_RESULT_PARSE_ERROR   3
+#define MPEXPR_RESULT_NOT_UI        4
+
+
+/* basic types */
+#define MPEXPR_TYPE_NARY(n)       ((n) * 0x0100)
+#define MPEXPR_TYPE_MASK_ARGCOUNT MPEXPR_TYPE_NARY(0xF)
+#define MPEXPR_TYPE_0ARY          MPEXPR_TYPE_NARY(0)
+#define MPEXPR_TYPE_UNARY         MPEXPR_TYPE_NARY(1)
+#define MPEXPR_TYPE_BINARY        MPEXPR_TYPE_NARY(2)
+#define MPEXPR_TYPE_TERNARY       MPEXPR_TYPE_NARY(3)
+
+/* options for all */
+#define MPEXPR_TYPE_LAST_UI       0x0010
+#define MPEXPR_TYPE_RESULT_INT    0x0020
+#define MPEXPR_TYPE_MASK_ARGSTYLE 0x0030
+
+#define MPEXPR_TYPE_UNARY_UI     (MPEXPR_TYPE_UNARY   | MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_I_UNARY      (MPEXPR_TYPE_UNARY   | MPEXPR_TYPE_RESULT_INT)
+#define MPEXPR_TYPE_I_UNARY_UI   (MPEXPR_TYPE_I_UNARY | MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_BINARY_UI    (MPEXPR_TYPE_BINARY  | MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_I_BINARY     (MPEXPR_TYPE_BINARY  | MPEXPR_TYPE_RESULT_INT)
+#define MPEXPR_TYPE_I_BINARY_UI  (MPEXPR_TYPE_I_BINARY| MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_TERNARY_UI   (MPEXPR_TYPE_TERNARY | MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_I_TERNARY    (MPEXPR_TYPE_TERNARY | MPEXPR_TYPE_RESULT_INT)
+#define MPEXPR_TYPE_I_TERNARY_UI (MPEXPR_TYPE_I_TERNARY|MPEXPR_TYPE_LAST_UI)
+
+/* 0ary with options */
+#define MPEXPR_TYPE_CONSTANT      (MPEXPR_TYPE_0ARY | 0x0040)
+
+/* unary options */
+#define MPEXPR_TYPE_PREFIX        0x0040
+
+/* binary options */
+#define MPEXPR_TYPE_RIGHTASSOC    0x0040
+#define MPEXPR_TYPE_PAIRWISE      0x0080
+
+#define MPEXPR_TYPE_MASK_SPECIAL  0x000F
+
+/* unary specials */
+#define MPEXPR_TYPE_NEW_TABLE     (MPEXPR_TYPE_UNARY | 0x001)
+#define MPEXPR_TYPE_DONE          (MPEXPR_TYPE_UNARY | 0x002)
+#define MPEXPR_TYPE_VARIABLE      (MPEXPR_TYPE_UNARY | 0x003)
+#define MPEXPR_TYPE_LOGICAL_NOT   (MPEXPR_TYPE_UNARY | 0x004)
+#define MPEXPR_TYPE_CLOSEPAREN    (MPEXPR_TYPE_UNARY | 0x005)
+#define MPEXPR_TYPE_OPENPAREN     (MPEXPR_TYPE_CLOSEPAREN | MPEXPR_TYPE_PREFIX)
+
+/* binary specials */
+#define MPEXPR_TYPE_LOGICAL_AND   (MPEXPR_TYPE_BINARY | 0x001)
+#define MPEXPR_TYPE_LOGICAL_OR    (MPEXPR_TYPE_BINARY | 0x002)
+#define MPEXPR_TYPE_ARGSEP        (MPEXPR_TYPE_BINARY | 0x003)
+#define MPEXPR_TYPE_QUESTION      (MPEXPR_TYPE_BINARY | 0x004)
+#define MPEXPR_TYPE_COLON         (MPEXPR_TYPE_BINARY | 0x005)
+#define MPEXPR_TYPE_MAX           (MPEXPR_TYPE_BINARY | 0x006)
+#define MPEXPR_TYPE_MIN           (MPEXPR_TYPE_BINARY | 0x007)
+#define MPEXPR_TYPE_MASK_CMP      0x008
+#define MPEXPR_TYPE_MASK_CMP_LT   0x001
+#define MPEXPR_TYPE_MASK_CMP_EQ   0x002
+#define MPEXPR_TYPE_MASK_CMP_GT   0x004
+#define MPEXPR_TYPE_CMP_LT       (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_MASK_CMP \
+				  | MPEXPR_TYPE_MASK_CMP_LT)
+#define MPEXPR_TYPE_CMP_EQ       (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_MASK_CMP \
+				  | MPEXPR_TYPE_MASK_CMP_EQ)
+#define MPEXPR_TYPE_CMP_GT       (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_MASK_CMP \
+				  | MPEXPR_TYPE_MASK_CMP_GT)
+#define MPEXPR_TYPE_CMP_LE       (MPEXPR_TYPE_CMP_LT | MPEXPR_TYPE_MASK_CMP_EQ)
+#define MPEXPR_TYPE_CMP_NE       (MPEXPR_TYPE_CMP_LT | MPEXPR_TYPE_MASK_CMP_GT)
+#define MPEXPR_TYPE_CMP_GE       (MPEXPR_TYPE_CMP_GT | MPEXPR_TYPE_MASK_CMP_EQ)
+
+/* parse options */
+#define MPEXPR_TYPE_WHOLEWORD      0x1000
+#define MPEXPR_TYPE_OPERATOR       0x2000
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*mpexpr_fun_t) (void);
+
+struct mpexpr_operator_t {
+  const char   *name;
+  mpexpr_fun_t fun;
+  int          type;
+  int          precedence;
+};
+
+
+int mpf_expr_a (const struct mpexpr_operator_t *, mpf_ptr, int,
+		unsigned long, const char *, size_t, mpf_srcptr [26]);
+int mpf_expr (mpf_ptr, int, const char *, ...);
+
+int mpq_expr_a (const struct mpexpr_operator_t *, mpq_ptr,
+		int, const char *, size_t, mpq_srcptr [26]);
+int mpq_expr (mpq_ptr, int, const char *, ...);
+
+int mpz_expr_a (const struct mpexpr_operator_t *, mpz_ptr, int,
+		const char *, size_t, mpz_srcptr [26]);
+int mpz_expr (mpz_ptr, int, const char *, ...);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/third_party/gmp/demos/expr/exprf.c b/third_party/gmp/demos/expr/exprf.c
new file mode 100644
index 0000000..1f7e21f
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprf.c
@@ -0,0 +1,123 @@
+/* mpf expression evaluation
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces. */
+#define TRACE(x)
+
+
+static int
+e_mpf_sgn (mpf_srcptr x)
+{
+  return mpf_sgn (x);
+}
+
+
+static const struct mpexpr_operator_t  _mpf_expr_standard_table[] = {
+
+  { "**",  (mpexpr_fun_t) mpf_pow_ui,
+    MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC,                   220 },
+
+  { "!",   (mpexpr_fun_t) e_mpf_sgn,
+    MPEXPR_TYPE_LOGICAL_NOT | MPEXPR_TYPE_PREFIX,                     210 },
+  { "-",   (mpexpr_fun_t) mpf_neg,
+    MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                           210 },
+
+  { "*",   (mpexpr_fun_t) mpf_mul,           MPEXPR_TYPE_BINARY,      200 },
+  { "/",   (mpexpr_fun_t) mpf_div,           MPEXPR_TYPE_BINARY,      200 },
+
+  { "+",   (mpexpr_fun_t) mpf_add,           MPEXPR_TYPE_BINARY,      190 },
+  { "-",   (mpexpr_fun_t) mpf_sub,           MPEXPR_TYPE_BINARY,      190 },
+
+  { "<<",  (mpexpr_fun_t) mpf_mul_2exp,      MPEXPR_TYPE_BINARY_UI,   180 },
+  { ">>",  (mpexpr_fun_t) mpf_div_2exp,      MPEXPR_TYPE_BINARY_UI,   180 },
+
+  { "<=",  (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_LE,      170 },
+  { "<",   (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_LT,      170 },
+  { ">=",  (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_GE,      170 },
+  { ">",   (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_GT,      170 },
+
+  { "==",  (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_EQ,      160 },
+  { "!=",  (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_NE,      160 },
+
+  { "&&",  (mpexpr_fun_t) e_mpf_sgn,         MPEXPR_TYPE_LOGICAL_AND, 120 },
+  { "||",  (mpexpr_fun_t) e_mpf_sgn,         MPEXPR_TYPE_LOGICAL_OR,  110 },
+
+  { ":",   NULL,                             MPEXPR_TYPE_COLON,       101 },
+  { "?",   (mpexpr_fun_t) e_mpf_sgn,         MPEXPR_TYPE_QUESTION,    100 },
+
+  { ")",   NULL,                             MPEXPR_TYPE_CLOSEPAREN,    4 },
+  { "(",   NULL,                             MPEXPR_TYPE_OPENPAREN,     3 },
+  { ",",   NULL,                             MPEXPR_TYPE_ARGSEP,        2 },
+  { "$",   NULL,                             MPEXPR_TYPE_VARIABLE,      1 },
+
+  { "abs",      (mpexpr_fun_t) mpf_abs,          MPEXPR_TYPE_UNARY        },
+  { "ceil",     (mpexpr_fun_t) mpf_ceil,         MPEXPR_TYPE_UNARY        },
+  { "cmp",      (mpexpr_fun_t) mpf_cmp,          MPEXPR_TYPE_I_BINARY     },
+  { "eq",       (mpexpr_fun_t) mpf_eq,           MPEXPR_TYPE_I_TERNARY_UI },
+  { "floor",    (mpexpr_fun_t) mpf_floor,        MPEXPR_TYPE_UNARY        },
+  { "integer_p",(mpexpr_fun_t) mpf_integer_p,    MPEXPR_TYPE_I_UNARY      },
+  { "max",   (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_MAX | MPEXPR_TYPE_PAIRWISE },
+  { "min",   (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_MIN | MPEXPR_TYPE_PAIRWISE },
+  { "reldiff",  (mpexpr_fun_t) mpf_reldiff,      MPEXPR_TYPE_BINARY       },
+  { "sgn",      (mpexpr_fun_t) e_mpf_sgn,        MPEXPR_TYPE_I_UNARY      },
+  { "sqrt",     (mpexpr_fun_t) mpf_sqrt,         MPEXPR_TYPE_UNARY        },
+  { "trunc",    (mpexpr_fun_t) mpf_trunc,        MPEXPR_TYPE_UNARY        },
+
+  { NULL }
+};
+
+const struct mpexpr_operator_t * const mpf_expr_standard_table
+= _mpf_expr_standard_table;
+
+
+int
+mpf_expr (mpf_ptr res, int base, const char *e, ...)
+{
+  mpf_srcptr  var[MPEXPR_VARIABLES];
+  va_list     ap;
+  int         ret;
+  va_start (ap, e);
+
+  TRACE (printf ("mpf_expr(): base %d, %s\n", base, e));
+  ret = mpexpr_va_to_var ((void **) var, ap);
+  va_end (ap);
+
+  if (ret != MPEXPR_RESULT_OK)
+    return ret;
+
+  return mpf_expr_a (mpf_expr_standard_table, res, base,
+		     mpf_get_prec (res), e, strlen(e), var);
+}
diff --git a/third_party/gmp/demos/expr/exprfa.c b/third_party/gmp/demos/expr/exprfa.c
new file mode 100644
index 0000000..1918cb5
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprfa.c
@@ -0,0 +1,191 @@
+/* mpf expression evaluation
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Future: Bitwise "&", "|" and "&" could be done, if desired.  Not sure
+   those functions would be much value though.  */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces. */
+#define TRACE(x)
+
+
+static size_t
+e_mpf_number (mpf_ptr res, const char *e, size_t elen, int base)
+{
+  char    *edup;
+  size_t  i, ret, extra=0;
+  int     mant_base, exp_base;
+  void    *(*allocate_func) (size_t);
+  void    (*free_func) (void *, size_t);
+
+  TRACE (printf ("mpf_number base=%d \"%.*s\"\n", base, (int) elen, e));
+
+  /* mpf_set_str doesn't currently accept 0x for hex in base==0, so do it
+     here instead.  FIXME: Would prefer to let mpf_set_str handle this.  */
+  if (base == 0 && elen >= 2 && e[0] == '0' && (e[1] == 'x' || e[1] == 'X'))
+    {
+      base = 16;
+      extra = 2;
+      e += extra;
+      elen -= extra;
+    }
+
+  if (base == 0)
+    mant_base = 10;
+  else if (base < 0)
+    mant_base = -base;
+  else
+    mant_base = base;
+
+  /* exponent in decimal if base is negative */
+  if (base < 0)
+    exp_base = 10;
+  else if (base == 0)
+    exp_base = 10;
+  else
+    exp_base = base;
+
+#define IS_EXPONENT(c) \
+  (c == '@' || (base <= 10 && base >= -10 && (e[i] == 'e' || e[i] == 'E')))
+
+  i = 0;
+  for (;;)
+    {
+      if (i >= elen)
+        goto parsed;
+      if (e[i] == '.')
+        break;
+      if (IS_EXPONENT (e[i]))
+        goto exponent;
+      if (! isasciidigit_in_base (e[i], mant_base))
+        goto parsed;
+      i++;
+    }
+
+  /* fraction */
+  i++;
+  for (;;)
+    {
+      if (i >= elen)
+        goto parsed;
+      if (IS_EXPONENT (e[i]))
+        goto exponent;
+      if (! isasciidigit_in_base (e[i], mant_base))
+        goto parsed;
+      i++;
+    }
+
+ exponent:
+  i++;
+  if (i >= elen)
+    goto parsed;
+  if (e[i] == '-')
+    i++;
+  for (;;)
+    {
+      if (i >= elen)
+        goto parsed;
+      if (! isasciidigit_in_base (e[i], exp_base))
+        break;
+      i++;
+    }
+
+ parsed:
+  TRACE (printf ("  parsed i=%u \"%.*s\"\n", i, (int) i, e));
+
+  mp_get_memory_functions (&allocate_func, NULL, &free_func);
+  edup = (*allocate_func) (i+1);
+  memcpy (edup, e, i);
+  edup[i] = '\0';
+
+  if (mpf_set_str (res, edup, base) == 0)
+    ret = i + extra;
+  else
+    ret = 0;
+
+  (*free_func) (edup, i+1);
+  return ret;
+}
+
+static int
+e_mpf_ulong_p (mpf_srcptr f)
+{
+  return mpf_integer_p (f) && mpf_fits_ulong_p (f);
+}
+
+/* Don't want to change the precision of w, can only do an actual swap when
+   w and x have the same precision.  */
+static void
+e_mpf_set_or_swap (mpf_ptr w, mpf_ptr x)
+{
+  if (mpf_get_prec (w) == mpf_get_prec (x))
+    mpf_swap (w, x);
+  else
+    mpf_set (w, x);
+}
+
+
+int
+mpf_expr_a (const struct mpexpr_operator_t *table,
+            mpf_ptr res, int base, unsigned long prec,
+            const char *e, size_t elen,
+            mpf_srcptr var[26])
+{
+  struct mpexpr_parse_t  p;
+
+  p.table = table;
+  p.res = (mpX_ptr) res;
+  p.base = base;
+  p.prec = prec;
+  p.e = e;
+  p.elen = elen;
+  p.var = (mpX_srcptr *) var;
+
+  p.mpX_clear       = (mpexpr_fun_one_t)      mpf_clear;
+  p.mpX_ulong_p     = (mpexpr_fun_i_unary_t)  e_mpf_ulong_p;
+  p.mpX_get_ui      = (mpexpr_fun_get_ui_t)   mpf_get_ui;
+  p.mpX_init        = (mpexpr_fun_unary_ui_t) mpf_init2;
+  p.mpX_number      = (mpexpr_fun_number_t)   e_mpf_number;
+  p.mpX_set         = (mpexpr_fun_unary_t)    mpf_set;
+  p.mpX_set_or_swap = (mpexpr_fun_unary_t)    e_mpf_set_or_swap;
+  p.mpX_set_si      = (mpexpr_fun_set_si_t)   mpf_set_si;
+  p.mpX_swap        = (mpexpr_fun_swap_t)     mpf_swap;
+
+  return mpexpr_evaluate (&p);
+}
diff --git a/third_party/gmp/demos/expr/exprq.c b/third_party/gmp/demos/expr/exprq.c
new file mode 100644
index 0000000..9643200
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprq.c
@@ -0,0 +1,155 @@
+/* mpq expression evaluation
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces. */
+#define TRACE(x)
+
+
+static void
+e_mpq_pow_ui (mpq_ptr r, mpq_srcptr b, unsigned long e)
+{
+  mpz_pow_ui (mpq_numref(r), mpq_numref(b), e);
+  mpz_pow_ui (mpq_denref(r), mpq_denref(b), e);
+}
+
+/* Wrapped because mpq_sgn is a macro. */
+static int
+e_mpq_sgn (mpq_srcptr x)
+{
+  return mpq_sgn (x);
+}
+
+/* Wrapped because mpq_equal only guarantees a non-zero return, whereas we
+   want 1 or 0 for == and !=. */
+static int
+e_mpq_equal (mpq_srcptr x, mpq_srcptr y)
+{
+  return mpq_equal (x, y) != 0;
+}
+static int
+e_mpq_notequal (mpq_srcptr x, mpq_srcptr y)
+{
+  return ! mpq_equal (x, y);
+}
+
+static void
+e_mpq_num (mpq_ptr w, mpq_srcptr x)
+{
+  if (w != x)
+    mpz_set (mpq_numref(w), mpq_numref(x));
+  mpz_set_ui (mpq_denref(w), 1L);
+}
+static void
+e_mpq_den (mpq_ptr w, mpq_srcptr x)
+{
+  if (w == x)
+    mpz_swap (mpq_numref(w), mpq_denref(w));
+  else
+    mpz_set (mpq_numref(w), mpq_denref(x));
+  mpz_set_ui (mpq_denref(w), 1L);
+}
+
+
+static const struct mpexpr_operator_t  _mpq_expr_standard_table[] = {
+
+  { "**",  (mpexpr_fun_t) e_mpq_pow_ui,
+    MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC,                   220 },
+
+  { "!",   (mpexpr_fun_t) e_mpq_sgn,
+    MPEXPR_TYPE_LOGICAL_NOT | MPEXPR_TYPE_PREFIX,                     210 },
+  { "-",   (mpexpr_fun_t) mpq_neg,
+    MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                           210 },
+
+  { "*",   (mpexpr_fun_t) mpq_mul,           MPEXPR_TYPE_BINARY,      200 },
+  { "/",   (mpexpr_fun_t) mpq_div,           MPEXPR_TYPE_BINARY,      200 },
+
+  { "+",   (mpexpr_fun_t) mpq_add,           MPEXPR_TYPE_BINARY,      190 },
+  { "-",   (mpexpr_fun_t) mpq_sub,           MPEXPR_TYPE_BINARY,      190 },
+
+  { "<<",  (mpexpr_fun_t) mpq_mul_2exp,      MPEXPR_TYPE_BINARY_UI,   180 },
+  { ">>",  (mpexpr_fun_t) mpq_div_2exp,      MPEXPR_TYPE_BINARY_UI,   180 },
+
+  { "<=",  (mpexpr_fun_t) mpq_cmp,           MPEXPR_TYPE_CMP_LE,      170 },
+  { "<",   (mpexpr_fun_t) mpq_cmp,           MPEXPR_TYPE_CMP_LT,      170 },
+  { ">=",  (mpexpr_fun_t) mpq_cmp,           MPEXPR_TYPE_CMP_GE,      170 },
+  { ">",   (mpexpr_fun_t) mpq_cmp,           MPEXPR_TYPE_CMP_GT,      170 },
+
+  { "==",  (mpexpr_fun_t) e_mpq_equal,       MPEXPR_TYPE_I_BINARY,    160 },
+  { "!=",  (mpexpr_fun_t) e_mpq_notequal,    MPEXPR_TYPE_I_BINARY,    160 },
+
+  { "&&",  (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_LOGICAL_AND, 120 },
+  { "||",  (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_LOGICAL_OR,  110 },
+
+  { ":",   NULL,                             MPEXPR_TYPE_COLON,       101 },
+  { "?",   (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_QUESTION,    100 },
+
+  { ")",   (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_CLOSEPAREN,    4 },
+  { "(",   (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_OPENPAREN,     3 },
+  { ",",   (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_ARGSEP,        2 },
+  { "$",   NULL,                             MPEXPR_TYPE_VARIABLE,      1 },
+
+  { "abs",  (mpexpr_fun_t) mpq_abs,          MPEXPR_TYPE_UNARY            },
+  { "cmp",  (mpexpr_fun_t) mpq_cmp,          MPEXPR_TYPE_I_BINARY         },
+  { "den",  (mpexpr_fun_t) e_mpq_den,        MPEXPR_TYPE_UNARY            },
+  { "max",  (mpexpr_fun_t) mpq_cmp,  MPEXPR_TYPE_MAX | MPEXPR_TYPE_PAIRWISE },
+  { "min",  (mpexpr_fun_t) mpq_cmp,  MPEXPR_TYPE_MIN | MPEXPR_TYPE_PAIRWISE },
+  { "num",  (mpexpr_fun_t) e_mpq_num,        MPEXPR_TYPE_UNARY            },
+  { "sgn",  (mpexpr_fun_t) e_mpq_sgn,        MPEXPR_TYPE_I_UNARY          },
+
+  { NULL }
+};
+
+const struct mpexpr_operator_t * const mpq_expr_standard_table
+= _mpq_expr_standard_table;
+
+
+int
+mpq_expr (mpq_ptr res, int base, const char *e, ...)
+{
+  mpq_srcptr  var[MPEXPR_VARIABLES];
+  va_list     ap;
+  int         ret;
+  va_start (ap, e);
+
+  TRACE (printf ("mpq_expr(): base %d, %s\n", base, e));
+  ret = mpexpr_va_to_var ((void **) var, ap);
+  va_end (ap);
+
+  if (ret != MPEXPR_RESULT_OK)
+    return ret;
+
+  return mpq_expr_a (mpq_expr_standard_table, res, base, e, strlen(e), var);
+}
diff --git a/third_party/gmp/demos/expr/exprqa.c b/third_party/gmp/demos/expr/exprqa.c
new file mode 100644
index 0000000..f3b6ecb
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprqa.c
@@ -0,0 +1,100 @@
+/* mpq expression evaluation
+
+Copyright 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include <stdio.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+static int
+e_mpq_ulong_p (mpq_srcptr q)
+{
+  return mpz_fits_ulong_p (mpq_numref (q))
+    && mpz_cmp_ui (mpq_denref (q), 1L) == 0;
+}
+
+/* get value as a ui, on the assumption it fits */
+static int
+e_mpq_get_ui_fits (mpq_srcptr q)
+{
+  return mpz_get_ui (mpq_numref (q));
+}
+
+static void
+e_mpq_set_si1 (mpq_ptr q, long num)
+{
+  mpq_set_si (q, num, 1L);
+}
+
+/* The same as mpz, but putting the result in the numerator.  Negatives and
+   fractions aren't parsed here because '-' and '/' are operators. */
+static size_t
+e_mpq_number (mpq_ptr res, const char *e, size_t elen, int base)
+{
+  mpz_set_ui (mpq_denref (res), 1L);
+  return mpexpr_mpz_number (mpq_numref (res), e, elen, base);
+}
+
+
+/* ignoring prec */
+static void
+e_mpq_init (mpq_ptr q, unsigned long prec)
+{
+  mpq_init (q);
+}
+
+int
+mpq_expr_a (const struct mpexpr_operator_t *table,
+            mpq_ptr res, int base,
+            const char *e, size_t elen,
+            mpq_srcptr var[26])
+{
+  struct mpexpr_parse_t  p;
+
+  p.table = table;
+  p.res = (mpX_ptr) res;
+  p.base = base;
+  p.e = e;
+  p.elen = elen;
+  p.var = (mpX_srcptr *) var;
+
+  p.mpX_clear       = (mpexpr_fun_one_t)      mpq_clear;
+  p.mpX_ulong_p     = (mpexpr_fun_i_unary_t)  e_mpq_ulong_p;
+  p.mpX_get_ui      = (mpexpr_fun_get_ui_t)   e_mpq_get_ui_fits;
+  p.mpX_init        = (mpexpr_fun_unary_ui_t) e_mpq_init;
+  p.mpX_number      = (mpexpr_fun_number_t)   e_mpq_number;
+  p.mpX_set         = (mpexpr_fun_unary_t)    mpq_set;
+  p.mpX_set_or_swap = (mpexpr_fun_unary_t)    mpq_swap;
+  p.mpX_set_si      = (mpexpr_fun_set_si_t)   e_mpq_set_si1;
+  p.mpX_swap        = (mpexpr_fun_swap_t)     mpq_swap;
+
+  return mpexpr_evaluate (&p);
+}
diff --git a/third_party/gmp/demos/expr/exprv.c b/third_party/gmp/demos/expr/exprv.c
new file mode 100644
index 0000000..c25741b
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprv.c
@@ -0,0 +1,57 @@
+/* mpz expression evaluation, simple part */
+
+/*
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+int
+mpexpr_va_to_var (void *var[], va_list ap)
+{
+  int   i = 0;
+  void  *v;
+
+  for (;;)
+    {
+      v = va_arg (ap, void *);
+      if (v == NULL)
+	break;
+      if (i >= MPEXPR_VARIABLES)
+	return MPEXPR_RESULT_BAD_VARIABLE;
+      var[i++] = v;
+    }
+
+  while (i < MPEXPR_VARIABLES)
+    var[i++] = NULL;
+
+  return MPEXPR_RESULT_OK;
+}
diff --git a/third_party/gmp/demos/expr/exprz.c b/third_party/gmp/demos/expr/exprz.c
new file mode 100644
index 0000000..bac1a99
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprz.c
@@ -0,0 +1,206 @@
+/* mpz expression evaluation, simple part
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces. */
+#define TRACE(x)
+
+
+/* These are macros, so need function wrappers. */
+static int
+e_mpz_sgn (mpz_srcptr x)
+{
+  return mpz_sgn (x);
+}
+static int
+e_mpz_odd_p (mpz_srcptr x)
+{
+  return mpz_odd_p (x);
+}
+static int
+e_mpz_even_p (mpz_srcptr x)
+{
+  return mpz_even_p (x);
+}
+
+/* These wrapped because MPEXPR_TYPE_I_ functions are expected to return
+   "int" whereas these return "unsigned long".  */
+static void
+e_mpz_hamdist (mpz_ptr w, mpz_srcptr x, mpz_srcptr y)
+{
+  mpz_set_ui (w, mpz_hamdist (x, y));
+}
+static void
+e_mpz_popcount (mpz_ptr w, mpz_srcptr x)
+{
+  mpz_set_ui (w, mpz_popcount (x));
+}
+static void
+e_mpz_scan0 (mpz_ptr w, mpz_srcptr x, unsigned long start)
+{
+  mpz_set_ui (w, mpz_scan0 (x, start));
+}
+static void
+e_mpz_scan1 (mpz_ptr w, mpz_srcptr x, unsigned long start)
+{
+  mpz_set_ui (w, mpz_scan1 (x, start));
+}
+
+/* These wrapped because they're in-place whereas MPEXPR_TYPE_BINARY_UI
+   expects a separate source and destination.  Actually the parser will
+   normally pass w==x anyway.  */
+static void
+e_mpz_setbit (mpz_ptr w, mpz_srcptr x, unsigned long n)
+{
+  if (w != x)
+    mpz_set (w, x);
+  mpz_setbit (w, n);
+}
+static void
+e_mpz_clrbit (mpz_ptr w, mpz_srcptr x, unsigned long n)
+{
+  if (w != x)
+    mpz_set (w, x);
+  mpz_clrbit (w, n);
+}
+
+static const struct mpexpr_operator_t  _mpz_expr_standard_table[] = {
+
+  { "**",  (mpexpr_fun_t) mpz_pow_ui,
+    MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC,                  220 },
+
+  { "~",   (mpexpr_fun_t) mpz_com,
+    MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                          210 },
+  { "!",   (mpexpr_fun_t) e_mpz_sgn,
+    MPEXPR_TYPE_LOGICAL_NOT | MPEXPR_TYPE_PREFIX,                    210 },
+  { "-",   (mpexpr_fun_t) mpz_neg,
+    MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                          210 },
+
+  { "*",   (mpexpr_fun_t) mpz_mul,          MPEXPR_TYPE_BINARY,      200 },
+  { "/",   (mpexpr_fun_t) mpz_tdiv_q,       MPEXPR_TYPE_BINARY,      200 },
+  { "%",   (mpexpr_fun_t) mpz_tdiv_r,       MPEXPR_TYPE_BINARY,      200 },
+
+  { "+",   (mpexpr_fun_t) mpz_add,          MPEXPR_TYPE_BINARY,      190 },
+  { "-",   (mpexpr_fun_t) mpz_sub,          MPEXPR_TYPE_BINARY,      190 },
+
+  { "<<",  (mpexpr_fun_t) mpz_mul_2exp,     MPEXPR_TYPE_BINARY_UI,   180 },
+  { ">>",  (mpexpr_fun_t) mpz_tdiv_q_2exp,  MPEXPR_TYPE_BINARY_UI,   180 },
+
+  { "<=",  (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_LE,      170 },
+  { "<",   (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_LT,      170 },
+  { ">=",  (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_GE,      170 },
+  { ">",   (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_GT,      170 },
+
+  { "==",  (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_EQ,      160 },
+  { "!=",  (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_NE,      160 },
+
+  { "&",   (mpexpr_fun_t) mpz_and,          MPEXPR_TYPE_BINARY,      150 },
+  { "^",   (mpexpr_fun_t) mpz_xor,          MPEXPR_TYPE_BINARY,      140 },
+  { "|",   (mpexpr_fun_t) mpz_ior,          MPEXPR_TYPE_BINARY,      130 },
+  { "&&",  (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_LOGICAL_AND, 120 },
+  { "||",  (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_LOGICAL_OR,  110 },
+
+  { ":",   NULL,                            MPEXPR_TYPE_COLON,       101 },
+  { "?",   (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_QUESTION,    100 },
+
+  { ")",   NULL,                            MPEXPR_TYPE_CLOSEPAREN,   4 },
+  { "(",   NULL,                            MPEXPR_TYPE_OPENPAREN,    3 },
+  { ",",   NULL,                            MPEXPR_TYPE_ARGSEP,       2 },
+  { "$",   NULL,                            MPEXPR_TYPE_VARIABLE,     1 },
+
+  { "abs",       (mpexpr_fun_t) mpz_abs,           MPEXPR_TYPE_UNARY         },
+  { "bin",       (mpexpr_fun_t) mpz_bin_ui,        MPEXPR_TYPE_BINARY_UI     },
+  { "clrbit",    (mpexpr_fun_t) e_mpz_clrbit,      MPEXPR_TYPE_BINARY_UI     },
+  { "cmp",       (mpexpr_fun_t) mpz_cmp,           MPEXPR_TYPE_I_BINARY      },
+  { "cmpabs",    (mpexpr_fun_t) mpz_cmpabs,        MPEXPR_TYPE_I_BINARY      },
+  { "congruent_p",(mpexpr_fun_t)mpz_congruent_p,   MPEXPR_TYPE_I_TERNARY     },
+  { "divisible_p",(mpexpr_fun_t)mpz_divisible_p,   MPEXPR_TYPE_I_BINARY      },
+  { "even_p",    (mpexpr_fun_t) e_mpz_even_p,      MPEXPR_TYPE_I_UNARY       },
+  { "fib",       (mpexpr_fun_t) mpz_fib_ui,        MPEXPR_TYPE_UNARY_UI      },
+  { "fac",       (mpexpr_fun_t) mpz_fac_ui,        MPEXPR_TYPE_UNARY_UI      },
+  { "gcd",       (mpexpr_fun_t) mpz_gcd,           MPEXPR_TYPE_BINARY
+						   | MPEXPR_TYPE_PAIRWISE    },
+  { "hamdist",   (mpexpr_fun_t) e_mpz_hamdist,     MPEXPR_TYPE_BINARY        },
+  { "invert",    (mpexpr_fun_t) mpz_invert,        MPEXPR_TYPE_BINARY        },
+  { "jacobi",    (mpexpr_fun_t) mpz_jacobi,        MPEXPR_TYPE_I_BINARY      },
+  { "kronecker", (mpexpr_fun_t) mpz_kronecker,     MPEXPR_TYPE_I_BINARY      },
+  { "lcm",       (mpexpr_fun_t) mpz_lcm,           MPEXPR_TYPE_BINARY
+						   | MPEXPR_TYPE_PAIRWISE    },
+  { "lucnum",    (mpexpr_fun_t) mpz_lucnum_ui,     MPEXPR_TYPE_UNARY_UI      },
+  { "max",       (mpexpr_fun_t) mpz_cmp,           MPEXPR_TYPE_MAX
+						   | MPEXPR_TYPE_PAIRWISE    },
+  { "min",       (mpexpr_fun_t) mpz_cmp,           MPEXPR_TYPE_MIN
+						   | MPEXPR_TYPE_PAIRWISE    },
+  { "nextprime", (mpexpr_fun_t) mpz_nextprime,     MPEXPR_TYPE_UNARY         },
+  { "odd_p",     (mpexpr_fun_t) e_mpz_odd_p,       MPEXPR_TYPE_I_UNARY       },
+  { "perfect_power_p", (mpexpr_fun_t)mpz_perfect_power_p, MPEXPR_TYPE_I_UNARY},
+  { "perfect_square_p",(mpexpr_fun_t)mpz_perfect_square_p,MPEXPR_TYPE_I_UNARY},
+  { "popcount",  (mpexpr_fun_t) e_mpz_popcount,    MPEXPR_TYPE_UNARY         },
+  { "powm",      (mpexpr_fun_t) mpz_powm,          MPEXPR_TYPE_TERNARY       },
+  { "probab_prime_p",  (mpexpr_fun_t)mpz_probab_prime_p,  MPEXPR_TYPE_I_UNARY},
+  { "root",      (mpexpr_fun_t) mpz_root,          MPEXPR_TYPE_BINARY_UI     },
+  { "scan0",     (mpexpr_fun_t) e_mpz_scan0,       MPEXPR_TYPE_BINARY_UI     },
+  { "scan1",     (mpexpr_fun_t) e_mpz_scan1,       MPEXPR_TYPE_BINARY_UI     },
+  { "setbit",    (mpexpr_fun_t) e_mpz_setbit,      MPEXPR_TYPE_BINARY_UI     },
+  { "tstbit",    (mpexpr_fun_t) mpz_tstbit,        MPEXPR_TYPE_I_BINARY_UI   },
+  { "sgn",       (mpexpr_fun_t) e_mpz_sgn,         MPEXPR_TYPE_I_UNARY       },
+  { "sqrt",      (mpexpr_fun_t) mpz_sqrt,          MPEXPR_TYPE_UNARY         },
+  { NULL }
+};
+
+/* The table is available globally only through a pointer, so the table size
+   can change without breaking binary compatibility. */
+const struct mpexpr_operator_t * const mpz_expr_standard_table
+= _mpz_expr_standard_table;
+
+
+int
+mpz_expr (mpz_ptr res, int base, const char *e, ...)
+{
+  mpz_srcptr  var[MPEXPR_VARIABLES];
+  va_list     ap;
+  int         ret;
+  va_start (ap, e);
+
+  TRACE (printf ("mpz_expr(): base %d, %s\n", base, e));
+  ret = mpexpr_va_to_var ((void **) var, ap);
+  va_end (ap);
+
+  if (ret != MPEXPR_RESULT_OK)
+    return ret;
+
+  return mpz_expr_a (mpz_expr_standard_table, res, base, e, strlen(e), var);
+}
diff --git a/third_party/gmp/demos/expr/exprza.c b/third_party/gmp/demos/expr/exprza.c
new file mode 100644
index 0000000..eda830d
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprza.c
@@ -0,0 +1,108 @@
+/* mpz expression evaluation
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* No need to parse '-' since that's handled as an operator.
+   This function also by mpq_expr_a, so it's not static.  */
+size_t
+mpexpr_mpz_number (mpz_ptr res, const char *e, size_t elen, int base)
+{
+  char    *edup;
+  size_t  i, ret;
+  int     base_effective = (base == 0 ? 10 : base);
+  void    *(*allocate_func) (size_t);
+  void    (*free_func) (void *, size_t);
+
+  i = 0;
+  if (e[i] == '0')
+    {
+      i++;
+      if (e[i] == 'x' || e[i] == 'b')
+        i++;
+    }
+
+  for ( ; i < elen; i++)
+    if (! isasciidigit_in_base (e[i], base_effective))
+      break;
+
+  mp_get_memory_functions (&allocate_func, NULL, &free_func);
+  edup = (*allocate_func) (i+1);
+  memcpy (edup, e, i);
+  edup[i] = '\0';
+
+  if (mpz_set_str (res, edup, base) == 0)
+    ret = i;
+  else
+    ret = 0;
+
+  (*free_func) (edup, i+1);
+  return ret;
+}
+
+/* ignoring prec */
+static void
+e_mpz_init (mpz_ptr z, unsigned long prec)
+{
+  mpz_init (z);
+}
+
+int
+mpz_expr_a (const struct mpexpr_operator_t *table,
+            mpz_ptr res, int base,
+            const char *e, size_t elen,
+            mpz_srcptr var[26])
+{
+  struct mpexpr_parse_t  p;
+
+  p.table = table;
+  p.res = (mpX_ptr) res;
+  p.base = base;
+  p.e = e;
+  p.elen = elen;
+  p.var = (mpX_srcptr *) var;
+
+  p.mpX_clear       = (mpexpr_fun_one_t)      mpz_clear;
+  p.mpX_ulong_p     = (mpexpr_fun_i_unary_t)  mpz_fits_ulong_p;
+  p.mpX_get_ui      = (mpexpr_fun_get_ui_t)   mpz_get_ui;
+  p.mpX_init        = (mpexpr_fun_unary_ui_t) e_mpz_init;
+  p.mpX_number      = (mpexpr_fun_number_t)   mpexpr_mpz_number;
+  p.mpX_set         = (mpexpr_fun_unary_t)    mpz_set;
+  p.mpX_set_or_swap = (mpexpr_fun_unary_t)    mpz_swap;
+  p.mpX_set_si      = (mpexpr_fun_set_si_t)   mpz_set_si;
+  p.mpX_swap        = (mpexpr_fun_swap_t)     mpz_swap;
+
+  return mpexpr_evaluate (&p);
+}
diff --git a/third_party/gmp/demos/expr/run-expr.c b/third_party/gmp/demos/expr/run-expr.c
new file mode 100644
index 0000000..706b910
--- /dev/null
+++ b/third_party/gmp/demos/expr/run-expr.c
@@ -0,0 +1,242 @@
+/* Demo program to run expression evaluation.
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: ./run-expr [-z] [-q] [-f] [-p prec] [-b base] expression...
+
+   Evaluate each argument as a simple expression.  By default this is in mpz
+   integers, but -q selects mpq or -f selects mpf.  For mpf the float
+   precision can be set with -p.  In all cases the input base can be set
+   with -b, or the default is "0" meaning decimal with "0x" allowed.
+
+   This is a pretty trivial program, it's just an easy way to experiment
+   with the evaluation functions.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp.h"
+#include "expr.h"
+
+
+void
+run_expr (int type, int base, unsigned long prec, char *str)
+{
+  int  outbase = (base == 0 ? 10 : base);
+  int  ret;
+
+  switch (type) {
+  case 'z':
+  default:
+    {
+      mpz_t  res, var_a, var_b;
+
+      mpz_init (res);
+      mpz_init_set_ui (var_a, 55L);
+      mpz_init_set_ui (var_b, 99L);
+
+      ret = mpz_expr (res, base, str, var_a, var_b, NULL);
+      printf ("\"%s\" base %d: ", str, base);
+      if (ret == MPEXPR_RESULT_OK)
+        {
+          printf ("result ");
+          mpz_out_str (stdout, outbase, res);
+          printf ("\n");
+        }
+      else
+        printf ("invalid (return code %d)\n", ret);
+
+      mpz_clear (res);
+      mpz_clear (var_a);
+      mpz_clear (var_b);
+    }
+    break;
+
+  case 'q':
+    {
+      mpq_t  res, var_a, var_b;
+
+      mpq_init (res);
+      mpq_init (var_a);
+      mpq_init (var_b);
+
+      mpq_set_ui (var_a, 55L, 1);
+      mpq_set_ui (var_b, 99L, 1);
+
+      ret = mpq_expr (res, base, str, var_a, var_b, NULL);
+      printf ("\"%s\" base %d: ", str, base);
+      if (ret == MPEXPR_RESULT_OK)
+        {
+          printf ("result ");
+          mpq_out_str (stdout, outbase, res);
+          printf ("\n");
+        }
+      else
+        printf ("invalid (return code %d)\n", ret);
+
+      mpq_clear (res);
+      mpq_clear (var_a);
+      mpq_clear (var_b);
+    }
+    break;
+
+  case 'f':
+    {
+      mpf_t  res, var_a, var_b;
+
+      mpf_init2 (res, prec);
+      mpf_init_set_ui (var_a, 55L);
+      mpf_init_set_ui (var_b, 99L);
+
+      ret = mpf_expr (res, base, str, var_a, var_b, NULL);
+      printf ("\"%s\" base %d: ", str, base);
+      if (ret == MPEXPR_RESULT_OK)
+        {
+          printf ("result ");
+          mpf_out_str (stdout, outbase, (size_t) 0, res);
+          printf ("\n");
+        }
+      else
+        printf ("invalid (return code %d)\n", ret);
+
+      mpf_clear (res);
+      mpf_clear (var_a);
+      mpf_clear (var_b);
+    }
+    break;
+  }
+}
+
+int
+main (int argc, char *argv[])
+{
+  int            type = 'z';
+  int            base = 0;
+  unsigned long  prec = 64;
+  int            seen_expr = 0;
+  int            opt;
+  char           *arg;
+
+  for (;;)
+    {
+      argv++;
+      arg = argv[0];
+      if (arg == NULL)
+        break;
+
+      if (arg[0] == '-')
+        {
+          for (;;)
+            {
+              arg++;
+              opt = arg[0];
+
+              switch (opt) {
+              case '\0':
+                goto end_opt;
+
+              case 'f':
+              case 'q':
+              case 'z':
+                type = opt;
+                break;
+
+              case 'b':
+                arg++;
+                if (arg[0] == '\0')
+                  {
+                    argv++;
+                    arg = argv[0];
+                    if (arg == NULL)
+                      {
+                      need_arg:
+                        fprintf (stderr, "Need argument for -%c\n", opt);
+                        exit (1);
+                      }
+                  }
+                base = atoi (arg);
+                goto end_opt;
+
+              case 'p':
+                arg++;
+                if (arg[0] == '\0')
+                  {
+                    argv++;
+                    arg = argv[0];
+                    if (arg == NULL)
+                      goto need_arg;
+                  }
+                prec = atoi (arg);
+                goto end_opt;
+
+              case '-':
+                arg++;
+                if (arg[0] != '\0')
+                  {
+                    /* no "--foo" options */
+                    fprintf (stderr, "Unrecognised option --%s\n", arg);
+                    exit (1);
+                  }
+                /* stop option interpretation at "--" */
+                for (;;)
+                  {
+                    argv++;
+                    arg = argv[0];
+                    if (arg == NULL)
+                      goto done;
+                    run_expr (type, base, prec, arg);
+                    seen_expr = 1;
+                  }
+
+              default:
+                fprintf (stderr, "Unrecognised option -%c\n", opt);
+                exit (1);
+              }
+            }
+        end_opt:
+          ;
+        }
+      else
+        {
+          run_expr (type, base, prec, arg);
+          seen_expr = 1;
+        }
+    }
+
+ done:
+  if (! seen_expr)
+    {
+      printf ("Usage: %s [-z] [-q] [-f] [-p prec] [-b base] expression...\n", argv[0]);
+      exit (1);
+    }
+
+  return 0;
+}
diff --git a/third_party/gmp/demos/expr/t-expr.c b/third_party/gmp/demos/expr/t-expr.c
new file mode 100644
index 0000000..64fbfab
--- /dev/null
+++ b/third_party/gmp/demos/expr/t-expr.c
@@ -0,0 +1,510 @@
+/* Test expression evaluation (print nothing and exit 0 if successful).
+
+Copyright 2000-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+#include "expr-impl.h"
+
+
+int  option_trace = 0;
+
+
+struct data_t {
+  int         base;
+  const char  *expr;
+  const char  *want;
+};
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+
+/* These data_xxx[] arrays are tables to be tested with one or more of the
+   mp?_t types.  z=mpz_t, q=mpz_t, f=mpf_t.  */
+
+struct data_t  data_zqf[] = {
+
+  /* various deliberately wrong expressions */
+  { 0, "", NULL },
+  { 0, "1+", NULL },
+  { 0, "+2", NULL },
+  { 0, "1,2", NULL },
+  { 0, "foo(1,2)", NULL },
+  { 0, "1+foo", NULL },
+  { 10, "0fff", NULL },
+  { 0, "!", NULL },
+  { 0, "10!", NULL },
+  { 0, "-10!", NULL },
+  { 0, "gcd((4,6))", NULL },
+  { 0, "()", NULL },
+  { 0, "fac(2**1000)", NULL },
+  { 0, "$", NULL },
+  { 0, "$-", NULL },
+
+  /* some basics */
+  { 10, "123", "123" },
+  { 10, "-123", "-123" },
+  { 10, "1+2", "3" },
+  { 10, "1+2+3", "6" },
+  { 10, "1+2*3", "7" },
+  { 10, "3*2+1", "7" },
+  { 10, "$a", "55" },
+  { 10, "b", "99" },
+  { 16, "b", "11" },
+  { 10, "4**3 * 2 + 1", "129" },
+  { 10, "1<2", "1" },
+  { 10, "1>2", "0" },
+
+  { 10, "(123)", "123" },
+
+  { 10, "sgn(-123)", "-1" },
+  { 10, "5-7", "-2" },
+
+  { 0, "cmp(0,0)", "0" },
+  { 0, "cmp(1,0)", "1" },
+  { 0, "cmp(0,1)", "-1" },
+  { 0, "cmp(-1,0)", "-1" },
+  { 0, "cmp(0,-1)", "1" },
+
+  { 10, "0 ? 123 : 456", "456" },
+  { 10, "1 ? 4+5 : 6+7", "9" },
+
+  { 10, "(123)", "123" },
+  { 10, "(2+3)", "5" },
+  { 10, "(4+5)*(5+6)", "99" },
+
+  { 0, "1 << 16", "65536" },
+  { 0, "256 >> 4", "16" },
+  { 0, "-256 >> 4", "-16" },
+
+  { 0, "!1", "0" },
+  { 0, "!9", "0" },
+  { 0, "!0", "1" },
+
+  { 0, "2**2**2", "16" },
+  { 0, "-2**2**2", "-16" },
+
+  { 0, "0x100", "256" },
+  { 10, "0x100", NULL },
+  { 10, "0x 100", NULL },
+
+  { 0, " max ( 1, 2, 3, 4, 5, 6, 7, 8)", "8" },
+  { 0, " max ( 1, 9, 2, 3, 4, 5, 6, 7, 8)", "9" },
+  { 0, " min ( 1, 9, 2, 3, 4, 5, 6, 7, 8)", "1" },
+
+  { 10, "abs(123)",  "123" },
+  { 10, "abs(-123)", "123" },
+  { 10, "abs(0)",    "0" },
+
+  /* filling data stack */
+  { 0, "1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1))))))))))))))", "16" },
+
+  /* filling control stack */
+  { 0, "----------------------------------------------------1", "1" },
+};
+
+
+const struct data_t  data_z[] = {
+  { 0, "divisible_p(333,3)", "1" },
+  { 0, "congruent_p(7,1,3)", "1" },
+
+  { 0, "cmpabs(0,0)", "0" },
+  { 0, "cmpabs(1,0)", "1" },
+  { 0, "cmpabs(0,1)", "-1" },
+  { 0, "cmpabs(-1,0)", "1" },
+  { 0, "cmpabs(0,-1)", "-1" },
+
+  { 0, "odd_p(1)", "1" },
+  { 0, "odd_p(0)", "0" },
+  { 0, "odd_p(-1)", "1" },
+
+  { 0, "even_p(1)", "0" },
+  { 0, "even_p(0)", "1" },
+  { 0, "even_p(-1)", "0" },
+
+  { 0, "fac(0)",  "1" },
+  { 0, "fac(1)",  "1" },
+  { 0, "fac(2)",  "2" },
+  { 0, "fac(3)",  "6" },
+  { 0, "fac(10)", "3628800" },
+
+  { 10, "root(81,4)", "3" },
+
+  { 10, "gcd(4,6)", "2" },
+  { 10, "gcd(4,6,9)", "1" },
+
+  { 10, "powm(3,2,9)", "0" },
+  { 10, "powm(3,2,8)", "1" },
+
+  /* filling data stack */
+  { 0, "1 ? 1 : 1 || 1 && 1 | 1 ^ 1 & 1 == 1 >= 1 << 1 - 1 * 1 ** 1", "1" },
+
+  /* filling control stack */
+  { 0, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1", "1" },
+
+  { 0, "fib(10)", "55" },
+
+  { 0, "setbit(0,5)", "32" },
+  { 0, "clrbit(32,5)", "0" },
+  { 0, "tstbit(32,5)", "1" },
+  { 0, "tstbit(32,4)", "0" },
+  { 0, "scan0(7,0)", "3" },
+  { 0, "scan1(7,0)", "0" },
+};
+
+const struct data_t  data_zq[] = {
+  /* expecting failure */
+  { 0, "1.2", NULL },
+};
+
+const struct data_t  data_q[] = {
+  { 10,  "(1/2 + 1/3 + 1/4 + 1/5 + 1/6)*20", "29" },
+  { 0, "num(5/9)", "5" },
+  { 0, "den(5/9)", "9" },
+};
+
+const struct data_t  data_zf[] = {
+  { 10, "sqrt ( 49 )", "7" },
+  { 10, "sqrt ( 49 ) + 1", "8" },
+  { 10, "sqrt((49))", "7" },
+  { 10, "sqrt((((((((49))))))))", "7" },
+};
+
+const struct data_t  data_f[] = {
+  { 0, "1@10",    "10000000000" },
+  { 0, "1.5@10",  "15000000000" },
+  { 0, "1000@-1", "100" },
+  { 0, "10.00@-1", "1" },
+
+  { 0, "1e10",     "10000000000" },
+  { 0, "1.5e10",   "15000000000" },
+  { 0, "1000e-1",  "100" },
+  { 0, "10.00e-1", "1" },
+
+  { 16, "1@9",  "68719476736" },
+
+  { 16,  "1@10", "18446744073709551616" },
+  { -16, "1@10", "1099511627776" },
+
+  { 0, "ceil(0)",           "0" },
+  { 0, "ceil(0.25)",        "1" },
+  { 0, "ceil(0.5)",         "1" },
+  { 0, "ceil(1.5)",         "2" },
+  { 0, "ceil(-0.5)",        "0" },
+  { 0, "ceil(-1.5)",        "-1" },
+
+  /* only simple cases because mpf_eq currently only works on whole limbs */
+  { 0, "eq(0xFFFFFFFFFFFFFFFF1111111111111111,0xFFFFFFFFFFFFFFFF2222222222222222,64)", "1" },
+  { 0, "eq(0xFFFFFFFFFFFFFFFF1111111111111111,0xFFFFFFFFFFFFFFFF2222222222222222,128)", "0" },
+
+  { 0, "floor(0)",           "0" },
+  { 0, "floor(0.25)",        "0" },
+  { 0, "floor(0.5)",         "0" },
+  { 0, "floor(1.5)",         "1" },
+  { 0, "floor(-0.5)",        "-1" },
+  { 0, "floor(-1.5)",        "-2" },
+
+  { 0, "integer_p(1)",   "1" },
+  { 0, "integer_p(0.5)", "0" },
+
+  { 0, "trunc(0)",           "0" },
+  { 0, "trunc(0.25)",        "0" },
+  { 0, "trunc(0.5)",         "0" },
+  { 0, "trunc(1.5)",         "1" },
+  { 0, "trunc(-0.5)",        "0" },
+  { 0, "trunc(-1.5)",        "-1" },
+};
+
+struct datalist_t {
+  const struct data_t  *data;
+  int                  num;
+};
+
+#define DATALIST(data)  { data, numberof (data) }
+
+struct datalist_t  list_z[] = {
+  DATALIST (data_z),
+  DATALIST (data_zq),
+  DATALIST (data_zf),
+  DATALIST (data_zqf),
+};
+
+struct datalist_t  list_q[] = {
+  DATALIST (data_q),
+  DATALIST (data_zq),
+  DATALIST (data_zqf),
+};
+
+struct datalist_t  list_f[] = {
+  DATALIST (data_zf),
+  DATALIST (data_zqf),
+  DATALIST (data_f),
+};
+
+
+void
+check_z (void)
+{
+  const struct data_t  *data;
+  mpz_t  a, b, got, want;
+  int    l, i, ret;
+
+  mpz_init (got);
+  mpz_init (want);
+  mpz_init_set_ui (a, 55);
+  mpz_init_set_ui (b, 99);
+
+  for (l = 0; l < numberof (list_z); l++)
+    {
+      data = list_z[l].data;
+
+      for (i = 0; i < list_z[l].num; i++)
+        {
+          if (option_trace)
+            printf ("mpz_expr \"%s\"\n", data[i].expr);
+
+          ret = mpz_expr (got, data[i].base, data[i].expr, a, b, NULL);
+
+          if (data[i].want == NULL)
+            {
+              /* expect to fail */
+              if (ret == MPEXPR_RESULT_OK)
+                {
+                  printf ("mpz_expr wrong return value, got %d, expected failure\n", ret);
+                  goto error;
+                }
+            }
+          else
+            {
+              if (mpz_set_str (want, data[i].want, 0) != 0)
+                {
+                  printf ("Cannot parse wanted value string\n");
+                  goto error;
+                }
+              if (ret != MPEXPR_RESULT_OK)
+                {
+                  printf ("mpz_expr failed unexpectedly\n");
+                  printf ("   return value %d\n", ret);
+                  goto error;
+                }
+              if (mpz_cmp (got, want) != 0)
+                {
+                  printf ("mpz_expr wrong result\n");
+                  printf ("   got  "); mpz_out_str (stdout, 10, got);
+                  printf ("\n");
+                  printf ("   want "); mpz_out_str (stdout, 10, want);
+                  printf ("\n");
+                  goto error;
+                }
+            }
+        }
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (got);
+  mpz_clear (want);
+  return;
+
+ error:
+  printf ("   base %d\n", data[i].base);
+  printf ("   expr \"%s\"\n", data[i].expr);
+  if (data[i].want != NULL)
+    printf ("   want \"%s\"\n", data[i].want);
+  abort ();
+}
+
+void
+check_q (void)
+{
+  const struct data_t  *data;
+  mpq_t  a, b, got, want;
+  int    l, i, ret;
+
+  mpq_init (got);
+  mpq_init (want);
+  mpq_init (a);
+  mpq_init (b);
+
+  mpq_set_ui (a, 55, 1);
+  mpq_set_ui (b, 99, 1);
+
+  for (l = 0; l < numberof (list_q); l++)
+    {
+      data = list_q[l].data;
+
+      for (i = 0; i < list_q[l].num; i++)
+        {
+          if (option_trace)
+            printf ("mpq_expr \"%s\"\n", data[i].expr);
+
+          ret = mpq_expr (got, data[i].base, data[i].expr, a, b, NULL);
+
+          if (data[i].want == NULL)
+            {
+              /* expect to fail */
+              if (ret == MPEXPR_RESULT_OK)
+                {
+                  printf ("mpq_expr wrong return value, got %d, expected failure\n", ret);
+                  goto error;
+                }
+            }
+          else
+            {
+              if (mpz_set_str (mpq_numref(want), data[i].want, 0) != 0)
+                {
+                  printf ("Cannot parse wanted value string\n");
+                  goto error;
+                }
+              mpz_set_ui (mpq_denref(want), 1);
+
+              if (ret != MPEXPR_RESULT_OK)
+                {
+                  printf ("mpq_expr failed unexpectedly\n");
+                  printf ("   return value %d\n", ret);
+                  goto error;
+                }
+              if (mpq_cmp (got, want) != 0)
+                {
+                  printf ("mpq_expr wrong result\n");
+                  printf ("   got  "); mpq_out_str (stdout, 10, got);
+                  printf ("\n");
+                  printf ("   want "); mpq_out_str (stdout, 10, want);
+                  printf ("\n");
+                  goto error;
+                }
+            }
+        }
+    }
+  mpq_clear (a);
+  mpq_clear (b);
+  mpq_clear (got);
+  mpq_clear (want);
+  return;
+
+ error:
+  printf ("   base %d\n", data[i].base);
+  printf ("   expr \"%s\"\n", data[i].expr);
+  if (data[i].want != NULL)
+    printf ("   want \"%s\"\n", data[i].want);
+  abort ();
+}
+
+void
+check_f (void)
+{
+  const struct data_t  *data;
+  mpf_t  a, b, got, want;
+  int    l, i, ret;
+
+  mpf_set_default_prec (200L);
+
+  mpf_init (got);
+  mpf_init (want);
+  mpf_init_set_ui (a, 55);
+  mpf_init_set_ui (b, 99);
+
+  for (l = 0; l < numberof (list_f); l++)
+    {
+      data = list_f[l].data;
+
+      for (i = 0; i < list_f[l].num; i++)
+        {
+          if (option_trace)
+            printf ("mpf_expr \"%s\"\n", data[i].expr);
+
+          ret = mpf_expr (got, data[i].base, data[i].expr, a, b, NULL);
+
+          if (data[i].want == NULL)
+            {
+              /* expect to fail */
+              if (ret == MPEXPR_RESULT_OK)
+                {
+                  printf ("mpf_expr wrong return value, got %d, expected failure\n", ret);
+                  goto error;
+                }
+            }
+          else
+            {
+              if (mpf_set_str (want, data[i].want, 0) != 0)
+                {
+                  printf ("Cannot parse wanted value string\n");
+                  goto error;
+                }
+
+              if (ret != MPEXPR_RESULT_OK)
+                {
+                  printf ("mpf_expr failed unexpectedly\n");
+                  printf ("   return value %d\n", ret);
+                  goto error;
+                }
+              if (mpf_cmp (got, want) != 0)
+                {
+                  printf ("mpf_expr wrong result\n");
+                  printf ("   got  "); mpf_out_str (stdout, 10, 20, got);
+                  printf ("\n");
+                  printf ("   want "); mpf_out_str (stdout, 10, 20, want);
+                  printf ("\n");
+                  goto error;
+                }
+            }
+        }
+    }
+  mpf_clear (a);
+  mpf_clear (b);
+  mpf_clear (got);
+  mpf_clear (want);
+  return;
+
+ error:
+  printf ("   base %d\n", data[i].base);
+  printf ("   expr \"%s\"\n", data[i].expr);
+  if (data[i].want != NULL)
+    printf ("   want \"%s\"\n", data[i].want);
+  abort ();
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  if (argc >= 2)
+    option_trace = 1;
+
+  check_z ();
+  check_q ();
+  check_f ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/demos/factorize.c b/third_party/gmp/demos/factorize.c
new file mode 100644
index 0000000..91e6455
--- /dev/null
+++ b/third_party/gmp/demos/factorize.c
@@ -0,0 +1,447 @@
+/* Factoring with Pollard's rho method.
+
+Copyright 1995, 1997-2003, 2005, 2009, 2012, 2015 Free Software
+Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "gmp.h"
+
+static unsigned char primes_diff[] = {
+#define P(a,b,c) a,
+#include "primes.h"
+#undef P
+};
+#define PRIMES_PTAB_ENTRIES (sizeof(primes_diff) / sizeof(primes_diff[0]))
+
+int flag_verbose = 0;
+
+/* Prove primality or run probabilistic tests.  */
+int flag_prove_primality = 1;
+
+/* Number of Miller-Rabin tests to run when not proving primality. */
+#define MR_REPS 25
+
+struct factors
+{
+  mpz_t         *p;
+  unsigned long *e;
+  long nfactors;
+};
+
+void factor (mpz_t, struct factors *);
+
+void
+factor_init (struct factors *factors)
+{
+  factors->p = malloc (1);
+  factors->e = malloc (1);
+  factors->nfactors = 0;
+}
+
+void
+factor_clear (struct factors *factors)
+{
+  int i;
+
+  for (i = 0; i < factors->nfactors; i++)
+    mpz_clear (factors->p[i]);
+
+  free (factors->p);
+  free (factors->e);
+}
+
+void
+factor_insert (struct factors *factors, mpz_t prime)
+{
+  long    nfactors  = factors->nfactors;
+  mpz_t         *p  = factors->p;
+  unsigned long *e  = factors->e;
+  long i, j;
+
+  /* Locate position for insert new or increment e.  */
+  for (i = nfactors - 1; i >= 0; i--)
+    {
+      if (mpz_cmp (p[i], prime) <= 0)
+	break;
+    }
+
+  if (i < 0 || mpz_cmp (p[i], prime) != 0)
+    {
+      p = realloc (p, (nfactors + 1) * sizeof p[0]);
+      e = realloc (e, (nfactors + 1) * sizeof e[0]);
+
+      mpz_init (p[nfactors]);
+      for (j = nfactors - 1; j > i; j--)
+	{
+	  mpz_set (p[j + 1], p[j]);
+	  e[j + 1] = e[j];
+	}
+      mpz_set (p[i + 1], prime);
+      e[i + 1] = 1;
+
+      factors->p = p;
+      factors->e = e;
+      factors->nfactors = nfactors + 1;
+    }
+  else
+    {
+      e[i] += 1;
+    }
+}
+
+void
+factor_insert_ui (struct factors *factors, unsigned long prime)
+{
+  mpz_t pz;
+
+  mpz_init_set_ui (pz, prime);
+  factor_insert (factors, pz);
+  mpz_clear (pz);
+}
+
+
+void
+factor_using_division (mpz_t t, struct factors *factors)
+{
+  mpz_t q;
+  unsigned long int p;
+  int i;
+
+  if (flag_verbose > 0)
+    {
+      printf ("[trial division] ");
+    }
+
+  mpz_init (q);
+
+  p = mpz_scan1 (t, 0);
+  mpz_fdiv_q_2exp (t, t, p);
+  while (p)
+    {
+      factor_insert_ui (factors, 2);
+      --p;
+    }
+
+  p = 3;
+  for (i = 1; i <= PRIMES_PTAB_ENTRIES;)
+    {
+      if (! mpz_divisible_ui_p (t, p))
+	{
+	  p += primes_diff[i++];
+	  if (mpz_cmp_ui (t, p * p) < 0)
+	    break;
+	}
+      else
+	{
+	  mpz_tdiv_q_ui (t, t, p);
+	  factor_insert_ui (factors, p);
+	}
+    }
+
+  mpz_clear (q);
+}
+
+static int
+mp_millerrabin (mpz_srcptr n, mpz_srcptr nm1, mpz_ptr x, mpz_ptr y,
+		mpz_srcptr q, unsigned long int k)
+{
+  unsigned long int i;
+
+  mpz_powm (y, x, q, n);
+
+  if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
+    return 1;
+
+  for (i = 1; i < k; i++)
+    {
+      mpz_powm_ui (y, y, 2, n);
+      if (mpz_cmp (y, nm1) == 0)
+	return 1;
+      if (mpz_cmp_ui (y, 1) == 0)
+	return 0;
+    }
+  return 0;
+}
+
+int
+mp_prime_p (mpz_t n)
+{
+  int k, r, is_prime;
+  mpz_t q, a, nm1, tmp;
+  struct factors factors;
+
+  if (mpz_cmp_ui (n, 1) <= 0)
+    return 0;
+
+  /* We have already casted out small primes. */
+  if (mpz_cmp_ui (n, (long) FIRST_OMITTED_PRIME * FIRST_OMITTED_PRIME) < 0)
+    return 1;
+
+  mpz_inits (q, a, nm1, tmp, NULL);
+
+  /* Precomputation for Miller-Rabin.  */
+  mpz_sub_ui (nm1, n, 1);
+
+  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
+  k = mpz_scan1 (nm1, 0);
+  mpz_tdiv_q_2exp (q, nm1, k);
+
+  mpz_set_ui (a, 2);
+
+  /* Perform a Miller-Rabin test, finds most composites quickly.  */
+  if (!mp_millerrabin (n, nm1, a, tmp, q, k))
+    {
+      is_prime = 0;
+      goto ret2;
+    }
+
+  if (flag_prove_primality)
+    {
+      /* Factor n-1 for Lucas.  */
+      mpz_set (tmp, nm1);
+      factor (tmp, &factors);
+    }
+
+  /* Loop until Lucas proves our number prime, or Miller-Rabin proves our
+     number composite.  */
+  for (r = 0; r < PRIMES_PTAB_ENTRIES; r++)
+    {
+      int i;
+
+      if (flag_prove_primality)
+	{
+	  is_prime = 1;
+	  for (i = 0; i < factors.nfactors && is_prime; i++)
+	    {
+	      mpz_divexact (tmp, nm1, factors.p[i]);
+	      mpz_powm (tmp, a, tmp, n);
+	      is_prime = mpz_cmp_ui (tmp, 1) != 0;
+	    }
+	}
+      else
+	{
+	  /* After enough Miller-Rabin runs, be content. */
+	  is_prime = (r == MR_REPS - 1);
+	}
+
+      if (is_prime)
+	goto ret1;
+
+      mpz_add_ui (a, a, primes_diff[r]);	/* Establish new base.  */
+
+      if (!mp_millerrabin (n, nm1, a, tmp, q, k))
+	{
+	  is_prime = 0;
+	  goto ret1;
+	}
+    }
+
+  fprintf (stderr, "Lucas prime test failure.  This should not happen\n");
+  abort ();
+
+ ret1:
+  if (flag_prove_primality)
+    factor_clear (&factors);
+ ret2:
+  mpz_clears (q, a, nm1, tmp, NULL);
+
+  return is_prime;
+}
+
+void
+factor_using_pollard_rho (mpz_t n, unsigned long a, struct factors *factors)
+{
+  mpz_t x, z, y, P;
+  mpz_t t, t2;
+  unsigned long long k, l, i;
+
+  if (flag_verbose > 0)
+    {
+      printf ("[pollard-rho (%lu)] ", a);
+    }
+
+  mpz_inits (t, t2, NULL);
+  mpz_init_set_si (y, 2);
+  mpz_init_set_si (x, 2);
+  mpz_init_set_si (z, 2);
+  mpz_init_set_ui (P, 1);
+  k = 1;
+  l = 1;
+
+  while (mpz_cmp_ui (n, 1) != 0)
+    {
+      for (;;)
+	{
+	  do
+	    {
+	      mpz_mul (t, x, x);
+	      mpz_mod (x, t, n);
+	      mpz_add_ui (x, x, a);
+
+	      mpz_sub (t, z, x);
+	      mpz_mul (t2, P, t);
+	      mpz_mod (P, t2, n);
+
+	      if (k % 32 == 1)
+		{
+		  mpz_gcd (t, P, n);
+		  if (mpz_cmp_ui (t, 1) != 0)
+		    goto factor_found;
+		  mpz_set (y, x);
+		}
+	    }
+	  while (--k != 0);
+
+	  mpz_set (z, x);
+	  k = l;
+	  l = 2 * l;
+	  for (i = 0; i < k; i++)
+	    {
+	      mpz_mul (t, x, x);
+	      mpz_mod (x, t, n);
+	      mpz_add_ui (x, x, a);
+	    }
+	  mpz_set (y, x);
+	}
+
+    factor_found:
+      do
+	{
+	  mpz_mul (t, y, y);
+	  mpz_mod (y, t, n);
+	  mpz_add_ui (y, y, a);
+
+	  mpz_sub (t, z, y);
+	  mpz_gcd (t, t, n);
+	}
+      while (mpz_cmp_ui (t, 1) == 0);
+
+      mpz_divexact (n, n, t);	/* divide by t, before t is overwritten */
+
+      if (!mp_prime_p (t))
+	{
+	  if (flag_verbose > 0)
+	    {
+	      printf ("[composite factor--restarting pollard-rho] ");
+	    }
+	  factor_using_pollard_rho (t, a + 1, factors);
+	}
+      else
+	{
+	  factor_insert (factors, t);
+	}
+
+      if (mp_prime_p (n))
+	{
+	  factor_insert (factors, n);
+	  break;
+	}
+
+      mpz_mod (x, x, n);
+      mpz_mod (z, z, n);
+      mpz_mod (y, y, n);
+    }
+
+  mpz_clears (P, t2, t, z, x, y, NULL);
+}
+
+void
+factor (mpz_t t, struct factors *factors)
+{
+  factor_init (factors);
+
+  if (mpz_sgn (t) != 0)
+    {
+      factor_using_division (t, factors);
+
+      if (mpz_cmp_ui (t, 1) != 0)
+	{
+	  if (flag_verbose > 0)
+	    {
+	      printf ("[is number prime?] ");
+	    }
+	  if (mp_prime_p (t))
+	    factor_insert (factors, t);
+	  else
+	    factor_using_pollard_rho (t, 1, factors);
+	}
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  mpz_t t;
+  int i, j, k;
+  struct factors factors;
+
+  while (argc > 1)
+    {
+      if (!strcmp (argv[1], "-v"))
+	flag_verbose = 1;
+      else if (!strcmp (argv[1], "-w"))
+	flag_prove_primality = 0;
+      else
+	break;
+
+      argv++;
+      argc--;
+    }
+
+  mpz_init (t);
+  if (argc > 1)
+    {
+      for (i = 1; i < argc; i++)
+	{
+	  mpz_set_str (t, argv[i], 0);
+
+	  gmp_printf ("%Zd:", t);
+	  factor (t, &factors);
+
+	  for (j = 0; j < factors.nfactors; j++)
+	    for (k = 0; k < factors.e[j]; k++)
+	      gmp_printf (" %Zd", factors.p[j]);
+
+	  puts ("");
+	  factor_clear (&factors);
+	}
+    }
+  else
+    {
+      for (;;)
+	{
+	  mpz_inp_str (t, stdin, 0);
+	  if (feof (stdin))
+	    break;
+
+	  gmp_printf ("%Zd:", t);
+	  factor (t, &factors);
+
+	  for (j = 0; j < factors.nfactors; j++)
+	    for (k = 0; k < factors.e[j]; k++)
+	      gmp_printf (" %Zd", factors.p[j]);
+
+	  puts ("");
+	  factor_clear (&factors);
+	}
+    }
+
+  exit (0);
+}
diff --git a/third_party/gmp/demos/isprime.c b/third_party/gmp/demos/isprime.c
new file mode 100644
index 0000000..bf06945
--- /dev/null
+++ b/third_party/gmp/demos/isprime.c
@@ -0,0 +1,69 @@
+/* Classify numbers as probable primes, primes or composites.
+   With -q return true if the following argument is a (probable) prime.
+
+Copyright 1999, 2000, 2002, 2005, 2012 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gmp.h"
+
+char *progname;
+
+void
+print_usage_and_exit ()
+{
+  fprintf (stderr, "usage: %s -q nnn\n", progname);
+  fprintf (stderr, "usage: %s nnn ...\n", progname);
+  exit (-1);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t n;
+  int i;
+
+  progname = argv[0];
+
+  if (argc < 2)
+    print_usage_and_exit ();
+
+  mpz_init (n);
+
+  if (argc == 3 && strcmp (argv[1], "-q") == 0)
+    {
+      if (mpz_set_str (n, argv[2], 0) != 0)
+	print_usage_and_exit ();
+      exit (mpz_probab_prime_p (n, 25) == 0);
+    }
+
+  for (i = 1; i < argc; i++)
+    {
+      int class;
+      if (mpz_set_str (n, argv[i], 0) != 0)
+	print_usage_and_exit ();
+      class = mpz_probab_prime_p (n, 25);
+      mpz_out_str (stdout, 10, n);
+      if (class == 0)
+	puts (" is composite");
+      else if (class == 1)
+	puts (" is a probable prime");
+      else /* class == 2 */
+	puts (" is a prime");
+    }
+  exit (0);
+}
diff --git a/third_party/gmp/demos/perl/GMP.pm b/third_party/gmp/demos/perl/GMP.pm
new file mode 100644
index 0000000..46bc707
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP.pm
@@ -0,0 +1,671 @@
+# GMP perl module
+
+# Copyright 2001-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+# [Note: The above copyright notice is repeated in the documentation section
+# below, in order to get it into man pages etc generated by the various pod
+# conversions.  When changing, be sure to update below too.]
+
+
+# This code is designed to work with perl 5.005, so it and the sub-packages
+# aren't as modern as they could be.
+
+package GMP;
+
+require Symbol;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+
+@EXPORT = qw();
+@EXPORT_OK = qw(version);
+%EXPORT_TAGS = ('all' => [qw(
+                             get_d get_d_2exp get_si get_str integer_p
+                             printf sgn sprintf)],
+		'constants' => [()]);
+Exporter::export_ok_tags('all');
+
+$VERSION = '2.00';
+bootstrap GMP $VERSION;
+
+
+# The format string is cut up into "%" specifiers so GMP types can be
+# passed to GMP::sprintf_internal.  Any "*"s are interpolated before
+# calling sprintf_internal, which saves worrying about variable
+# argument lists there.
+#
+# Because sprintf_internal is only called after the conversion and
+# operand have been checked there won't be any crashes from a bad
+# format string.
+#
+sub sprintf {
+  my $fmt = shift;
+  my $out = '';
+  my ($pre, $dummy, $pat, $rest);
+
+  while (($pre, $dummy, $pat, $rest) = ($fmt =~ /^((%%|[^%])*)(%[- +#.*hlLqv\d]*[bcdfeEgGinopsuxX])(.*)$/s)) {
+
+    $out .= $pre;
+
+    my $pat2 = $pat;    # $pat with "*"s expanded
+    my @params = ();    # arguments per "*"s
+    while ($pat2 =~ /[*]/) {
+      my $arg = shift;
+      $pat2 =~ s/[*]/$arg/;
+      push @params, $arg;
+    }
+
+    if (UNIVERSAL::isa($_[0],"GMP::Mpz")) {
+      if ($pat2 !~ /[dioxX]$/) {
+	die "GMP::sprintf: unsupported output format for mpz: $pat2\n";
+      }
+      $pat2 =~ s/(.)$/Z$1/;
+      $out .= sprintf_internal ($pat2, shift);
+
+    } elsif (UNIVERSAL::isa($_[0],"GMP::Mpq")) {
+      if ($pat2 !~ /[dioxX]$/) {
+	die "GMP::sprintf: unsupported output format for mpq: $pat2\n";
+      }
+      $pat2 =~ s/(.)$/Q$1/;
+      $out .= sprintf_internal ($pat2, shift);
+
+    } elsif (UNIVERSAL::isa($_[0],"GMP::Mpf")) {
+      if ($pat2 !~ /[eEfgG]$/) {
+	die "GMP::sprintf: unsupported output format for mpf: $pat2\n";
+      }
+      $pat2 =~ s/(.)$/F$1/;
+      $out .= sprintf_internal ($pat2, shift);
+
+    } elsif ($pat =~ /n$/) {
+      # do it this way so h, l or V type modifiers are respected, and use a
+      # dummy variable to avoid a warning about discarding the value
+      my $dummy = sprintf "%s$pat", $out, $_[0];
+      shift;
+
+    } else {
+      $out .= sprintf $pat, @params, shift;
+    }
+
+    $fmt = $rest;
+  }
+  $out .= $fmt;
+  return $out;
+}
+
+sub printf {
+  if (ref($_[0]) eq 'GLOB') {
+    my $h = Symbol::qualify_to_ref(shift, caller);
+    print $h GMP::sprintf(@_);
+  } else {
+    print STDOUT GMP::sprintf(@_);
+  }
+}
+
+1;
+__END__
+
+
+
+=head1 NAME
+
+GMP - Perl interface to the GNU Multiple Precision Arithmetic Library
+
+=head1 SYNOPSIS
+
+    use GMP;
+    use GMP::Mpz;
+    use GMP::Mpq;
+    use GMP::Mpf;
+    use GMP::Rand;
+
+=head1 DESCRIPTION
+
+This module provides access to GNU MP arbitrary precision integers,
+rationals and floating point.
+
+No functions are exported from these packages by default, but can be
+selected in the usual way, or the tag :all for everything.
+
+    use GMP::Mpz qw(gcd, lcm);   # just these functions
+    use GMP::Mpq qw(:all);       # everything in mpq
+
+=head2 GMP::Mpz
+
+This class provides arbitrary precision integers.  A new mpz can be
+constructed with C<mpz>.  The initial value can be an integer, float,
+string, mpz, mpq or mpf.  Floats, mpq and mpf will be automatically
+truncated to an integer.
+
+    use GMP::Mpz qw(:all);
+    my $a = mpz(123);
+    my $b = mpz("0xFFFF");
+    my $c = mpz(1.5);       # truncated
+
+The following overloaded operators are available, and corresponding
+assignment forms like C<+=>,
+
+=over 4
+
+=item
+
++ - * / % E<lt>E<lt> E<gt>E<gt> ** & | ^ ! E<lt> E<lt>= == != E<gt> E<gt>=
+E<lt>=E<gt> abs not sqrt
+
+=back
+
+C</> and C<%> round towards zero (as per the C<tdiv> functions in GMP).
+
+The following functions are available, behaving the same as the
+corresponding GMP mpz functions,
+
+=over 4
+
+=item
+
+bin, cdiv, cdiv_2exp, clrbit, combit, congruent_p, congruent_2exp_p,
+divexact, divisible_p, divisible_2exp_p, even_p, fac, fdiv, fdiv_2exp, fib,
+fib2, gcd, gcdext, hamdist, invert, jacobi, kronecker, lcm, lucnum, lucnum2,
+mod, mpz_export, mpz_import, nextprime, odd_p, perfect_power_p,
+perfect_square_p, popcount, powm, probab_prime_p, realloc, remove, root,
+roote, scan0, scan1, setbit, sizeinbase, sqrtrem, tdiv, tdiv_2exp, tstbit
+
+=back
+
+C<cdiv>, C<fdiv> and C<tdiv> and their C<2exp> variants return a
+quotient/remainder pair.  C<fib2> returns a pair F[n] and F[n-1], similarly
+C<lucnum2>.  C<gcd> and C<lcm> accept a variable number of arguments (one or
+more).  C<gcdext> returns a triplet of gcd and two cofactors, for example
+
+    use GMP::Mpz qw(:all);
+    $a = 7257;
+    $b = 10701;
+    ($g, $x, $y) = gcdext ($a, $b);
+    print "gcd($a,$b) is $g, and $g == $a*$x + $b*$y\n";
+
+C<mpz_import> and C<mpz_export> are so named to avoid the C<import> keyword.
+Their parameters are as follows,
+
+    $z = mpz_import ($order, $size, $endian, $nails, $string);
+    $string = mpz_export ($order, $size, $endian, $nails, $z);
+
+The order, size, endian and nails parameters are as per the corresponding C
+functions.  The string input for C<mpz_import> is interpreted as byte data
+and must be a multiple of $size bytes.  C<mpz_export> conversely returns a
+string of byte data, which will be a multiple of $size bytes.
+
+C<invert> returns the inverse, or undef if it doesn't exist.  C<remove>
+returns a remainder/multiplicity pair.  C<root> returns the nth root, and
+C<roote> returns a root/bool pair, the bool indicating whether the root is
+exact.  C<sqrtrem> and C<rootrem> return a root/remainder pair.
+
+C<clrbit>, C<combit> and C<setbit> expect a variable which they can modify,
+it doesn't make sense to pass a literal constant.  Only the given variable
+is modified, if other variables are referencing the same mpz object then a
+new copy is made of it.  If the variable isn't an mpz it will be coerced to
+one.  For instance,
+
+    use GMP::Mpz qw(setbit);
+    setbit (123, 0);  # wrong, don't pass a constant
+    $a = mpz(6);
+    $b = $a;
+    setbit ($a, 0);   # $a becomes 7, $b stays at 6
+
+C<scan0> and C<scan1> return ~0 if no 0 or 1 bit respectively is found.
+
+=head2 GMP::Mpq
+
+This class provides rationals with arbitrary precision numerators and
+denominators.  A new mpq can be constructed with C<mpq>.  The initial value
+can be an integer, float, string, mpz, mpq or mpf, or a pair of integers or
+mpz's.  No precision is lost when converting a float or mpf, the exact value
+is retained.
+
+    use GMP::Mpq qw(:all);
+    $a = mpq();              # zero
+    $b = mpq(0.5);           # gives 1/2
+    $b = mpq(14);            # integer 14
+    $b = mpq(3,4);           # fraction 3/4
+    $b = mpq("7/12");        # fraction 7/12
+    $b = mpq("0xFF/0x100");  # fraction 255/256
+
+When a fraction is given, it should be in the canonical form specified in
+the GMP manual, which is denominator positive, no common factors, and zero
+always represented as 0/1.  If not then C<canonicalize> can be called to put
+it in that form.  For example,
+
+    use GMP::Mpq qw(:all);
+    $q = mpq(21,15);   # eek! common factor 3
+    canonicalize($q);  # get rid of it
+
+The following overloaded operators are available, and corresponding
+assignment forms like C<+=>,
+
+=over 4
+
+=item
+
++ - * / E<lt>E<lt> E<gt>E<gt> ** ! E<lt> E<lt>= == != E<gt> E<gt>=
+E<lt>=E<gt> abs not
+
+=back
+
+The following functions are available,
+
+=over 4
+
+=item
+
+den, inv, num
+
+=back
+
+C<inv> calculates 1/q, as per the corresponding GMP function.  C<num> and
+C<den> return an mpz copy of the numerator or denominator respectively.  In
+the future C<num> and C<den> might give lvalues so the original mpq can be
+modified through them, but this is not done currently.
+
+=head2 GMP::Mpf
+
+This class provides arbitrary precision floating point numbers.  The
+mantissa is an arbitrary user-selected precision and the exponent is a fixed
+size (one machine word).
+
+A new mpf can be constructed with C<mpf>.  The initial value can be an
+integer, float, string, mpz, mpq or mpf.  The second argument specifies the
+desired precision in bits, or if omitted then the default precision is used.
+
+    use GMP::Mpf qw(:all);
+    $a = mpf();         # zero
+    $b = mpf(-7.5);     # default precision
+    $c = mpf(1.5, 500); # 500 bits precision
+    $d = mpf("1.0000000000000001");
+
+The following overloaded operators are available, with the corresponding
+assignment forms like C<+=>,
+
+=over 4
+
+=item
+
++ - * / E<lt>E<lt> E<gt>E<gt> ** ! E<lt> E<lt>= == != E<gt> E<gt>=
+E<lt>=E<gt> abs not sqrt
+
+=back
+
+The following functions are available, behaving the same as the
+corresponding GMP mpf functions,
+
+=over 4
+
+=item
+
+ceil, floor, get_default_prec, get_prec, mpf_eq, set_default_prec, set_prec,
+trunc
+
+=back
+
+C<mpf_eq> is so named to avoid clashing with the perl C<eq> operator.
+
+C<set_prec> expects a variable which it can modify, it doesn't make sense to
+pass a literal constant.  Only the given variable is modified, if other
+variables are referencing the same mpf object then a new copy is made of it.
+If the variable isn't an mpf it will be coerced to one.
+
+Results are the same precision as inputs, or if two mpf's are given to a
+binary operator then the precision of the first is used.  For example,
+
+    use GMP::Mpf qw(mpf);
+    $a = mpf(2.0, 100);
+    $b = mpf(2.0, 500);
+    $c = $a + $b;         # gives 100 bits precision
+
+Mpf to string conversion via "" or the usual string contexts uses C<$#> the
+same as normal float to string conversions, or defaults to C<%.g> if C<$#>
+is not defined.  C<%.g> means all significant digits in the selected
+precision.
+
+=head2 GMP class
+
+The following functions are available in the GMP class,
+
+=over 4
+
+=item
+
+fits_slong_p, get_d, get_d_2exp, get_si, get_str, integer_p, printf, sgn,
+sprintf, version
+
+=back
+
+C<get_d_2exp> accepts any integer, string, float, mpz, mpq or mpf operands
+and returns a float and an integer exponent,
+
+    ($dbl, $exp) = get_d_2exp (mpf ("3.0"));
+    # dbl is 0.75, exp is 2
+
+C<get_str> takes an optional second argument which is the base, defaulting
+to decimal.  A negative base means upper case, as per the C functions.  For
+integer, integer string, mpz or mpq operands a string is returned.
+
+    use GMP qw(:all);
+    use GMP::Mpq qw(:all);
+    print get_str(mpq(-5,8)),"\n";      # -5/8
+    print get_str(255,16),"\n";         # ff
+
+For float, float strings or mpf operands, C<get_str> accepts an optional
+third parameter being how many digits to produce, defaulting to 0 which
+means all digits.  (Only as many digits as can be accurately represented by
+the float precision are ever produced though.)  A string/exponent pair is
+returned, as per the C mpf_get_str function.  For example,
+
+    use GMP qw(:all);
+    use GMP::Mpf qw(:all);
+    ($s, $e) = get_str(111.111111111, 10, 4);
+    printf ".$se$e\n";                  # .1111e3
+    ($s, $e) = get_str(1.625, 10);
+    print "0.$s*10^$e\n";               # 0.1625*10^1
+    ($s, $e) = get_str(mpf(2)**20, 16);
+    printf ".%s@%x\n", $s, $e;          # .1@14
+
+C<printf> and C<sprintf> allow formatted output of GMP types.  mpz and mpq
+values can be used with integer conversions (d, o, x, X) and mpf with float
+conversions (f, e, E, g, G).  All the standard perl printf features are
+available too.  For example,
+
+    use GMP::Mpz qw(mpz);
+    use GMP::Mpf qw(mpf);
+    GMP::printf ("%d %d %s", 123, mpz(2)**128, 'foo');
+    GMP::printf STDERR "%.40f", mpf(1.234);
+
+In perl 5.6.1 it doesn't seem to work to export C<printf>, the plain builtin
+C<printf> is reached unless calls are C<&printf()> style.  Explicit use of
+C<GMP::printf> is suggested.  C<sprintf> doesn't suffer this problem.
+
+    use GMP qw(sprintf);
+    use GMP::Mpq qw(mpq);
+    $s = sprintf "%x", mpq(15,16);
+
+C<version> is not exported by default or by tag :all, calling it as
+C<GMP::version()> is recommended.  It returns the GMP library version
+string, which is not to be confused with the module version number.
+
+The other GMP module functions behave as per the corresponding GMP routines,
+and accept any integer, string, float, mpz, mpq or mpf.  For example,
+
+    use GMP qw(:all);
+    use GMP::Mpz qw(mpz);
+    $z = mpz(123);
+    print sgn($z);    # gives 1
+
+Because each of GMP::Mpz, GMP::Mpq and GMP::Mpf is a sub-class of GMP,
+C<-E<gt>> style calls work too.
+
+    use GMP qw(:all);
+    use GMP::Mpq qw(mpf);
+    $q = mpq(-5,7);
+    if ($q->integer_p())   # false
+      ...
+
+=head2 GMP::Rand
+
+This class provides objects holding an algorithm and state for random number
+generation.  C<randstate> creates a new object, for example,
+
+    use GMP::Rand qw(randstate);
+    $r = randstate();
+    $r = randstate('lc_2exp_size', 64);
+    $r = randstate('lc_2exp', 43840821, 1, 32);
+    $r = randstate('mt');
+    $r = randstate($another_r);
+
+With no parameters this corresponds to the C function
+C<gmp_randinit_default>, and is a compromise between speed and randomness.
+'lc_2exp_size' corresponds to C<gmp_randinit_lc_2exp_size>, 'lc_2exp'
+corresponds to C<gmp_randinit_lc_2exp>, and 'mt' corresponds to
+C<gmp_randinit_mt>.  Or when passed another randstate object, a copy of that
+object is made.
+
+'lc_2exp_size' can fail if the requested size is bigger than the internal
+table provides for, in which case undef is returned.  The maximum size
+currently supported is 128.  The other forms always succeed.
+
+A randstate can be seeded with an integer or mpz, using the C<seed> method.
+/dev/random might be a good source of randomness, or time() or
+Time::HiRes::time() might be adequate, depending on the application.
+
+    $r->seed(time()));
+
+Random numbers can be generated with the following functions,
+
+=over 4
+
+=item
+
+mpf_urandomb, mpz_rrandomb, mpz_urandomb, mpz_urandomm,
+gmp_urandomb_ui, gmp_urandomm_ui
+
+=back
+
+Each constructs a new mpz or mpf and with a distribution per the
+corresponding GMP function.  For example,
+
+    use GMP::Rand (:all);
+    $r = randstate();
+    $a = mpz_urandomb($r,256);         # uniform mpz, 256 bits
+    $b = mpz_urandomm($r,mpz(3)**100); # uniform mpz, 0 to 3**100-1
+    $c = mpz_rrandomb($r,1024);        # special mpz, 1024 bits
+    $f = mpf_urandomb($r,128);         # uniform mpf, 128 bits, 0<=$f<1
+    $f = gmp_urandomm_ui($r,56);       # uniform int, 0 to 55
+
+=head2 Coercion
+
+Arguments to operators and functions are converted as necessary to the
+appropriate type.  For instance C<**> requires an unsigned integer exponent,
+and an mpq argument will be converted, so long as it's an integer in the
+appropriate range.
+
+    use GMP::Mpz (mpz);
+    use GMP::Mpq (mpq);
+    $p = mpz(3) ** mpq(45);   # allowed, 45 is an integer
+
+It's an error if a conversion to an integer or mpz would cause any
+truncation.  For example,
+
+    use GMP::Mpz (mpz);
+    $p = mpz(3) + 1.25;       # not allowed
+    $p = mpz(3) + mpz(1.25);  # allowed, explicit truncation
+
+Comparisons, however, accept any combination of operands and are always done
+exactly.  For example,
+
+    use GMP::Mpz (mpz);
+    print mpz(3) < 3.1;       # true
+
+Variables used on the left of an assignment operator like C<+=> are subject
+to coercion too.  An integer, float or string will change type when an mpz,
+mpq or mpf is applied to it.  For example,
+
+    use GMP::Mpz (mpz);
+    $a = 1;
+    $a += mpz(1234);   # $a becomes an mpz
+
+=head2 Overloading
+
+The rule for binary operators in the C<overload> mechanism is that if both
+operands are class objects then the method from the first is used.  This
+determines the result type when mixing GMP classes.  For example,
+
+    use GMP::Mpz (mpz);
+    use GMP::Mpq (mpq);
+    use GMP::Mpf (mpf);
+    $z = mpz(123);
+    $q = mpq(3,2);
+    $f = mpf(1.375)
+    print $q+$f;     # gives an mpq
+    print $f+$z;     # gives an mpf
+    print $z+$f;     # not allowed, would lose precision
+
+=head2 Constants
+
+A special tag C<:constants> is recognised in the module exports list.  It
+doesn't select any functions, but indicates that perl constants should be
+GMP objects.  This can only be used on one of GMP::Mpz, GMP::Mpq or GMP::Mpf
+at any one time, since they apply different rules.
+
+GMP::Mpz will treat constants as mpz's if they're integers, or ordinary
+floats if not.  For example,
+
+    use GMP::Mpz qw(:constants);
+    print 764861287634126387126378128,"\n";   # an mpz
+    print 1.25,"\n";                          # a float
+
+GMP::Mpq is similar, treating integers as mpq's and leaving floats to the
+normal perl handling.  Something like 3/4 is read as two integer mpq's and a
+division, but that's fine since it gives the intended fraction.
+
+    use GMP::Mpq qw(:constants);
+    print 3/4,"\n";    # an mpq
+    print 1.25,"\n";   # a float
+
+GMP::Mpf will treat all constants as mpf's using the default precision.
+BEGIN blocks can be used to set that precision while the code is parsed.
+For example,
+
+    use GMP::Mpf qw(:constants);
+    BEGIN { GMP::Mpf::set_default_prec(256); }
+    print 1/3;
+    BEGIN { GMP::Mpf::set_default_prec(64); }
+    print 5/7;
+
+A similar special tag :noconstants is recognised to turn off the constants
+feature.  For example,
+
+    use GMP::Mpz qw(:constants);
+    print 438249738748174928193,"\n";   # an mpz
+    use GMP::Mpz qw(:noconstants);
+    print 438249738748174928193,"\n";   # now a float
+
+All three 'integer', 'binary' and 'float' constant methods are captured.
+'float' is captured even for GMP::Mpz and GMP::Mpq since perl by default
+treats integer strings as floats if they don't fit a plain integer.
+
+=head1 SEE ALSO
+
+GMP manual, L<perl>, L<overload>.
+
+=head1 BUGS
+
+In perl 5.005_03 on i386 FreeBSD, the overloaded constants sometimes provoke
+seg faults.  Don't know if that's a perl bug or a GMP module bug, though it
+does seem to go bad before reaching anything in GMP.xs.
+
+There's no way to specify an arbitrary base when converting a string to an
+mpz (or mpq or mpf), only hex or octal with 0x or 0 (for mpz and mpq, but
+not for mpf).
+
+These modules are not reentrant or thread safe, due to the implementation of
+the XSUBs.
+
+Returning a new object from the various functions is convenient, but
+assignment versions could avoid creating new objects.  Perhaps they could be
+named after the C language functions, eg. mpq_inv($q,$q);
+
+It'd be good if C<num> and C<den> gave lvalues so the underlying mpq could
+be manipulated.
+
+C<printf> could usefully accept %b for mpz, mpq and mpf, and perhaps %x for
+mpf too.
+
+C<get_str> returning different style values for integer versus float is a
+bit unfortunate.  With mpz, mpq and mpf objects there's no doubt what it
+will do, but on a plain scalar its action depends on whether the scalar was
+promoted to a float at any stage, and then on the GMP module rules about
+using the integer or float part.
+
+=head1 INTERNALS
+
+In usual perl object style, an mpz is a reference to an object blessed into
+class C<GMP::Mpz>.  The object holds a pointer to the C language C<mpz_t>
+structure.  Similarly for mpq, mpf and randstate.
+
+A free list of mpz and mpq values is kept to avoid repeated initializing and
+clearing when objects are created and destroyed.  This aims to help speed,
+but it's not clear whether it's really needed.
+
+mpf doesn't use a free list because the precision of new objects can be
+different each time.
+
+No interface to C<mpf_set_prec_raw> is provided.  It wouldn't be very useful
+since there's no way to make an operation store its result in a particular
+object.  The plain C<set_prec> is useful though, for truncating to a lower
+precision, or as a sort of directive that subsequent calculations involving
+that variable should use a higher precision.
+
+The overheads of perl dynamic typing (operator dispatch, operand type
+checking or coercion) will mean this interface is slower than using C
+directly.
+
+Some assertion checking is available as a compile-time option.
+
+=head1 COPYRIGHT
+
+Copyright 2001-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+=cut
+
+# Local variables:
+# perl-indent-level: 2
+# fill-column: 76
+# End:
diff --git a/third_party/gmp/demos/perl/GMP.xs b/third_party/gmp/demos/perl/GMP.xs
new file mode 100644
index 0000000..8f5acc9
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP.xs
@@ -0,0 +1,3212 @@
+/* GMP module external subroutines.
+
+Copyright 2001-2003, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+/* Notes:
+
+   Routines are grouped with the alias feature and a table of function
+   pointers where possible, since each xsub routine ends up with quite a bit
+   of code size.  Different combinations of arguments and return values have
+   to be separate though.
+
+   The "INTERFACE:" feature isn't available in perl 5.005 and so isn't used.
+   "ALIAS:" requires a table lookup with CvXSUBANY(cv).any_i32 (which is
+   "ix") whereas "INTERFACE:" would have CvXSUBANY(cv).any_dptr as the
+   function pointer immediately.
+
+   Mixed-type swapped-order assignments like "$a = 123; $a += mpz(456);"
+   invoke the plain overloaded "+", not "+=", which makes life easier.
+
+   mpz_assume etc types are used with the overloaded operators since such
+   operators are always called with a class object as the first argument, we
+   don't need an sv_derived_from() lookup to check.  There's assert()s in
+   MPX_ASSUME() for this though.
+
+   The overload_constant routines reached via overload::constant get 4
+   arguments in perl 5.6, not the 3 as documented.  This is apparently a
+   bug, using "..." lets us ignore the extra one.
+
+   There's only a few "si" functions in gmp, so usually SvIV values get
+   handled with an mpz_set_si into a temporary and then a full precision mpz
+   routine.  This is reasonably efficient.
+
+   Argument types are checked, with a view to preserving all bits in the
+   operand.  Perl is a bit looser in its arithmetic, allowing rounding or
+   truncation to an intended operand type (IV, UV or NV).
+
+   Bugs:
+
+   The memory leak detection attempted in GMP::END() doesn't work when mpz's
+   are created as constants because END() is called before they're
+   destroyed.  What's the right place to hook such a check?
+
+   See the bugs section of GMP.pm too.  */
+
+
+/* Comment this out to get assertion checking. */
+#define NDEBUG
+
+/* Change this to "#define TRACE(x) x" for some diagnostics. */
+#define TRACE(x)
+
+
+#include <assert.h>
+#include <float.h>
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include "patchlevel.h"
+
+#include "gmp.h"
+
+
+/* Perl 5.005 doesn't have SvIsUV, only 5.6 and up.
+   Perl 5.8 has SvUOK, but not 5.6, so we don't use that.  */
+#ifndef SvIsUV
+#define SvIsUV(sv)  0
+#endif
+#ifndef SvUVX
+#define SvUVX(sv)  (croak("GMP: oops, shouldn't be using SvUVX"), 0)
+#endif
+
+
+/* Code which doesn't check anything itself, but exists to support other
+   assert()s.  */
+#ifdef NDEBUG
+#define assert_support(x)
+#else
+#define assert_support(x) x
+#endif
+
+/* LONG_MAX + 1 and ULONG_MAX + 1, as a doubles */
+#define LONG_MAX_P1_AS_DOUBLE   ((double) ((unsigned long) LONG_MAX + 1))
+#define ULONG_MAX_P1_AS_DOUBLE  (2.0 * (double) ((unsigned long) ULONG_MAX/2 + 1))
+
+/* Check for perl version "major.minor".
+   Perl 5.004 doesn't have PERL_REVISION and PERL_VERSION, but that's ok,
+   we're only interested in tests above that.  */
+#if defined (PERL_REVISION) && defined (PERL_VERSION)
+#define PERL_GE(major,minor)                                    \
+    (PERL_REVISION > (major)                                    \
+     || ((major) == PERL_REVISION && PERL_VERSION >= (minor)))
+#else
+#define PERL_GE(major,minor)  (0)
+#endif
+#define PERL_LT(major,minor)  (! PERL_GE(major,minor))
+
+/* sv_derived_from etc in 5.005 took "char *" rather than "const char *".
+   Avoid some compiler warnings by using const only where it works.  */
+#if PERL_LT (5,6)
+#define classconst
+#else
+#define classconst const
+#endif
+
+/* In a MINGW or Cygwin DLL build of gmp, the various gmp functions are
+   given with dllimport directives, which prevents them being used as
+   initializers for constant data.  We give function tables as
+   "static_functable const ...", which is normally "static const", but for
+   mingw expands to just "const" making the table an automatic with a
+   run-time initializer.
+
+   In gcc 3.3.1, the function tables initialized like this end up getting
+   all the __imp__foo values fetched, even though just one or two will be
+   used.  This is wasteful, but probably not too bad.  */
+
+#if defined (__MINGW32__) || defined (__CYGWIN__)
+#define static_functable
+#else
+#define static_functable  static
+#endif
+
+#define GMP_MALLOC_ID  42
+
+static classconst char mpz_class[]  = "GMP::Mpz";
+static classconst char mpq_class[]  = "GMP::Mpq";
+static classconst char mpf_class[]  = "GMP::Mpf";
+static classconst char rand_class[] = "GMP::Rand";
+
+static HV *mpz_class_hv;
+static HV *mpq_class_hv;
+static HV *mpf_class_hv;
+
+assert_support (static long mpz_count = 0;)
+assert_support (static long mpq_count = 0;)
+assert_support (static long mpf_count = 0;)
+assert_support (static long rand_count = 0;)
+
+#define TRACE_ACTIVE()                                                   \
+  assert_support                                                         \
+  (TRACE (printf ("  active %ld mpz, %ld mpq, %ld mpf, %ld randstate\n", \
+                  mpz_count, mpq_count, mpf_count, rand_count)))
+
+
+/* Each "struct mpz_elem" etc is an mpz_t with a link field tacked on the
+   end so they can be held on a linked list.  */
+
+#define CREATE_MPX(type)                                \
+                                                        \
+  /* must have mpz_t etc first, for sprintf below */    \
+  struct type##_elem {                                  \
+    type##_t            m;                              \
+    struct type##_elem  *next;                          \
+  };                                                    \
+  typedef struct type##_elem  *type;                    \
+  typedef struct type##_elem  *type##_assume;           \
+  typedef type##_ptr          type##_coerce;            \
+                                                        \
+  static type type##_freelist = NULL;                   \
+                                                        \
+  static type                                           \
+  new_##type (void)                                     \
+  {                                                     \
+    type p;                                             \
+    TRACE (printf ("new %s\n", type##_class));          \
+    if (type##_freelist != NULL)                        \
+      {                                                 \
+        p = type##_freelist;                            \
+        type##_freelist = type##_freelist->next;        \
+      }                                                 \
+    else                                                \
+      {                                                 \
+        New (GMP_MALLOC_ID, p, 1, struct type##_elem);  \
+        type##_init (p->m);                             \
+      }                                                 \
+    TRACE (printf ("  p=%p\n", p));                     \
+    assert_support (type##_count++);                    \
+    TRACE_ACTIVE ();                                    \
+    return p;                                           \
+  }                                                     \
+
+CREATE_MPX (mpz)
+CREATE_MPX (mpq)
+
+typedef mpf_ptr  mpf;
+typedef mpf_ptr  mpf_assume;
+typedef mpf_ptr  mpf_coerce_st0;
+typedef mpf_ptr  mpf_coerce_def;
+
+
+static mpf
+new_mpf (unsigned long prec)
+{
+  mpf p;
+  New (GMP_MALLOC_ID, p, 1, __mpf_struct);
+  mpf_init2 (p, prec);
+  TRACE (printf ("  mpf p=%p\n", p));
+  assert_support (mpf_count++);
+  TRACE_ACTIVE ();
+  return p;
+}
+
+
+/* tmp_mpf_t records an allocated precision with an mpf_t so changes of
+   precision can be done with just an mpf_set_prec_raw.  */
+
+struct tmp_mpf_struct {
+  mpf_t          m;
+  unsigned long  allocated_prec;
+};
+typedef const struct tmp_mpf_struct  *tmp_mpf_srcptr;
+typedef struct tmp_mpf_struct        *tmp_mpf_ptr;
+typedef struct tmp_mpf_struct        tmp_mpf_t[1];
+
+#define tmp_mpf_init(f)                         \
+  do {                                          \
+    mpf_init (f->m);                            \
+    f->allocated_prec = mpf_get_prec (f->m);    \
+  } while (0)
+
+static void
+tmp_mpf_grow (tmp_mpf_ptr f, unsigned long prec)
+{
+  mpf_set_prec_raw (f->m, f->allocated_prec);
+  mpf_set_prec (f->m, prec);
+  f->allocated_prec = mpf_get_prec (f->m);
+}
+
+#define tmp_mpf_shrink(f)  tmp_mpf_grow (f, 1L)
+
+#define tmp_mpf_set_prec(f,prec)        \
+  do {                                  \
+    if (prec > f->allocated_prec)       \
+      tmp_mpf_grow (f, prec);           \
+    else                                \
+      mpf_set_prec_raw (f->m, prec);    \
+  } while (0)
+
+
+static mpz_t  tmp_mpz_0, tmp_mpz_1, tmp_mpz_2;
+static mpq_t  tmp_mpq_0, tmp_mpq_1;
+static tmp_mpf_t tmp_mpf_0, tmp_mpf_1;
+
+/* for GMP::Mpz::export */
+#define tmp_mpz_4  tmp_mpz_2
+
+
+#define FREE_MPX_FREELIST(p,type)               \
+  do {                                          \
+    TRACE (printf ("free %s\n", type##_class)); \
+    p->next = type##_freelist;                  \
+    type##_freelist = p;                        \
+    assert_support (type##_count--);            \
+    TRACE_ACTIVE ();                            \
+    assert (type##_count >= 0);                 \
+  } while (0)
+
+/* this version for comparison, if desired */
+#define FREE_MPX_NOFREELIST(p,type)             \
+  do {                                          \
+    TRACE (printf ("free %s\n", type##_class)); \
+    type##_clear (p->m);                        \
+    Safefree (p);                               \
+    assert_support (type##_count--);            \
+    TRACE_ACTIVE ();                            \
+    assert (type##_count >= 0);                 \
+  } while (0)
+
+#define free_mpz(z)    FREE_MPX_FREELIST (z, mpz)
+#define free_mpq(q)    FREE_MPX_FREELIST (q, mpq)
+
+
+/* Return a new mortal SV holding the given mpx_ptr pointer.
+   class_hv should be one of mpz_class_hv etc.  */
+#define MPX_NEWMORTAL(mpx_ptr, class_hv)                                \
+    sv_bless (sv_setref_pv (sv_newmortal(), NULL, mpx_ptr), class_hv)
+
+/* Aliases for use in typemaps */
+typedef char           *malloced_string;
+typedef const char     *const_string;
+typedef const char     *const_string_assume;
+typedef char           *string;
+typedef SV             *order_noswap;
+typedef SV             *dummy;
+typedef SV             *SV_copy_0;
+typedef unsigned long  ulong_coerce;
+typedef __gmp_randstate_struct *randstate;
+typedef UV             gmp_UV;
+
+#define SvMPX(s,type)  ((type) SvIV((SV*) SvRV(s)))
+#define SvMPZ(s)       SvMPX(s,mpz)
+#define SvMPQ(s)       SvMPX(s,mpq)
+#define SvMPF(s)       SvMPX(s,mpf)
+#define SvRANDSTATE(s) SvMPX(s,randstate)
+
+#define MPX_ASSUME(x,sv,type)                           \
+  do {                                                  \
+    assert (sv_derived_from (sv, type##_class));        \
+    x = SvMPX(sv,type);                                 \
+  } while (0)
+
+#define MPZ_ASSUME(z,sv)    MPX_ASSUME(z,sv,mpz)
+#define MPQ_ASSUME(q,sv)    MPX_ASSUME(q,sv,mpq)
+#define MPF_ASSUME(f,sv)    MPX_ASSUME(f,sv,mpf)
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+#define SGN(x)       ((x)<0 ? -1 : (x) != 0)
+#define ABS(x)       ((x)>=0 ? (x) : -(x))
+#define double_integer_p(d)  (floor (d) == (d))
+
+#define x_mpq_integer_p(q) \
+  (mpz_cmp_ui (mpq_denref(q), 1L) == 0)
+
+#define assert_table(ix)  assert (ix >= 0 && ix < numberof (table))
+
+#define SV_PTR_SWAP(x,y) \
+  do { SV *__tmp = (x); (x) = (y); (y) = __tmp; } while (0)
+#define MPF_PTR_SWAP(x,y) \
+  do { mpf_ptr __tmp = (x); (x) = (y); (y) = __tmp; } while (0)
+
+
+static void
+class_or_croak (SV *sv, classconst char *cl)
+{
+  if (! sv_derived_from (sv, cl))
+    croak("not type %s", cl);
+}
+
+
+/* These are macros, wrap them in functions. */
+static int
+x_mpz_odd_p (mpz_srcptr z)
+{
+  return mpz_odd_p (z);
+}
+static int
+x_mpz_even_p (mpz_srcptr z)
+{
+  return mpz_even_p (z);
+}
+
+static void
+x_mpq_pow_ui (mpq_ptr r, mpq_srcptr b, unsigned long e)
+{
+  mpz_pow_ui (mpq_numref(r), mpq_numref(b), e);
+  mpz_pow_ui (mpq_denref(r), mpq_denref(b), e);
+}
+
+
+static void *
+my_gmp_alloc (size_t n)
+{
+  void *p;
+  TRACE (printf ("my_gmp_alloc %u\n", n));
+  New (GMP_MALLOC_ID, p, n, char);
+  TRACE (printf ("  p=%p\n", p));
+  return p;
+}
+
+static void *
+my_gmp_realloc (void *p, size_t oldsize, size_t newsize)
+{
+  TRACE (printf ("my_gmp_realloc %p, %u to %u\n", p, oldsize, newsize));
+  Renew (p, newsize, char);
+  TRACE (printf ("  p=%p\n", p));
+  return p;
+}
+
+static void
+my_gmp_free (void *p, size_t n)
+{
+  TRACE (printf ("my_gmp_free %p %u\n", p, n));
+  Safefree (p);
+}
+
+
+#define my_mpx_set_svstr(type)                                  \
+  static void                                                   \
+  my_##type##_set_svstr (type##_ptr x, SV *sv)                  \
+  {                                                             \
+    const char  *str;                                           \
+    STRLEN      len;                                            \
+    TRACE (printf ("  my_" #type "_set_svstr\n"));              \
+    assert (SvPOK(sv) || SvPOKp(sv));                           \
+    str = SvPV (sv, len);                                       \
+    TRACE (printf ("  str \"%s\"\n", str));                     \
+    if (type##_set_str (x, str, 0) != 0)                        \
+      croak ("%s: invalid string: %s", type##_class, str);      \
+  }
+
+my_mpx_set_svstr(mpz)
+my_mpx_set_svstr(mpq)
+my_mpx_set_svstr(mpf)
+
+
+/* very slack */
+static int
+x_mpq_cmp_si (mpq_srcptr x, long yn, unsigned long yd)
+{
+  mpq  y;
+  int  ret;
+  y = new_mpq ();
+  mpq_set_si (y->m, yn, yd);
+  ret = mpq_cmp (x, y->m);
+  free_mpq (y);
+  return ret;
+}
+
+static int
+x_mpq_fits_slong_p (mpq_srcptr q)
+{
+  return x_mpq_cmp_si (q, LONG_MIN, 1L) >= 0
+    && mpq_cmp_ui (q, LONG_MAX, 1L) <= 0;
+}
+
+static int
+x_mpz_cmp_q (mpz_ptr x, mpq_srcptr y)
+{
+  int  ret;
+  mpz_set_ui (mpq_denref(tmp_mpq_0), 1L);
+  mpz_swap (mpq_numref(tmp_mpq_0), x);
+  ret = mpq_cmp (tmp_mpq_0, y);
+  mpz_swap (mpq_numref(tmp_mpq_0), x);
+  return ret;
+}
+
+static int
+x_mpz_cmp_f (mpz_srcptr x, mpf_srcptr y)
+{
+  tmp_mpf_set_prec (tmp_mpf_0, mpz_sizeinbase (x, 2));
+  mpf_set_z (tmp_mpf_0->m, x);
+  return mpf_cmp (tmp_mpf_0->m, y);
+}
+
+
+#define USE_UNKNOWN  0
+#define USE_IVX      1
+#define USE_UVX      2
+#define USE_NVX      3
+#define USE_PVX      4
+#define USE_MPZ      5
+#define USE_MPQ      6
+#define USE_MPF      7
+
+/* mg_get is called every time we get a value, even if the private flags are
+   still set from a previous such call.  This is the same as as SvIV and
+   friends do.
+
+   When POK, we use the PV, even if there's an IV or NV available.  This is
+   because it's hard to be sure there wasn't any rounding in establishing
+   the IV and/or NV.  Cases of overflow, where the PV should definitely be
+   used, are easy enough to spot, but rounding is hard.  So although IV or
+   NV would be more efficient, we must use the PV to be sure of getting all
+   the data.  Applications should convert once to mpz, mpq or mpf when using
+   a value repeatedly.
+
+   Zany dual-type scalars like $! where the IV is an error code and the PV
+   is an error description string won't work with this preference for PV,
+   but that's too bad.  Such scalars should be rare, and unlikely to be used
+   in bignum calculations.
+
+   When IOK and NOK are both set, we would prefer to use the IV since it can
+   be converted more efficiently, and because on a 64-bit system the NV may
+   have less bits than the IV.  The following rules are applied,
+
+   - If the NV is not an integer, then we must use that NV, since clearly
+     the IV was merely established by rounding and is not the full value.
+
+   - In perl prior to 5.8, an NV too big for an IV leaves an overflow value
+     0xFFFFFFFF.  If the NV is too big to fit an IV then clearly it's the NV
+     which is the true value and must be used.
+
+   - In perl 5.8 and up, such an overflow doesn't set IOK, so that test is
+     unnecessary.  However when coming from get-magic, IOKp _is_ set, and we
+     must check for overflow the same as in older perl.
+
+   FIXME:
+
+   We'd like to call mg_get just once, but unfortunately sv_derived_from()
+   will call it for each of our checks.  We could do a string compare like
+   sv_isa ourselves, but that only tests the exact class, it doesn't
+   recognise subclassing.  There doesn't seem to be a public interface to
+   the subclassing tests (in the internal isa_lookup() function).  */
+
+int
+use_sv (SV *sv)
+{
+  double  d;
+
+  if (SvGMAGICAL(sv))
+    {
+      mg_get(sv);
+
+      if (SvPOKp(sv))
+        return USE_PVX;
+
+      if (SvIOKp(sv))
+        {
+          if (SvIsUV(sv))
+            {
+              if (SvNOKp(sv))
+                goto u_or_n;
+              return USE_UVX;
+            }
+          else
+            {
+              if (SvNOKp(sv))
+                goto i_or_n;
+              return USE_IVX;
+            }
+        }
+
+      if (SvNOKp(sv))
+        return USE_NVX;
+
+      goto rok_or_unknown;
+    }
+
+  if (SvPOK(sv))
+    return USE_PVX;
+
+  if (SvIOK(sv))
+    {
+      if (SvIsUV(sv))
+        {
+          if (SvNOK(sv))
+            {
+              if (PERL_LT (5, 8))
+                {
+                u_or_n:
+                  d = SvNVX(sv);
+                  if (d >= ULONG_MAX_P1_AS_DOUBLE || d < 0.0)
+                    return USE_NVX;
+                }
+              d = SvNVX(sv);
+              if (d != floor (d))
+                return USE_NVX;
+            }
+          return USE_UVX;
+        }
+      else
+        {
+          if (SvNOK(sv))
+            {
+              if (PERL_LT (5, 8))
+                {
+                i_or_n:
+                  d = SvNVX(sv);
+                  if (d >= LONG_MAX_P1_AS_DOUBLE || d < (double) LONG_MIN)
+                    return USE_NVX;
+                }
+              d = SvNVX(sv);
+              if (d != floor (d))
+                return USE_NVX;
+            }
+          return USE_IVX;
+        }
+    }
+
+  if (SvNOK(sv))
+    return USE_NVX;
+
+ rok_or_unknown:
+  if (SvROK(sv))
+    {
+      if (sv_derived_from (sv, mpz_class))
+        return USE_MPZ;
+      if (sv_derived_from (sv, mpq_class))
+        return USE_MPQ;
+      if (sv_derived_from (sv, mpf_class))
+        return USE_MPF;
+    }
+
+  return USE_UNKNOWN;
+}
+
+
+/* Coerce sv to an mpz.  Use tmp to hold the converted value if sv isn't
+   already an mpz (or an mpq of which the numerator can be used).  Return
+   the chosen mpz (tmp or the contents of sv).  */
+
+static mpz_ptr
+coerce_mpz_using (mpz_ptr tmp, SV *sv, int use)
+{
+  switch (use) {
+  case USE_IVX:
+    mpz_set_si (tmp, SvIVX(sv));
+    return tmp;
+
+  case USE_UVX:
+    mpz_set_ui (tmp, SvUVX(sv));
+    return tmp;
+
+  case USE_NVX:
+    {
+      double d;
+      d = SvNVX(sv);
+      if (! double_integer_p (d))
+        croak ("cannot coerce non-integer double to mpz");
+      mpz_set_d (tmp, d);
+      return tmp;
+    }
+
+  case USE_PVX:
+    my_mpz_set_svstr (tmp, sv);
+    return tmp;
+
+  case USE_MPZ:
+    return SvMPZ(sv)->m;
+
+  case USE_MPQ:
+    {
+      mpq q = SvMPQ(sv);
+      if (! x_mpq_integer_p (q->m))
+        croak ("cannot coerce non-integer mpq to mpz");
+      return mpq_numref(q->m);
+    }
+
+  case USE_MPF:
+    {
+      mpf f = SvMPF(sv);
+      if (! mpf_integer_p (f))
+        croak ("cannot coerce non-integer mpf to mpz");
+      mpz_set_f (tmp, f);
+      return tmp;
+    }
+
+  default:
+    croak ("cannot coerce to mpz");
+  }
+}
+static mpz_ptr
+coerce_mpz (mpz_ptr tmp, SV *sv)
+{
+  return coerce_mpz_using (tmp, sv, use_sv (sv));
+}
+
+
+/* Coerce sv to an mpq.  If sv is an mpq then just return that, otherwise
+   use tmp to hold the converted value and return that.  */
+
+static mpq_ptr
+coerce_mpq_using (mpq_ptr tmp, SV *sv, int use)
+{
+  TRACE (printf ("coerce_mpq_using %p %d\n", tmp, use));
+  switch (use) {
+  case USE_IVX:
+    mpq_set_si (tmp, SvIVX(sv), 1L);
+    return tmp;
+
+  case USE_UVX:
+    mpq_set_ui (tmp, SvUVX(sv), 1L);
+    return tmp;
+
+  case USE_NVX:
+    mpq_set_d (tmp, SvNVX(sv));
+    return tmp;
+
+  case USE_PVX:
+    my_mpq_set_svstr (tmp, sv);
+    return tmp;
+
+  case USE_MPZ:
+    mpq_set_z (tmp, SvMPZ(sv)->m);
+    return tmp;
+
+  case USE_MPQ:
+    return SvMPQ(sv)->m;
+
+  case USE_MPF:
+    mpq_set_f (tmp, SvMPF(sv));
+    return tmp;
+
+  default:
+    croak ("cannot coerce to mpq");
+  }
+}
+static mpq_ptr
+coerce_mpq (mpq_ptr tmp, SV *sv)
+{
+  return coerce_mpq_using (tmp, sv, use_sv (sv));
+}
+
+
+static void
+my_mpf_set_sv_using (mpf_ptr f, SV *sv, int use)
+{
+  switch (use) {
+  case USE_IVX:
+    mpf_set_si (f, SvIVX(sv));
+    break;
+
+  case USE_UVX:
+    mpf_set_ui (f, SvUVX(sv));
+    break;
+
+  case USE_NVX:
+    mpf_set_d (f, SvNVX(sv));
+    break;
+
+  case USE_PVX:
+    my_mpf_set_svstr (f, sv);
+    break;
+
+  case USE_MPZ:
+    mpf_set_z (f, SvMPZ(sv)->m);
+    break;
+
+  case USE_MPQ:
+    mpf_set_q (f, SvMPQ(sv)->m);
+    break;
+
+  case USE_MPF:
+    mpf_set (f, SvMPF(sv));
+    break;
+
+  default:
+    croak ("cannot coerce to mpf");
+  }
+}
+
+/* Coerce sv to an mpf.  If sv is an mpf then just return that, otherwise
+   use tmp to hold the converted value (with prec precision).  */
+static mpf_ptr
+coerce_mpf_using (tmp_mpf_ptr tmp, SV *sv, unsigned long prec, int use)
+{
+  if (use == USE_MPF)
+    return SvMPF(sv);
+
+  tmp_mpf_set_prec (tmp, prec);
+  my_mpf_set_sv_using (tmp->m, sv, use);
+  return tmp->m;
+}
+static mpf_ptr
+coerce_mpf (tmp_mpf_ptr tmp, SV *sv, unsigned long prec)
+{
+  return coerce_mpf_using (tmp, sv, prec, use_sv (sv));
+}
+
+
+/* Coerce xv to an mpf and store the pointer in x, ditto for yv to x.  If
+   one of xv or yv is an mpf then use it for the precision, otherwise use
+   the default precision.  */
+unsigned long
+coerce_mpf_pair (mpf *xp, SV *xv, mpf *yp, SV *yv)
+{
+  int x_use = use_sv (xv);
+  int y_use = use_sv (yv);
+  unsigned long  prec;
+  mpf  x, y;
+
+  if (x_use == USE_MPF)
+    {
+      x = SvMPF(xv);
+      prec = mpf_get_prec (x);
+      y = coerce_mpf_using (tmp_mpf_0, yv, prec, y_use);
+    }
+  else
+    {
+      y = coerce_mpf_using (tmp_mpf_0, yv, mpf_get_default_prec(), y_use);
+      prec = mpf_get_prec (y);
+      x = coerce_mpf_using (tmp_mpf_1, xv, prec, x_use);
+    }
+  *xp = x;
+  *yp = y;
+  return prec;
+}
+
+
+/* Note that SvUV is not used, since it merely treats the signed IV as if it
+   was unsigned.  We get an IV and check its sign. */
+static unsigned long
+coerce_ulong (SV *sv)
+{
+  long  n;
+
+  switch (use_sv (sv)) {
+  case USE_IVX:
+    n = SvIVX(sv);
+  negative_check:
+    if (n < 0)
+      goto range_error;
+    return n;
+
+  case USE_UVX:
+    return SvUVX(sv);
+
+  case USE_NVX:
+    {
+      double d;
+      d = SvNVX(sv);
+      if (! double_integer_p (d))
+        goto integer_error;
+      n = SvIV(sv);
+    }
+    goto negative_check;
+
+  case USE_PVX:
+    /* FIXME: Check the string is an integer. */
+    n = SvIV(sv);
+    goto negative_check;
+
+  case USE_MPZ:
+    {
+      mpz z = SvMPZ(sv);
+      if (! mpz_fits_ulong_p (z->m))
+        goto range_error;
+      return mpz_get_ui (z->m);
+    }
+
+  case USE_MPQ:
+    {
+      mpq q = SvMPQ(sv);
+      if (! x_mpq_integer_p (q->m))
+        goto integer_error;
+      if (! mpz_fits_ulong_p (mpq_numref (q->m)))
+        goto range_error;
+      return mpz_get_ui (mpq_numref (q->m));
+    }
+
+  case USE_MPF:
+    {
+      mpf f = SvMPF(sv);
+      if (! mpf_integer_p (f))
+        goto integer_error;
+      if (! mpf_fits_ulong_p (f))
+        goto range_error;
+      return mpf_get_ui (f);
+    }
+
+  default:
+    croak ("cannot coerce to ulong");
+  }
+
+ integer_error:
+  croak ("not an integer");
+
+ range_error:
+  croak ("out of range for ulong");
+}
+
+
+static long
+coerce_long (SV *sv)
+{
+  switch (use_sv (sv)) {
+  case USE_IVX:
+    return SvIVX(sv);
+
+  case USE_UVX:
+    {
+      UV u = SvUVX(sv);
+      if (u > (UV) LONG_MAX)
+        goto range_error;
+      return u;
+    }
+
+  case USE_NVX:
+    {
+      double d = SvNVX(sv);
+      if (! double_integer_p (d))
+        goto integer_error;
+      return SvIV(sv);
+    }
+
+  case USE_PVX:
+    /* FIXME: Check the string is an integer. */
+    return SvIV(sv);
+
+  case USE_MPZ:
+    {
+      mpz z = SvMPZ(sv);
+      if (! mpz_fits_slong_p (z->m))
+        goto range_error;
+      return mpz_get_si (z->m);
+    }
+
+  case USE_MPQ:
+    {
+      mpq q = SvMPQ(sv);
+      if (! x_mpq_integer_p (q->m))
+        goto integer_error;
+      if (! mpz_fits_slong_p (mpq_numref (q->m)))
+        goto range_error;
+      return mpz_get_si (mpq_numref (q->m));
+    }
+
+  case USE_MPF:
+    {
+      mpf f = SvMPF(sv);
+      if (! mpf_integer_p (f))
+        goto integer_error;
+      if (! mpf_fits_slong_p (f))
+        goto range_error;
+      return mpf_get_si (f);
+    }
+
+  default:
+    croak ("cannot coerce to long");
+  }
+
+ integer_error:
+  croak ("not an integer");
+
+ range_error:
+  croak ("out of range for ulong");
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+MODULE = GMP         PACKAGE = GMP
+
+BOOT:
+    TRACE (printf ("GMP boot\n"));
+    mp_set_memory_functions (my_gmp_alloc, my_gmp_realloc, my_gmp_free);
+    mpz_init (tmp_mpz_0);
+    mpz_init (tmp_mpz_1);
+    mpz_init (tmp_mpz_2);
+    mpq_init (tmp_mpq_0);
+    mpq_init (tmp_mpq_1);
+    tmp_mpf_init (tmp_mpf_0);
+    tmp_mpf_init (tmp_mpf_1);
+    mpz_class_hv = gv_stashpv (mpz_class, 1);
+    mpq_class_hv = gv_stashpv (mpq_class, 1);
+    mpf_class_hv = gv_stashpv (mpf_class, 1);
+
+
+void
+END()
+CODE:
+    TRACE (printf ("GMP end\n"));
+    TRACE_ACTIVE ();
+    /* These are not always true, see Bugs at the top of the file. */
+    /* assert (mpz_count == 0); */
+    /* assert (mpq_count == 0); */
+    /* assert (mpf_count == 0); */
+    /* assert (rand_count == 0); */
+
+
+const_string
+version()
+CODE:
+    RETVAL = gmp_version;
+OUTPUT:
+    RETVAL
+
+
+bool
+fits_slong_p (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      RETVAL = 1;
+      break;
+
+    case USE_UVX:
+      {
+        UV u = SvUVX(sv);
+        RETVAL = (u <= LONG_MAX);
+      }
+      break;
+
+    case USE_NVX:
+      {
+        double  d = SvNVX(sv);
+        RETVAL = (d >= (double) LONG_MIN && d < LONG_MAX_P1_AS_DOUBLE);
+      }
+      break;
+
+    case USE_PVX:
+      {
+        STRLEN len;
+        const char *str = SvPV (sv, len);
+        if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
+          RETVAL = x_mpq_fits_slong_p (tmp_mpq_0);
+        else
+          {
+            /* enough precision for a long */
+            tmp_mpf_set_prec (tmp_mpf_0, 2*mp_bits_per_limb);
+            if (mpf_set_str (tmp_mpf_0->m, str, 10) != 0)
+              croak ("GMP::fits_slong_p invalid string format");
+            RETVAL = mpf_fits_slong_p (tmp_mpf_0->m);
+          }
+      }
+      break;
+
+    case USE_MPZ:
+      RETVAL = mpz_fits_slong_p (SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      RETVAL = x_mpq_fits_slong_p (SvMPQ(sv)->m);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_fits_slong_p (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::fits_slong_p invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+double
+get_d (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      RETVAL = (double) SvIVX(sv);
+      break;
+
+    case USE_UVX:
+      RETVAL = (double) SvUVX(sv);
+      break;
+
+    case USE_NVX:
+      RETVAL = SvNVX(sv);
+      break;
+
+    case USE_PVX:
+      {
+        STRLEN len;
+        RETVAL = atof(SvPV(sv, len));
+      }
+      break;
+
+    case USE_MPZ:
+      RETVAL = mpz_get_d (SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      RETVAL = mpq_get_d (SvMPQ(sv)->m);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_get_d (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::get_d invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+void
+get_d_2exp (sv)
+    SV *sv
+PREINIT:
+    double ret;
+    long   exp;
+PPCODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      ret = (double) SvIVX(sv);
+      goto use_frexp;
+
+    case USE_UVX:
+      ret = (double) SvUVX(sv);
+      goto use_frexp;
+
+    case USE_NVX:
+      {
+        int i_exp;
+        ret = SvNVX(sv);
+      use_frexp:
+        ret = frexp (ret, &i_exp);
+        exp = i_exp;
+      }
+      break;
+
+    case USE_PVX:
+      /* put strings through mpf to give full exp range */
+      tmp_mpf_set_prec (tmp_mpf_0, DBL_MANT_DIG);
+      my_mpf_set_svstr (tmp_mpf_0->m, sv);
+      ret = mpf_get_d_2exp (&exp, tmp_mpf_0->m);
+      break;
+
+    case USE_MPZ:
+      ret = mpz_get_d_2exp (&exp, SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      tmp_mpf_set_prec (tmp_mpf_0, DBL_MANT_DIG);
+      mpf_set_q (tmp_mpf_0->m, SvMPQ(sv)->m);
+      ret = mpf_get_d_2exp (&exp, tmp_mpf_0->m);
+      break;
+
+    case USE_MPF:
+      ret = mpf_get_d_2exp (&exp, SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::get_d_2exp invalid argument");
+    }
+    PUSHs (sv_2mortal (newSVnv (ret)));
+    PUSHs (sv_2mortal (newSViv (exp)));
+
+
+long
+get_si (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      RETVAL = SvIVX(sv);
+      break;
+
+    case USE_UVX:
+      RETVAL = SvUVX(sv);
+      break;
+
+    case USE_NVX:
+      RETVAL = (long) SvNVX(sv);
+      break;
+
+    case USE_PVX:
+      RETVAL = SvIV(sv);
+      break;
+
+    case USE_MPZ:
+      RETVAL = mpz_get_si (SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      mpz_set_q (tmp_mpz_0, SvMPQ(sv)->m);
+      RETVAL = mpz_get_si (tmp_mpz_0);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_get_si (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::get_si invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+void
+get_str (sv, ...)
+    SV *sv
+PREINIT:
+    char      *str;
+    mp_exp_t  exp;
+    mpz_ptr   z;
+    mpq_ptr   q;
+    mpf       f;
+    int       base;
+    int       ndigits;
+PPCODE:
+    TRACE (printf ("GMP::get_str\n"));
+
+    if (items >= 2)
+      base = coerce_long (ST(1));
+    else
+      base = 10;
+    TRACE (printf (" base=%d\n", base));
+
+    if (items >= 3)
+      ndigits = coerce_long (ST(2));
+    else
+      ndigits = 10;
+    TRACE (printf (" ndigits=%d\n", ndigits));
+
+    EXTEND (SP, 2);
+
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      mpz_set_si (tmp_mpz_0, SvIVX(sv));
+    get_tmp_mpz_0:
+      z = tmp_mpz_0;
+      goto get_mpz;
+
+    case USE_UVX:
+      mpz_set_ui (tmp_mpz_0, SvUVX(sv));
+      goto get_tmp_mpz_0;
+
+    case USE_NVX:
+      /* only digits in the original double, not in the coerced form */
+      if (ndigits == 0)
+        ndigits = DBL_DIG;
+      mpf_set_d (tmp_mpf_0->m, SvNVX(sv));
+      f = tmp_mpf_0->m;
+      goto get_mpf;
+
+    case USE_PVX:
+      {
+        /* get_str on a string is not much more than a base conversion */
+        STRLEN len;
+        str = SvPV (sv, len);
+        if (mpz_set_str (tmp_mpz_0, str, 0) == 0)
+          {
+            z = tmp_mpz_0;
+            goto get_mpz;
+          }
+        else if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
+          {
+            q = tmp_mpq_0;
+            goto get_mpq;
+          }
+        else
+          {
+            /* FIXME: Would like perhaps a precision equivalent to the
+               number of significant digits of the string, in its given
+               base.  */
+            tmp_mpf_set_prec (tmp_mpf_0, strlen(str));
+            if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0)
+              {
+                f = tmp_mpf_0->m;
+                goto get_mpf;
+              }
+            else
+              croak ("GMP::get_str invalid string format");
+          }
+      }
+      break;
+
+    case USE_MPZ:
+      z = SvMPZ(sv)->m;
+    get_mpz:
+      str = mpz_get_str (NULL, base, z);
+    push_str:
+      PUSHs (sv_2mortal (newSVpv (str, 0)));
+      break;
+
+    case USE_MPQ:
+      q = SvMPQ(sv)->m;
+    get_mpq:
+      str = mpq_get_str (NULL, base, q);
+      goto push_str;
+
+    case USE_MPF:
+      f = SvMPF(sv);
+    get_mpf:
+      str = mpf_get_str (NULL, &exp, base, 0, f);
+      PUSHs (sv_2mortal (newSVpv (str, 0)));
+      PUSHs (sv_2mortal (newSViv (exp)));
+      break;
+
+    default:
+      croak ("GMP::get_str invalid argument");
+    }
+
+
+bool
+integer_p (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+    case USE_UVX:
+      RETVAL = 1;
+      break;
+
+    case USE_NVX:
+      RETVAL = double_integer_p (SvNVX(sv));
+      break;
+
+    case USE_PVX:
+      {
+        /* FIXME: Maybe this should be done by parsing the string, not by an
+           actual conversion.  */
+        STRLEN len;
+        const char *str = SvPV (sv, len);
+        if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
+          RETVAL = x_mpq_integer_p (tmp_mpq_0);
+        else
+          {
+            /* enough for all digits of the string */
+            tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64);
+            if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0)
+              RETVAL = mpf_integer_p (tmp_mpf_0->m);
+            else
+              croak ("GMP::integer_p invalid string format");
+          }
+      }
+      break;
+
+    case USE_MPZ:
+      RETVAL = 1;
+      break;
+
+    case USE_MPQ:
+      RETVAL = x_mpq_integer_p (SvMPQ(sv)->m);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_integer_p (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::integer_p invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+int
+sgn (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      RETVAL = SGN (SvIVX(sv));
+      break;
+
+    case USE_UVX:
+      RETVAL = (SvUVX(sv) > 0);
+      break;
+
+    case USE_NVX:
+      RETVAL = SGN (SvNVX(sv));
+      break;
+
+    case USE_PVX:
+      {
+        /* FIXME: Maybe this should be done by parsing the string, not by an
+           actual conversion.  */
+        STRLEN len;
+        const char *str = SvPV (sv, len);
+        if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
+          RETVAL = mpq_sgn (tmp_mpq_0);
+        else
+          {
+            /* enough for all digits of the string */
+            tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64);
+            if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0)
+              RETVAL = mpf_sgn (tmp_mpf_0->m);
+            else
+              croak ("GMP::sgn invalid string format");
+          }
+      }
+      break;
+
+    case USE_MPZ:
+      RETVAL = mpz_sgn (SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      RETVAL = mpq_sgn (SvMPQ(sv)->m);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_sgn (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::sgn invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+# currently undocumented
+void
+shrink ()
+CODE:
+#define x_mpz_shrink(z) \
+    mpz_set_ui (z, 0L); _mpz_realloc (z, 1)
+#define x_mpq_shrink(q) \
+    x_mpz_shrink (mpq_numref(q)); x_mpz_shrink (mpq_denref(q))
+
+    x_mpz_shrink (tmp_mpz_0);
+    x_mpz_shrink (tmp_mpz_1);
+    x_mpz_shrink (tmp_mpz_2);
+    x_mpq_shrink (tmp_mpq_0);
+    x_mpq_shrink (tmp_mpq_1);
+    tmp_mpf_shrink (tmp_mpf_0);
+    tmp_mpf_shrink (tmp_mpf_1);
+
+
+
+malloced_string
+sprintf_internal (fmt, sv)
+    const_string fmt
+    SV           *sv
+CODE:
+    assert (strlen (fmt) >= 3);
+    assert (SvROK(sv));
+    assert ((sv_derived_from (sv, mpz_class)    && fmt[strlen(fmt)-2] == 'Z')
+            || (sv_derived_from (sv, mpq_class) && fmt[strlen(fmt)-2] == 'Q')
+            || (sv_derived_from (sv, mpf_class) && fmt[strlen(fmt)-2] == 'F'));
+    TRACE (printf ("GMP::sprintf_internal\n");
+           printf ("  fmt  |%s|\n", fmt);
+           printf ("  sv   |%p|\n", SvMPZ(sv)));
+
+    /* cheat a bit here, SvMPZ works for mpq and mpf too */
+    gmp_asprintf (&RETVAL, fmt, SvMPZ(sv));
+
+    TRACE (printf ("  result |%s|\n", RETVAL));
+OUTPUT:
+    RETVAL
+
+
+
+#------------------------------------------------------------------------------
+
+MODULE = GMP         PACKAGE = GMP::Mpz
+
+mpz
+mpz (...)
+ALIAS:
+    GMP::Mpz::new = 1
+PREINIT:
+    SV *sv;
+CODE:
+    TRACE (printf ("%s new, ix=%ld, items=%d\n", mpz_class, ix, (int) items));
+    RETVAL = new_mpz();
+
+    switch (items) {
+    case 0:
+      mpz_set_ui (RETVAL->m, 0L);
+      break;
+
+    case 1:
+      sv = ST(0);
+      TRACE (printf ("  use %d\n", use_sv (sv)));
+      switch (use_sv (sv)) {
+      case USE_IVX:
+        mpz_set_si (RETVAL->m, SvIVX(sv));
+        break;
+
+      case USE_UVX:
+        mpz_set_ui (RETVAL->m, SvUVX(sv));
+        break;
+
+      case USE_NVX:
+        mpz_set_d (RETVAL->m, SvNVX(sv));
+        break;
+
+      case USE_PVX:
+        my_mpz_set_svstr (RETVAL->m, sv);
+        break;
+
+      case USE_MPZ:
+        mpz_set (RETVAL->m, SvMPZ(sv)->m);
+        break;
+
+      case USE_MPQ:
+        mpz_set_q (RETVAL->m, SvMPQ(sv)->m);
+        break;
+
+      case USE_MPF:
+        mpz_set_f (RETVAL->m, SvMPF(sv));
+        break;
+
+      default:
+        goto invalid;
+      }
+      break;
+
+    default:
+    invalid:
+      croak ("%s new: invalid arguments", mpz_class);
+    }
+OUTPUT:
+    RETVAL
+
+
+void
+overload_constant (str, pv, d1, ...)
+    const_string_assume str
+    SV                  *pv
+    dummy               d1
+PREINIT:
+    mpz z;
+PPCODE:
+    TRACE (printf ("%s constant: %s\n", mpz_class, str));
+    z = new_mpz();
+    if (mpz_set_str (z->m, str, 0) == 0)
+      {
+        PUSHs (MPX_NEWMORTAL (z, mpz_class_hv));
+      }
+    else
+      {
+        free_mpz (z);
+        PUSHs(pv);
+      }
+
+
+mpz
+overload_copy (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+CODE:
+    RETVAL = new_mpz();
+    mpz_set (RETVAL->m, z->m);
+OUTPUT:
+    RETVAL
+
+
+void
+DESTROY (z)
+    mpz_assume z
+CODE:
+    TRACE (printf ("%s DESTROY %p\n", mpz_class, z));
+    free_mpz (z);
+
+
+malloced_string
+overload_string (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+CODE:
+    TRACE (printf ("%s overload_string %p\n", mpz_class, z));
+    RETVAL = mpz_get_str (NULL, 10, z->m);
+OUTPUT:
+    RETVAL
+
+
+mpz
+overload_add (xv, yv, order)
+    SV *xv
+    SV *yv
+    SV *order
+ALIAS:
+    GMP::Mpz::overload_sub = 1
+    GMP::Mpz::overload_mul = 2
+    GMP::Mpz::overload_div = 3
+    GMP::Mpz::overload_rem = 4
+    GMP::Mpz::overload_and = 5
+    GMP::Mpz::overload_ior = 6
+    GMP::Mpz::overload_xor = 7
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_add    }, /* 0 */
+      { mpz_sub    }, /* 1 */
+      { mpz_mul    }, /* 2 */
+      { mpz_tdiv_q }, /* 3 */
+      { mpz_tdiv_r }, /* 4 */
+      { mpz_and    }, /* 5 */
+      { mpz_ior    }, /* 6 */
+      { mpz_xor    }, /* 7 */
+    };
+CODE:
+    assert_table (ix);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (xv, yv);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m,
+                     coerce_mpz (tmp_mpz_0, xv),
+                     coerce_mpz (tmp_mpz_1, yv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_addeq (x, y, o)
+    mpz_assume   x
+    mpz_coerce   y
+    order_noswap o
+ALIAS:
+    GMP::Mpz::overload_subeq = 1
+    GMP::Mpz::overload_muleq = 2
+    GMP::Mpz::overload_diveq = 3
+    GMP::Mpz::overload_remeq = 4
+    GMP::Mpz::overload_andeq = 5
+    GMP::Mpz::overload_ioreq = 6
+    GMP::Mpz::overload_xoreq = 7
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_add    }, /* 0 */
+      { mpz_sub    }, /* 1 */
+      { mpz_mul    }, /* 2 */
+      { mpz_tdiv_q }, /* 3 */
+      { mpz_tdiv_r }, /* 4 */
+      { mpz_and    }, /* 5 */
+      { mpz_ior    }, /* 6 */
+      { mpz_xor    }, /* 7 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (x->m, x->m, y);
+    XPUSHs (ST(0));
+
+
+mpz
+overload_lshift (zv, nv, order)
+    SV *zv
+    SV *nv
+    SV *order
+ALIAS:
+    GMP::Mpz::overload_rshift   = 1
+    GMP::Mpz::overload_pow      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, unsigned long);
+    } table[] = {
+      { mpz_mul_2exp }, /* 0 */
+      { mpz_fdiv_q_2exp }, /* 1 */
+      { mpz_pow_ui   }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (zv, nv);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, coerce_mpz (RETVAL->m, zv), coerce_ulong (nv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_lshifteq (z, n, o)
+    mpz_assume   z
+    ulong_coerce n
+    order_noswap o
+ALIAS:
+    GMP::Mpz::overload_rshifteq   = 1
+    GMP::Mpz::overload_poweq      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, unsigned long);
+    } table[] = {
+      { mpz_mul_2exp }, /* 0 */
+      { mpz_fdiv_q_2exp }, /* 1 */
+      { mpz_pow_ui   }, /* 2 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (z->m, z->m, n);
+    XPUSHs(ST(0));
+
+
+mpz
+overload_abs (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpz::overload_neg  = 1
+    GMP::Mpz::overload_com  = 2
+    GMP::Mpz::overload_sqrt = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr w, mpz_srcptr x);
+    } table[] = {
+      { mpz_abs  }, /* 0 */
+      { mpz_neg  }, /* 1 */
+      { mpz_com  }, /* 2 */
+      { mpz_sqrt }, /* 3 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, z->m);
+OUTPUT:
+    RETVAL
+
+
+void
+overload_inc (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpz::overload_dec = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr w, mpz_srcptr x, unsigned long y);
+    } table[] = {
+      { mpz_add_ui }, /* 0 */
+      { mpz_sub_ui }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    (*table[ix].op) (z->m, z->m, 1L);
+
+
+int
+overload_spaceship (xv, yv, order)
+    SV *xv
+    SV *yv
+    SV *order
+PREINIT:
+    mpz x;
+CODE:
+    TRACE (printf ("%s overload_spaceship\n", mpz_class));
+    MPZ_ASSUME (x, xv);
+    switch (use_sv (yv)) {
+    case USE_IVX:
+      RETVAL = mpz_cmp_si (x->m, SvIVX(yv));
+      break;
+    case USE_UVX:
+      RETVAL = mpz_cmp_ui (x->m, SvUVX(yv));
+      break;
+    case USE_PVX:
+      RETVAL = mpz_cmp (x->m, coerce_mpz (tmp_mpz_0, yv));
+      break;
+    case USE_NVX:
+      RETVAL = mpz_cmp_d (x->m, SvNVX(yv));
+      break;
+    case USE_MPZ:
+      RETVAL = mpz_cmp (x->m, SvMPZ(yv)->m);
+      break;
+    case USE_MPQ:
+      RETVAL = x_mpz_cmp_q (x->m, SvMPQ(yv)->m);
+      break;
+    case USE_MPF:
+      RETVAL = x_mpz_cmp_f (x->m, SvMPF(yv));
+      break;
+    default:
+      croak ("%s <=>: invalid operand", mpz_class);
+    }
+    RETVAL = SGN (RETVAL);
+    if (order == &PL_sv_yes)
+      RETVAL = -RETVAL;
+OUTPUT:
+    RETVAL
+
+
+bool
+overload_bool (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpz::overload_not = 1
+CODE:
+    RETVAL = (mpz_sgn (z->m) != 0) ^ ix;
+OUTPUT:
+    RETVAL
+
+
+mpz
+bin (n, k)
+    mpz_coerce   n
+    ulong_coerce k
+ALIAS:
+    GMP::Mpz::root = 1
+PREINIT:
+    /* mpz_root returns an int, hence the cast */
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, unsigned long);
+    } table[] = {
+      {                                                mpz_bin_ui }, /* 0 */
+      { (void (*)(mpz_ptr, mpz_srcptr, unsigned long)) mpz_root   }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, n, k);
+OUTPUT:
+    RETVAL
+
+
+void
+cdiv (a, d)
+    mpz_coerce a
+    mpz_coerce d
+ALIAS:
+    GMP::Mpz::fdiv = 1
+    GMP::Mpz::tdiv = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_cdiv_qr }, /* 0 */
+      { mpz_fdiv_qr }, /* 1 */
+      { mpz_tdiv_qr }, /* 2 */
+    };
+    mpz q, r;
+PPCODE:
+    assert_table (ix);
+    q = new_mpz();
+    r = new_mpz();
+    (*table[ix].op) (q->m, r->m, a, d);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (q, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (r, mpz_class_hv));
+
+
+void
+cdiv_2exp (a, d)
+    mpz_coerce   a
+    ulong_coerce d
+ALIAS:
+    GMP::Mpz::fdiv_2exp = 1
+    GMP::Mpz::tdiv_2exp = 2
+PREINIT:
+    static_functable const struct {
+      void (*q) (mpz_ptr, mpz_srcptr, unsigned long);
+      void (*r) (mpz_ptr, mpz_srcptr, unsigned long);
+    } table[] = {
+      { mpz_cdiv_q_2exp, mpz_cdiv_r_2exp }, /* 0 */
+      { mpz_fdiv_q_2exp, mpz_fdiv_r_2exp }, /* 1 */
+      { mpz_tdiv_q_2exp, mpz_tdiv_r_2exp }, /* 2 */
+    };
+    mpz q, r;
+PPCODE:
+    assert_table (ix);
+    q = new_mpz();
+    r = new_mpz();
+    (*table[ix].q) (q->m, a, d);
+    (*table[ix].r) (r->m, a, d);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (q, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (r, mpz_class_hv));
+
+
+bool
+congruent_p (a, c, d)
+    mpz_coerce a
+    mpz_coerce c
+    mpz_coerce d
+PREINIT:
+CODE:
+    RETVAL = mpz_congruent_p (a, c, d);
+OUTPUT:
+    RETVAL
+
+
+bool
+congruent_2exp_p (a, c, d)
+    mpz_coerce   a
+    mpz_coerce   c
+    ulong_coerce d
+PREINIT:
+CODE:
+    RETVAL = mpz_congruent_2exp_p (a, c, d);
+OUTPUT:
+    RETVAL
+
+
+mpz
+divexact (a, d)
+    mpz_coerce a
+    mpz_coerce d
+ALIAS:
+    GMP::Mpz::mod = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_divexact }, /* 0 */
+      { mpz_mod      }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, a, d);
+OUTPUT:
+    RETVAL
+
+
+bool
+divisible_p (a, d)
+    mpz_coerce a
+    mpz_coerce d
+CODE:
+    RETVAL = mpz_divisible_p (a, d);
+OUTPUT:
+    RETVAL
+
+
+bool
+divisible_2exp_p (a, d)
+    mpz_coerce   a
+    ulong_coerce d
+CODE:
+    RETVAL = mpz_divisible_2exp_p (a, d);
+OUTPUT:
+    RETVAL
+
+
+bool
+even_p (z)
+    mpz_coerce z
+ALIAS:
+    GMP::Mpz::odd_p            = 1
+    GMP::Mpz::perfect_square_p = 2
+    GMP::Mpz::perfect_power_p  = 3
+PREINIT:
+    static_functable const struct {
+      int (*op) (mpz_srcptr z);
+    } table[] = {
+      { x_mpz_even_p         }, /* 0 */
+      { x_mpz_odd_p          }, /* 1 */
+      { mpz_perfect_square_p }, /* 2 */
+      { mpz_perfect_power_p  }, /* 3 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = (*table[ix].op) (z);
+OUTPUT:
+    RETVAL
+
+
+mpz
+fac (n)
+    ulong_coerce n
+ALIAS:
+    GMP::Mpz::fib    = 1
+    GMP::Mpz::lucnum = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr r, unsigned long n);
+    } table[] = {
+      { mpz_fac_ui },    /* 0 */
+      { mpz_fib_ui },    /* 1 */
+      { mpz_lucnum_ui }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, n);
+OUTPUT:
+    RETVAL
+
+
+void
+fib2 (n)
+    ulong_coerce n
+ALIAS:
+    GMP::Mpz::lucnum2 = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr r, mpz_ptr r2, unsigned long n);
+    } table[] = {
+      { mpz_fib2_ui },    /* 0 */
+      { mpz_lucnum2_ui }, /* 1 */
+    };
+    mpz  r, r2;
+PPCODE:
+    assert_table (ix);
+    r = new_mpz();
+    r2 = new_mpz();
+    (*table[ix].op) (r->m, r2->m, n);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (r,  mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (r2, mpz_class_hv));
+
+
+mpz
+gcd (x, ...)
+    mpz_coerce x
+ALIAS:
+    GMP::Mpz::lcm = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr w, mpz_srcptr x, mpz_srcptr y);
+      void (*op_ui) (mpz_ptr w, mpz_srcptr x, unsigned long y);
+    } table[] = {
+      /* cast to ignore ulong return from mpz_gcd_ui */
+      { mpz_gcd,
+        (void (*) (mpz_ptr, mpz_srcptr, unsigned long)) mpz_gcd_ui }, /* 0 */
+      { mpz_lcm, mpz_lcm_ui },                                        /* 1 */
+    };
+    int  i;
+    SV   *yv;
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    if (items == 1)
+      mpz_set (RETVAL->m, x);
+    else
+      {
+        for (i = 1; i < items; i++)
+          {
+            yv = ST(i);
+            if (SvIOK(yv))
+              (*table[ix].op_ui) (RETVAL->m, x, ABS(SvIVX(yv)));
+            else
+              (*table[ix].op) (RETVAL->m, x, coerce_mpz (tmp_mpz_1, yv));
+            x = RETVAL->m;
+          }
+      }
+OUTPUT:
+    RETVAL
+
+
+void
+gcdext (a, b)
+    mpz_coerce a
+    mpz_coerce b
+PREINIT:
+    mpz g, x, y;
+    SV  *sv;
+PPCODE:
+    g = new_mpz();
+    x = new_mpz();
+    y = new_mpz();
+    mpz_gcdext (g->m, x->m, y->m, a, b);
+    EXTEND (SP, 3);
+    PUSHs (MPX_NEWMORTAL (g, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (x, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (y, mpz_class_hv));
+
+
+unsigned long
+hamdist (x, y)
+    mpz_coerce x
+    mpz_coerce y
+CODE:
+    RETVAL = mpz_hamdist (x, y);
+OUTPUT:
+    RETVAL
+
+
+mpz
+invert (a, m)
+    mpz_coerce a
+    mpz_coerce m
+CODE:
+    RETVAL = new_mpz();
+    if (! mpz_invert (RETVAL->m, a, m))
+      {
+        free_mpz (RETVAL);
+        XSRETURN_UNDEF;
+      }
+OUTPUT:
+    RETVAL
+
+
+int
+jacobi (a, b)
+    mpz_coerce a
+    mpz_coerce b
+CODE:
+    RETVAL = mpz_jacobi (a, b);
+OUTPUT:
+    RETVAL
+
+
+int
+kronecker (a, b)
+    SV *a
+    SV *b
+CODE:
+    if (SvIOK(b))
+      RETVAL = mpz_kronecker_si (coerce_mpz(tmp_mpz_0,a), SvIVX(b));
+    else if (SvIOK(a))
+      RETVAL = mpz_si_kronecker (SvIVX(a), coerce_mpz(tmp_mpz_0,b));
+    else
+      RETVAL = mpz_kronecker (coerce_mpz(tmp_mpz_0,a),
+                              coerce_mpz(tmp_mpz_1,b));
+OUTPUT:
+    RETVAL
+
+
+void
+mpz_export (order, size, endian, nails, z)
+    int        order
+    size_t     size
+    int        endian
+    size_t     nails
+    mpz_coerce z
+PREINIT:
+    size_t  numb, count, bytes, actual_count;
+    char    *data;
+    SV      *sv;
+PPCODE:
+    numb = 8*size - nails;
+    count = (mpz_sizeinbase (z, 2) + numb-1) / numb;
+    bytes = count * size;
+    New (GMP_MALLOC_ID, data, bytes+1, char);
+    mpz_export (data, &actual_count, order, size, endian, nails, z);
+    assert (count == actual_count);
+    data[bytes] = '\0';
+    sv = sv_newmortal(); sv_usepvn_mg (sv, data, bytes); PUSHs(sv);
+
+
+mpz
+mpz_import (order, size, endian, nails, sv)
+    int     order
+    size_t  size
+    int     endian
+    size_t  nails
+    SV      *sv
+PREINIT:
+    size_t      count;
+    const char  *data;
+    STRLEN      len;
+CODE:
+    data = SvPV (sv, len);
+    if ((len % size) != 0)
+      croak ("%s mpz_import: string not a multiple of the given size",
+             mpz_class);
+    count = len / size;
+    RETVAL = new_mpz();
+    mpz_import (RETVAL->m, count, order, size, endian, nails, data);
+OUTPUT:
+    RETVAL
+
+
+mpz
+nextprime (z)
+    mpz_coerce z
+CODE:
+    RETVAL = new_mpz();
+    mpz_nextprime (RETVAL->m, z);
+OUTPUT:
+    RETVAL
+
+
+unsigned long
+popcount (x)
+    mpz_coerce x
+CODE:
+    RETVAL = mpz_popcount (x);
+OUTPUT:
+    RETVAL
+
+
+mpz
+powm (b, e, m)
+    mpz_coerce b
+    mpz_coerce e
+    mpz_coerce m
+CODE:
+    RETVAL = new_mpz();
+    mpz_powm (RETVAL->m, b, e, m);
+OUTPUT:
+    RETVAL
+
+
+bool
+probab_prime_p (z, n)
+    mpz_coerce   z
+    ulong_coerce n
+CODE:
+    RETVAL = mpz_probab_prime_p (z, n);
+OUTPUT:
+    RETVAL
+
+
+# No attempt to coerce here, only an mpz makes sense.
+void
+realloc (z, limbs)
+    mpz z
+    int limbs
+CODE:
+    _mpz_realloc (z->m, limbs);
+
+
+void
+remove (z, f)
+    mpz_coerce z
+    mpz_coerce f
+PREINIT:
+    SV             *sv;
+    mpz            rem;
+    unsigned long  mult;
+PPCODE:
+    rem = new_mpz();
+    mult = mpz_remove (rem->m, z, f);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (rem, mpz_class_hv));
+    PUSHs (sv_2mortal (newSViv (mult)));
+
+
+void
+roote (z, n)
+    mpz_coerce   z
+    ulong_coerce n
+PREINIT:
+    SV  *sv;
+    mpz root;
+    int exact;
+PPCODE:
+    root = new_mpz();
+    exact = mpz_root (root->m, z, n);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (root, mpz_class_hv));
+    sv = (exact ? &PL_sv_yes : &PL_sv_no); sv_2mortal(sv); PUSHs(sv);
+
+
+void
+rootrem (z, n)
+    mpz_coerce   z
+    ulong_coerce n
+PREINIT:
+    SV  *sv;
+    mpz root;
+    mpz rem;
+PPCODE:
+    root = new_mpz();
+    rem = new_mpz();
+    mpz_rootrem (root->m, rem->m, z, n);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (root, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (rem,  mpz_class_hv));
+
+
+# In the past scan0 and scan1 were described as returning ULONG_MAX which
+# could be obtained in perl with ~0.  That wasn't true on 64-bit systems
+# (eg. alpha) with perl 5.005, since in that version IV and UV were still
+# 32-bits.
+#
+# We changed in gmp 4.2 to just say ~0 for the not-found return.  It's
+# likely most people have used ~0 rather than POSIX::ULONG_MAX(), so this
+# change should match existing usage.  It only actually makes a difference
+# in old perl, since recent versions have gone to 64-bits for IV and UV, the
+# same as a ulong.
+#
+# In perl 5.005 we explicitly mask the mpz return down to 32-bits to get ~0.
+# UV_MAX is no good, it reflects the size of the UV type (64-bits), rather
+# than the size of the values one ought to be storing in an SV (32-bits).
+
+gmp_UV
+scan0 (z, start)
+    mpz_coerce   z
+    ulong_coerce start
+ALIAS:
+    GMP::Mpz::scan1 = 1
+PREINIT:
+    static_functable const struct {
+      unsigned long (*op) (mpz_srcptr, unsigned long);
+    } table[] = {
+      { mpz_scan0  }, /* 0 */
+      { mpz_scan1  }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = (*table[ix].op) (z, start);
+    if (PERL_LT (5,6))
+      RETVAL &= 0xFFFFFFFF;
+OUTPUT:
+    RETVAL
+
+
+void
+setbit (sv, bit)
+    SV           *sv
+    ulong_coerce bit
+ALIAS:
+    GMP::Mpz::clrbit = 1
+    GMP::Mpz::combit = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, unsigned long);
+    } table[] = {
+      { mpz_setbit }, /* 0 */
+      { mpz_clrbit }, /* 1 */
+      { mpz_combit }, /* 2 */
+    };
+    int  use;
+    mpz  z;
+CODE:
+    use = use_sv (sv);
+    if (use == USE_MPZ && SvREFCNT(SvRV(sv)) == 1 && ! SvSMAGICAL(sv))
+      {
+        /* our operand is a non-magical mpz with a reference count of 1, so
+           we can just modify it */
+        (*table[ix].op) (SvMPZ(sv)->m, bit);
+      }
+    else
+      {
+        /* otherwise we need to make a new mpz, from whatever we have, and
+           operate on that, possibly invoking magic when storing back */
+        SV   *new_sv;
+        mpz  z = new_mpz ();
+        mpz_ptr  coerce_ptr = coerce_mpz_using (z->m, sv, use);
+        if (coerce_ptr != z->m)
+          mpz_set (z->m, coerce_ptr);
+        (*table[ix].op) (z->m, bit);
+        new_sv = sv_bless (sv_setref_pv (sv_newmortal(), NULL, z),
+                           mpz_class_hv);
+        SvSetMagicSV (sv, new_sv);
+      }
+
+
+void
+sqrtrem (z)
+    mpz_coerce z
+PREINIT:
+    SV  *sv;
+    mpz root;
+    mpz rem;
+PPCODE:
+    root = new_mpz();
+    rem = new_mpz();
+    mpz_sqrtrem (root->m, rem->m, z);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (root, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (rem,  mpz_class_hv));
+
+
+size_t
+sizeinbase (z, base)
+    mpz_coerce z
+    int        base
+CODE:
+    RETVAL = mpz_sizeinbase (z, base);
+OUTPUT:
+    RETVAL
+
+
+int
+tstbit (z, bit)
+    mpz_coerce   z
+    ulong_coerce bit
+CODE:
+    RETVAL = mpz_tstbit (z, bit);
+OUTPUT:
+    RETVAL
+
+
+
+#------------------------------------------------------------------------------
+
+MODULE = GMP         PACKAGE = GMP::Mpq
+
+
+mpq
+mpq (...)
+ALIAS:
+    GMP::Mpq::new = 1
+CODE:
+    TRACE (printf ("%s new, ix=%ld, items=%d\n", mpq_class, ix, (int) items));
+    RETVAL = new_mpq();
+    switch (items) {
+    case 0:
+      mpq_set_ui (RETVAL->m, 0L, 1L);
+      break;
+    case 1:
+      {
+        mpq_ptr rp = RETVAL->m;
+        mpq_ptr cp = coerce_mpq (rp, ST(0));
+        if (cp != rp)
+          mpq_set (rp, cp);
+      }
+      break;
+    case 2:
+      {
+        mpz_ptr rp, cp;
+        rp = mpq_numref (RETVAL->m);
+        cp = coerce_mpz (rp, ST(0));
+        if (cp != rp)
+          mpz_set (rp, cp);
+        rp = mpq_denref (RETVAL->m);
+        cp = coerce_mpz (rp, ST(1));
+        if (cp != rp)
+          mpz_set (rp, cp);
+      }
+      break;
+    default:
+      croak ("%s new: invalid arguments", mpq_class);
+    }
+OUTPUT:
+    RETVAL
+
+
+void
+overload_constant (str, pv, d1, ...)
+    const_string_assume str
+    SV                  *pv
+    dummy               d1
+PREINIT:
+    SV  *sv;
+    mpq q;
+PPCODE:
+    TRACE (printf ("%s constant: %s\n", mpq_class, str));
+    q = new_mpq();
+    if (mpq_set_str (q->m, str, 0) == 0)
+      { sv = sv_bless (sv_setref_pv (sv_newmortal(), NULL, q), mpq_class_hv); }
+    else
+      { free_mpq (q); sv = pv; }
+    XPUSHs(sv);
+
+
+mpq
+overload_copy (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+CODE:
+    RETVAL = new_mpq();
+    mpq_set (RETVAL->m, q->m);
+OUTPUT:
+    RETVAL
+
+
+void
+DESTROY (q)
+    mpq_assume q
+CODE:
+    TRACE (printf ("%s DESTROY %p\n", mpq_class, q));
+    free_mpq (q);
+
+
+malloced_string
+overload_string (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+CODE:
+    TRACE (printf ("%s overload_string %p\n", mpq_class, q));
+    RETVAL = mpq_get_str (NULL, 10, q->m);
+OUTPUT:
+    RETVAL
+
+
+mpq
+overload_add (xv, yv, order)
+    SV *xv
+    SV *yv
+    SV *order
+ALIAS:
+    GMP::Mpq::overload_sub   = 1
+    GMP::Mpq::overload_mul   = 2
+    GMP::Mpq::overload_div   = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr, mpq_srcptr, mpq_srcptr);
+    } table[] = {
+      { mpq_add }, /* 0 */
+      { mpq_sub }, /* 1 */
+      { mpq_mul }, /* 2 */
+      { mpq_div }, /* 3 */
+    };
+CODE:
+    TRACE (printf ("%s binary\n", mpf_class));
+    assert_table (ix);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (xv, yv);
+    RETVAL = new_mpq();
+    (*table[ix].op) (RETVAL->m,
+                     coerce_mpq (tmp_mpq_0, xv),
+                     coerce_mpq (tmp_mpq_1, yv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_addeq (x, y, o)
+    mpq_assume   x
+    mpq_coerce   y
+    order_noswap o
+ALIAS:
+    GMP::Mpq::overload_subeq = 1
+    GMP::Mpq::overload_muleq = 2
+    GMP::Mpq::overload_diveq = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr, mpq_srcptr, mpq_srcptr);
+    } table[] = {
+      { mpq_add    }, /* 0 */
+      { mpq_sub    }, /* 1 */
+      { mpq_mul    }, /* 2 */
+      { mpq_div    }, /* 3 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (x->m, x->m, y);
+    XPUSHs(ST(0));
+
+
+mpq
+overload_lshift (qv, nv, order)
+    SV *qv
+    SV *nv
+    SV *order
+ALIAS:
+    GMP::Mpq::overload_rshift   = 1
+    GMP::Mpq::overload_pow      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr, mpq_srcptr, unsigned long);
+    } table[] = {
+      { mpq_mul_2exp }, /* 0 */
+      { mpq_div_2exp }, /* 1 */
+      { x_mpq_pow_ui }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (qv, nv);
+    RETVAL = new_mpq();
+    (*table[ix].op) (RETVAL->m, coerce_mpq (RETVAL->m, qv), coerce_ulong (nv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_lshifteq (q, n, o)
+    mpq_assume   q
+    ulong_coerce n
+    order_noswap o
+ALIAS:
+    GMP::Mpq::overload_rshifteq   = 1
+    GMP::Mpq::overload_poweq      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr, mpq_srcptr, unsigned long);
+    } table[] = {
+      { mpq_mul_2exp }, /* 0 */
+      { mpq_div_2exp }, /* 1 */
+      { x_mpq_pow_ui }, /* 2 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (q->m, q->m, n);
+    XPUSHs(ST(0));
+
+
+void
+overload_inc (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpq::overload_dec = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_add }, /* 0 */
+      { mpz_sub }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    (*table[ix].op) (mpq_numref(q->m), mpq_numref(q->m), mpq_denref(q->m));
+
+
+mpq
+overload_abs (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpq::overload_neg = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr w, mpq_srcptr x);
+    } table[] = {
+      { mpq_abs }, /* 0 */
+      { mpq_neg }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpq();
+    (*table[ix].op) (RETVAL->m, q->m);
+OUTPUT:
+    RETVAL
+
+
+int
+overload_spaceship (x, y, order)
+    mpq_assume x
+    mpq_coerce y
+    SV         *order
+CODE:
+    RETVAL = mpq_cmp (x->m, y);
+    RETVAL = SGN (RETVAL);
+    if (order == &PL_sv_yes)
+      RETVAL = -RETVAL;
+OUTPUT:
+    RETVAL
+
+
+bool
+overload_bool (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpq::overload_not = 1
+CODE:
+    RETVAL = (mpq_sgn (q->m) != 0) ^ ix;
+OUTPUT:
+    RETVAL
+
+
+bool
+overload_eq (x, yv, d)
+    mpq_assume x
+    SV         *yv
+    dummy      d
+ALIAS:
+    GMP::Mpq::overload_ne = 1
+PREINIT:
+    int  use;
+CODE:
+    use = use_sv (yv);
+    switch (use) {
+    case USE_IVX:
+    case USE_UVX:
+    case USE_MPZ:
+      RETVAL = 0;
+      if (x_mpq_integer_p (x->m))
+        {
+          switch (use) {
+          case USE_IVX:
+            RETVAL = (mpz_cmp_si (mpq_numref(x->m), SvIVX(yv)) == 0);
+            break;
+          case USE_UVX:
+            RETVAL = (mpz_cmp_ui (mpq_numref(x->m), SvUVX(yv)) == 0);
+            break;
+          case USE_MPZ:
+            RETVAL = (mpz_cmp (mpq_numref(x->m), SvMPZ(yv)->m) == 0);
+            break;
+          }
+        }
+      break;
+
+    case USE_MPQ:
+      RETVAL = (mpq_equal (x->m, SvMPQ(yv)->m) != 0);
+      break;
+
+    default:
+      RETVAL = (mpq_equal (x->m, coerce_mpq_using (tmp_mpq_0, yv, use)) != 0);
+      break;
+    }
+    RETVAL ^= ix;
+OUTPUT:
+    RETVAL
+
+
+void
+canonicalize (q)
+    mpq q
+CODE:
+    mpq_canonicalize (q->m);
+
+
+mpq
+inv (q)
+    mpq_coerce q
+CODE:
+    RETVAL = new_mpq();
+    mpq_inv (RETVAL->m, q);
+OUTPUT:
+    RETVAL
+
+
+mpz
+num (q)
+    mpq q
+ALIAS:
+    GMP::Mpq::den = 1
+CODE:
+    RETVAL = new_mpz();
+    mpz_set (RETVAL->m, (ix == 0 ? mpq_numref(q->m) : mpq_denref(q->m)));
+OUTPUT:
+    RETVAL
+
+
+
+#------------------------------------------------------------------------------
+
+MODULE = GMP         PACKAGE = GMP::Mpf
+
+
+mpf
+mpf (...)
+ALIAS:
+    GMP::Mpf::new = 1
+PREINIT:
+    unsigned long  prec;
+CODE:
+    TRACE (printf ("%s new\n", mpf_class));
+    if (items > 2)
+      croak ("%s new: invalid arguments", mpf_class);
+    prec = (items == 2 ? coerce_ulong (ST(1)) : mpf_get_default_prec());
+    RETVAL = new_mpf (prec);
+    if (items >= 1)
+      {
+        SV *sv = ST(0);
+        my_mpf_set_sv_using (RETVAL, sv, use_sv(sv));
+      }
+OUTPUT:
+    RETVAL
+
+
+mpf
+overload_constant (sv, d1, d2, ...)
+    SV     *sv
+    dummy  d1
+    dummy  d2
+CODE:
+    assert (SvPOK (sv));
+    TRACE (printf ("%s constant: %s\n", mpq_class, SvPVX(sv)));
+    RETVAL = new_mpf (mpf_get_default_prec());
+    my_mpf_set_svstr (RETVAL, sv);
+OUTPUT:
+    RETVAL
+
+
+mpf
+overload_copy (f, d1, d2)
+    mpf_assume f
+    dummy      d1
+    dummy      d2
+CODE:
+    TRACE (printf ("%s copy\n", mpf_class));
+    RETVAL = new_mpf (mpf_get_prec (f));
+    mpf_set (RETVAL, f);
+OUTPUT:
+    RETVAL
+
+
+void
+DESTROY (f)
+    mpf_assume f
+CODE:
+    TRACE (printf ("%s DESTROY %p\n", mpf_class, f));
+    mpf_clear (f);
+    Safefree (f);
+    assert_support (mpf_count--);
+    TRACE_ACTIVE ();
+
+
+mpf
+overload_add (x, y, order)
+    mpf_assume     x
+    mpf_coerce_st0 y
+    SV             *order
+ALIAS:
+    GMP::Mpf::overload_sub   = 1
+    GMP::Mpf::overload_mul   = 2
+    GMP::Mpf::overload_div   = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr, mpf_srcptr, mpf_srcptr);
+    } table[] = {
+      { mpf_add }, /* 0 */
+      { mpf_sub }, /* 1 */
+      { mpf_mul }, /* 2 */
+      { mpf_div }, /* 3 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpf (mpf_get_prec (x));
+    if (order == &PL_sv_yes)
+      MPF_PTR_SWAP (x, y);
+    (*table[ix].op) (RETVAL, x, y);
+OUTPUT:
+    RETVAL
+
+
+void
+overload_addeq (x, y, o)
+    mpf_assume     x
+    mpf_coerce_st0 y
+    order_noswap   o
+ALIAS:
+    GMP::Mpf::overload_subeq = 1
+    GMP::Mpf::overload_muleq = 2
+    GMP::Mpf::overload_diveq = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr, mpf_srcptr, mpf_srcptr);
+    } table[] = {
+      { mpf_add }, /* 0 */
+      { mpf_sub }, /* 1 */
+      { mpf_mul }, /* 2 */
+      { mpf_div }, /* 3 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (x, x, y);
+    XPUSHs(ST(0));
+
+
+mpf
+overload_lshift (fv, nv, order)
+    SV *fv
+    SV *nv
+    SV *order
+ALIAS:
+    GMP::Mpf::overload_rshift = 1
+    GMP::Mpf::overload_pow    = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr, mpf_srcptr, unsigned long);
+    } table[] = {
+      { mpf_mul_2exp }, /* 0 */
+      { mpf_div_2exp }, /* 1 */
+      { mpf_pow_ui   }, /* 2 */
+    };
+    mpf f;
+    unsigned long prec;
+CODE:
+    assert_table (ix);
+    MPF_ASSUME (f, fv);
+    prec = mpf_get_prec (f);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (fv, nv);
+    f = coerce_mpf (tmp_mpf_0, fv, prec);
+    RETVAL = new_mpf (prec);
+    (*table[ix].op) (RETVAL, f, coerce_ulong (nv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_lshifteq (f, n, o)
+    mpf_assume   f
+    ulong_coerce n
+    order_noswap o
+ALIAS:
+    GMP::Mpf::overload_rshifteq   = 1
+    GMP::Mpf::overload_poweq      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr, mpf_srcptr, unsigned long);
+    } table[] = {
+      { mpf_mul_2exp }, /* 0 */
+      { mpf_div_2exp }, /* 1 */
+      { mpf_pow_ui   }, /* 2 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (f, f, n);
+    XPUSHs(ST(0));
+
+
+mpf
+overload_abs (f, d1, d2)
+    mpf_assume f
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpf::overload_neg   = 1
+    GMP::Mpf::overload_sqrt  = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr w, mpf_srcptr x);
+    } table[] = {
+      { mpf_abs  }, /* 0 */
+      { mpf_neg  }, /* 1 */
+      { mpf_sqrt }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpf (mpf_get_prec (f));
+    (*table[ix].op) (RETVAL, f);
+OUTPUT:
+    RETVAL
+
+
+void
+overload_inc (f, d1, d2)
+    mpf_assume f
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpf::overload_dec = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr w, mpf_srcptr x, unsigned long y);
+    } table[] = {
+      { mpf_add_ui }, /* 0 */
+      { mpf_sub_ui }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    (*table[ix].op) (f, f, 1L);
+
+
+int
+overload_spaceship (xv, yv, order)
+    SV *xv
+    SV *yv
+    SV *order
+PREINIT:
+    mpf x;
+CODE:
+    MPF_ASSUME (x, xv);
+    switch (use_sv (yv)) {
+    case USE_IVX:
+      RETVAL = mpf_cmp_si (x, SvIVX(yv));
+      break;
+    case USE_UVX:
+      RETVAL = mpf_cmp_ui (x, SvUVX(yv));
+      break;
+    case USE_NVX:
+      RETVAL = mpf_cmp_d (x, SvNVX(yv));
+      break;
+    case USE_PVX:
+      {
+        STRLEN len;
+        const char *str = SvPV (yv, len);
+        /* enough for all digits of the string */
+        tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64);
+        if (mpf_set_str (tmp_mpf_0->m, str, 10) != 0)
+          croak ("%s <=>: invalid string format", mpf_class);
+        RETVAL = mpf_cmp (x, tmp_mpf_0->m);
+      }
+      break;
+    case USE_MPZ:
+      RETVAL = - x_mpz_cmp_f (SvMPZ(yv)->m, x);
+      break;
+    case USE_MPF:
+      RETVAL = mpf_cmp (x, SvMPF(yv));
+      break;
+    default:
+      RETVAL = mpq_cmp (coerce_mpq (tmp_mpq_0, xv),
+                        coerce_mpq (tmp_mpq_1, yv));
+      break;
+    }
+    RETVAL = SGN (RETVAL);
+    if (order == &PL_sv_yes)
+      RETVAL = -RETVAL;
+OUTPUT:
+    RETVAL
+
+
+bool
+overload_bool (f, d1, d2)
+    mpf_assume f
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpf::overload_not = 1
+CODE:
+    RETVAL = (mpf_sgn (f) != 0) ^ ix;
+OUTPUT:
+    RETVAL
+
+
+mpf
+ceil (f)
+    mpf_coerce_def f
+ALIAS:
+    GMP::Mpf::floor = 1
+    GMP::Mpf::trunc = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr w, mpf_srcptr x);
+    } table[] = {
+      { mpf_ceil  }, /* 0 */
+      { mpf_floor }, /* 1 */
+      { mpf_trunc }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpf (mpf_get_prec (f));
+    (*table[ix].op) (RETVAL, f);
+OUTPUT:
+    RETVAL
+
+
+unsigned long
+get_default_prec ()
+CODE:
+    RETVAL = mpf_get_default_prec();
+OUTPUT:
+    RETVAL
+
+
+unsigned long
+get_prec (f)
+    mpf_coerce_def f
+CODE:
+    RETVAL = mpf_get_prec (f);
+OUTPUT:
+    RETVAL
+
+
+bool
+mpf_eq (xv, yv, bits)
+    SV           *xv
+    SV           *yv
+    ulong_coerce bits
+PREINIT:
+    mpf  x, y;
+CODE:
+    TRACE (printf ("%s eq\n", mpf_class));
+    coerce_mpf_pair (&x,xv, &y,yv);
+    RETVAL = mpf_eq (x, y, bits);
+OUTPUT:
+    RETVAL
+
+
+mpf
+reldiff (xv, yv)
+    SV *xv
+    SV *yv
+PREINIT:
+    mpf  x, y;
+    unsigned long prec;
+CODE:
+    TRACE (printf ("%s reldiff\n", mpf_class));
+    prec = coerce_mpf_pair (&x,xv, &y,yv);
+    RETVAL = new_mpf (prec);
+    mpf_reldiff (RETVAL, x, y);
+OUTPUT:
+    RETVAL
+
+
+void
+set_default_prec (prec)
+    ulong_coerce prec
+CODE:
+    TRACE (printf ("%s set_default_prec %lu\n", mpf_class, prec));
+    mpf_set_default_prec (prec);
+
+
+void
+set_prec (sv, prec)
+    SV           *sv
+    ulong_coerce prec
+PREINIT:
+    mpf_ptr  old_f, new_f;
+    int      use;
+CODE:
+    TRACE (printf ("%s set_prec to %lu\n", mpf_class, prec));
+    use = use_sv (sv);
+    if (use == USE_MPF)
+      {
+        old_f = SvMPF(sv);
+        if (SvREFCNT(SvRV(sv)) == 1)
+          mpf_set_prec (old_f, prec);
+        else
+          {
+            TRACE (printf ("  fork new mpf\n"));
+            new_f = new_mpf (prec);
+            mpf_set (new_f, old_f);
+            goto setref;
+          }
+      }
+    else
+      {
+        TRACE (printf ("  coerce to mpf\n"));
+        new_f = new_mpf (prec);
+        my_mpf_set_sv_using (new_f, sv, use);
+      setref:
+        sv_bless (sv_setref_pv (sv, NULL, new_f), mpf_class_hv);
+      }
+
+
+
+#------------------------------------------------------------------------------
+
+MODULE = GMP         PACKAGE = GMP::Rand
+
+randstate
+new (...)
+ALIAS:
+    GMP::Rand::randstate = 1
+CODE:
+    TRACE (printf ("%s new\n", rand_class));
+    New (GMP_MALLOC_ID, RETVAL, 1, __gmp_randstate_struct);
+    TRACE (printf ("  RETVAL %p\n", RETVAL));
+    assert_support (rand_count++);
+    TRACE_ACTIVE ();
+
+    if (items == 0)
+      {
+        gmp_randinit_default (RETVAL);
+      }
+    else
+      {
+        if (SvROK (ST(0)) && sv_derived_from (ST(0), rand_class))
+          {
+            if (items != 1)
+              goto invalid;
+            gmp_randinit_set (RETVAL, SvRANDSTATE (ST(0)));
+          }
+        else
+          {
+            STRLEN      len;
+            const char  *method = SvPV (ST(0), len);
+            assert (len == strlen (method));
+            if (strcmp (method, "lc_2exp") == 0)
+              {
+                if (items != 4)
+                  goto invalid;
+                gmp_randinit_lc_2exp (RETVAL,
+                                      coerce_mpz (tmp_mpz_0, ST(1)),
+                                      coerce_ulong (ST(2)),
+                                      coerce_ulong (ST(3)));
+              }
+            else if (strcmp (method, "lc_2exp_size") == 0)
+              {
+                if (items != 2)
+                  goto invalid;
+                if (! gmp_randinit_lc_2exp_size (RETVAL, coerce_ulong (ST(1))))
+                  {
+                    Safefree (RETVAL);
+                    XSRETURN_UNDEF;
+                  }
+              }
+            else if (strcmp (method, "mt") == 0)
+              {
+                if (items != 1)
+                  goto invalid;
+                gmp_randinit_mt (RETVAL);
+              }
+            else
+              {
+              invalid:
+                croak ("%s new: invalid arguments", rand_class);
+              }
+          }
+      }
+OUTPUT:
+    RETVAL
+
+
+void
+DESTROY (r)
+    randstate r
+CODE:
+    TRACE (printf ("%s DESTROY\n", rand_class));
+    gmp_randclear (r);
+    Safefree (r);
+    assert_support (rand_count--);
+    TRACE_ACTIVE ();
+
+
+void
+seed (r, z)
+    randstate  r
+    mpz_coerce z
+CODE:
+    gmp_randseed (r, z);
+
+
+mpz
+mpz_urandomb (r, bits)
+    randstate    r
+    ulong_coerce bits
+ALIAS:
+    GMP::Rand::mpz_rrandomb = 1
+PREINIT:
+    static_functable const struct {
+      void (*fun) (mpz_ptr, gmp_randstate_t r, unsigned long bits);
+    } table[] = {
+      { mpz_urandomb }, /* 0 */
+      { mpz_rrandomb }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].fun) (RETVAL->m, r, bits);
+OUTPUT:
+    RETVAL
+
+
+mpz
+mpz_urandomm (r, m)
+    randstate  r
+    mpz_coerce m
+CODE:
+    RETVAL = new_mpz();
+    mpz_urandomm (RETVAL->m, r, m);
+OUTPUT:
+    RETVAL
+
+
+mpf
+mpf_urandomb (r, bits)
+    randstate    r
+    ulong_coerce bits
+CODE:
+    RETVAL = new_mpf (bits);
+    mpf_urandomb (RETVAL, r, bits);
+OUTPUT:
+    RETVAL
+
+
+unsigned long
+gmp_urandomb_ui (r, bits)
+    randstate    r
+    ulong_coerce bits
+ALIAS:
+    GMP::Rand::gmp_urandomm_ui = 1
+PREINIT:
+    static_functable const struct {
+      unsigned long (*fun) (gmp_randstate_t r, unsigned long bits);
+    } table[] = {
+      { gmp_urandomb_ui }, /* 0 */
+      { gmp_urandomm_ui }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = (*table[ix].fun) (r, bits);
+OUTPUT:
+    RETVAL
diff --git a/third_party/gmp/demos/perl/GMP/Mpf.pm b/third_party/gmp/demos/perl/GMP/Mpf.pm
new file mode 100644
index 0000000..4c0dec6
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP/Mpf.pm
@@ -0,0 +1,106 @@
+# GMP mpf module.
+
+# Copyright 2001, 2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+package GMP::Mpf;
+
+require GMP;
+require Exporter;
+@ISA = qw(GMP Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw();
+%EXPORT_TAGS = ('all' => [qw(
+			     ceil floor get_default_prec get_prec mpf mpf_eq
+			     reldiff set_default_prec set_prec trunc)],
+		'constants'   => [@EXPORT],
+		'noconstants' => [@EXPORT]);
+Exporter::export_ok_tags('all');
+
+use overload
+    '+'   => \&overload_add,     '+='  => \&overload_addeq,
+    '-'   => \&overload_sub,     '-='  => \&overload_subeq,
+    '*'   => \&overload_mul,     '*='  => \&overload_muleq,
+    '/'   => \&overload_div,     '/='  => \&overload_diveq,
+    '**'  => \&overload_pow,     '**=' => \&overload_poweq,
+    '<<'  => \&overload_lshift,  '<<=' => \&overload_lshifteq,
+    '>>'  => \&overload_rshift,  '>>=' => \&overload_rshifteq,
+
+    'bool' => \&overload_bool,
+    'not'  => \&overload_not,
+    '!'    => \&overload_not,
+    '<=>'  => \&overload_spaceship,
+    '++'   => \&overload_inc,
+    '--'   => \&overload_dec,
+    'abs'  => \&overload_abs,
+    'neg'  => \&overload_neg,
+    'sqrt' => \&overload_sqrt,
+    '='    => \&overload_copy,
+    '""'   => \&overload_string;
+
+sub import {
+  foreach (@_) {
+    if ($_ eq ':constants') {
+      overload::constant ('integer' => \&overload_constant,
+			  'binary'  => \&overload_constant,
+			  'float'   => \&overload_constant);
+    } elsif ($_ eq ':noconstants') {
+      overload::remove_constant ('integer' => \&overload_constant,
+				 'binary'  => \&overload_constant,
+				 'float'   => \&overload_constant);
+    }
+  }
+  goto &Exporter::import;
+}
+
+
+sub overload_string {
+  my $fmt;
+  BEGIN { $^W = 0; }
+  if (defined ($#)) {
+    $fmt = $#;
+    BEGIN { $^W = 1; }
+    # protect against calling sprintf_internal with a bad format
+    if ($fmt !~ /^((%%|[^%])*%[-+ .\d]*)([eEfgG](%%|[^%])*)$/) {
+      die "GMP::Mpf: invalid \$# format: $#\n";
+    }
+    $fmt = $1 . 'F' . $3;
+  } else {
+    $fmt = '%.Fg';
+  }
+  GMP::sprintf_internal ($fmt, $_[0]);
+}
+
+1;
+__END__
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/GMP/Mpq.pm b/third_party/gmp/demos/perl/GMP/Mpq.pm
new file mode 100644
index 0000000..fe01084
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP/Mpq.pm
@@ -0,0 +1,89 @@
+# GMP mpq module.
+
+# Copyright 2001 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+package GMP::Mpq;
+
+require GMP;
+require Exporter;
+@ISA = qw(GMP Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw();
+%EXPORT_TAGS = ('all' => [qw(canonicalize den inv mpq num)],
+		'constants'   => [@EXPORT],
+		'noconstants' => [@EXPORT] );
+Exporter::export_ok_tags('all');
+
+use overload
+    '+'   => \&overload_add,     '+='  => \&overload_addeq,
+    '-'   => \&overload_sub,     '-='  => \&overload_subeq,
+    '*'   => \&overload_mul,     '*='  => \&overload_muleq,
+    '/'   => \&overload_div,     '/='  => \&overload_diveq,
+    '**'  => \&overload_pow,     '**=' => \&overload_poweq,
+    '<<'  => \&overload_lshift,  '<<=' => \&overload_lshifteq,
+    '>>'  => \&overload_rshift,  '>>=' => \&overload_rshifteq,
+
+    'bool' => \&overload_bool,
+    'not'  => \&overload_not,
+    '!'    => \&overload_not,
+    '=='   => \&overload_eq,
+    '!='   => \&overload_ne,
+    '<=>'  => \&overload_spaceship,
+    '++'   => \&overload_inc,
+    '--'   => \&overload_dec,
+    'abs'  => \&overload_abs,
+    'neg'  => \&overload_neg,
+    '='    => \&overload_copy,
+    '""'   => \&overload_string;
+
+my $constants = { };
+
+sub import {
+  foreach (@_) {
+    if ($_ eq ':constants') {
+      overload::constant ('integer' => \&overload_constant,
+			  'binary'  => \&overload_constant,
+			  'float'   => \&overload_constant);
+    } elsif ($_ eq ':noconstants') {
+      overload::remove_constant ('integer' => \&overload_constant,
+				 'binary'  => \&overload_constant,
+				 'float'   => \&overload_constant);
+    }
+  }
+  goto &Exporter::import;
+}
+
+1;
+__END__
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/GMP/Mpz.pm b/third_party/gmp/demos/perl/GMP/Mpz.pm
new file mode 100644
index 0000000..27e6336
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP/Mpz.pm
@@ -0,0 +1,101 @@
+# GMP mpz module.
+
+# Copyright 2001-2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+package GMP::Mpz;
+
+require GMP;
+require Exporter;
+@ISA = qw(GMP Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw();
+%EXPORT_TAGS = ('all' => [qw(
+			     bin cdiv cdiv_2exp clrbit combit congruent_p
+			     congruent_2exp_p divexact divisible_p
+			     divisible_2exp_p even_p fac fdiv fdiv_2exp fib
+			     fib2 gcd gcdext hamdist invert jacobi kronecker
+			     lcm lucnum lucnum2 mod mpz mpz_export
+			     mpz_import nextprime odd_p perfect_power_p
+			     perfect_square_p popcount powm probab_prime_p
+			     realloc remove root roote rootrem scan0 scan1
+			     setbit sizeinbase sqrtrem tdiv tdiv_2exp
+			     tstbit)],
+		'constants'   => [@EXPORT],
+		'noconstants' => [@EXPORT]);
+Exporter::export_ok_tags('all');
+
+use overload
+    '+'    => \&overload_add,     '+='   => \&overload_addeq,
+    '-'    => \&overload_sub,     '-='   => \&overload_subeq,
+    '*'    => \&overload_mul,     '*='   => \&overload_muleq,
+    '/'    => \&overload_div,     '/='   => \&overload_diveq,
+    '%'    => \&overload_rem,     '%='   => \&overload_remeq,
+    '<<'   => \&overload_lshift,  '<<='  => \&overload_lshifteq,
+    '>>'   => \&overload_rshift,  '>>='  => \&overload_rshifteq,
+    '**'   => \&overload_pow,     '**='  => \&overload_poweq,
+    '&'    => \&overload_and,     '&='   => \&overload_andeq,
+    '|'    => \&overload_ior,     '|='   => \&overload_ioreq,
+    '^'    => \&overload_xor,     '^='   => \&overload_xoreq,
+
+    'bool' => \&overload_bool,
+    'not'  => \&overload_not,
+    '!'    => \&overload_not,
+    '~'    => \&overload_com,
+    '<=>'  => \&overload_spaceship,
+    '++'   => \&overload_inc,
+    '--'   => \&overload_dec,
+    '='    => \&overload_copy,
+    'abs'  => \&overload_abs,
+    'neg'  => \&overload_neg,
+    'sqrt' => \&overload_sqrt,
+    '""'   => \&overload_string;
+
+sub import {
+  foreach (@_) {
+    if ($_ eq ':constants') {
+      overload::constant ('integer' => \&overload_constant,
+			  'binary'  => \&overload_constant,
+			  'float'   => \&overload_constant);
+    } elsif ($_ eq ':noconstants') {
+      overload::remove_constant ('integer' => \&overload_constant,
+				 'binary'  => \&overload_constant,
+				 'float'   => \&overload_constant);
+    }
+  }
+  goto &Exporter::import;
+}
+
+1;
+__END__
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/GMP/Rand.pm b/third_party/gmp/demos/perl/GMP/Rand.pm
new file mode 100644
index 0000000..9f7d763
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP/Rand.pm
@@ -0,0 +1,44 @@
+# GMP random numbers module.
+
+# Copyright 2001, 2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+package GMP::Rand;
+
+require GMP;
+require Exporter;
+@ISA = qw(GMP Exporter);
+@EXPORT = qw();
+%EXPORT_TAGS = ('all' => [qw(
+			     randstate mpf_urandomb mpz_rrandomb
+			     mpz_urandomb mpz_urandomm gmp_urandomb_ui
+			     gmp_urandomm_ui)]);
+Exporter::export_ok_tags('all');
+1;
+__END__
diff --git a/third_party/gmp/demos/perl/INSTALL b/third_party/gmp/demos/perl/INSTALL
new file mode 100644
index 0000000..f3d7c53
--- /dev/null
+++ b/third_party/gmp/demos/perl/INSTALL
@@ -0,0 +1,88 @@
+Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+                  GMP PERL MODULE INSTALLATION
+
+
+This module can be compiled within the GMP source directory or moved
+elsewhere and compiled.  An installed GMP can be used, or a specified
+GMP build tree.  Both static and shared GMP builds will work.
+
+The simplest case is when GMP has been installed to a standard system
+location
+
+	perl Makefile.PL
+	make
+
+If not yet installed then the top-level GMP build directory must be
+specified
+
+	perl Makefile.PL GMP_BUILDDIR=/my/gmp/build
+	make
+
+In any case, with the module built, the sample program provided can be
+run
+
+	perl -Iblib/arch sample.pl
+
+If you built a shared version of libgmp but haven't yet installed it,
+then it might be necessary to add a run-time path to it.  For example
+
+	LD_LIBRARY_PATH=/my/gmp/build/.libs perl -Iblib/arch sample.pl
+
+Documentation is provided in pod format in GMP.pm, and will have been
+"man"-ified in the module build
+
+	man -l blib/man3/GMP.3pm
+or
+	man -M`pwd`/blib GMP
+
+A test script is provided, running a large number of more or less
+trivial checks
+
+	make test
+
+The module and its documentation can be installed in the usual way
+
+	make install
+
+This will be into /usr/local or wherever the perl Config module
+directs, but that can be controlled back at the Makefile.PL stage with
+the usual ExtUtils::MakeMaker options.
+
+Once installed, programs using the GMP module become simply
+
+	perl sample.pl
+
+And the documentation read directly too
+
+	man GMP
diff --git a/third_party/gmp/demos/perl/Makefile.PL b/third_party/gmp/demos/perl/Makefile.PL
new file mode 100644
index 0000000..a676710
--- /dev/null
+++ b/third_party/gmp/demos/perl/Makefile.PL
@@ -0,0 +1,82 @@
+# Makefile for GMP perl module.
+
+# Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Bugs:
+#
+# When the generated Makefile re-runs "perl Makefile.PL" the GMP_BUILDDIR
+# parameter is lost.
+
+
+use ExtUtils::MakeMaker;
+
+
+# Find and remove our parameters
+@ARGV = map {
+  if (/^GMP_BUILDDIR=(.*)/) {
+    $GMP_BUILDDIR=$1; ();
+  } else {
+    $_;
+  }
+} (@ARGV);
+
+$INC = "";
+$LIBS = "-lgmp";
+$OBJECT = "GMP.o";
+
+if (defined $GMP_BUILDDIR) {
+  if (! -f "$GMP_BUILDDIR/libgmp.la") {
+    die "$GMP_BUILDDIR doesn't contain libgmp.la\n" .
+	"if it's really a gmp build directory then go there and run \"make libgmp.la\"\n";
+  }
+  $INC = "-I$GMP_BUILDDIR $INC";
+  $LIBS = "-L$GMP_BUILDDIR/.libs $LIBS";
+}
+
+WriteMakefile(
+	      NAME         => 'GMP',
+	      VERSION      => '2.00',
+	      LIBS         => [$LIBS],
+	      OBJECT       => $OBJECT,
+	      INC          => $INC,
+	      clean        => { FILES => 'test.tmp' },
+	      PM => {
+		'GMP.pm'      => '$(INST_LIBDIR)/GMP.pm',
+		'GMP/Mpz.pm'  => '$(INST_LIBDIR)/GMP/Mpz.pm',
+		'GMP/Mpq.pm'  => '$(INST_LIBDIR)/GMP/Mpq.pm',
+		'GMP/Mpf.pm'  => '$(INST_LIBDIR)/GMP/Mpf.pm',
+		'GMP/Rand.pm' => '$(INST_LIBDIR)/GMP/Rand.pm',
+	      }
+	      );
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/sample.pl b/third_party/gmp/demos/perl/sample.pl
new file mode 100644
index 0000000..8a10ee1
--- /dev/null
+++ b/third_party/gmp/demos/perl/sample.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl -w
+
+# Some sample GMP module operations
+
+# Copyright 2001, 2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+use strict;
+
+
+use GMP;
+print "using GMP module $GMP::VERSION and GMP library ",GMP::version(),"\n";
+
+
+use GMP::Mpz qw(:all);
+print "the 200th fibonacci number is ", fib(200), "\n";
+print "next prime after 10**30 is (probably) ", nextprime(mpz(10)**30), "\n";
+
+
+use GMP::Mpq qw(:constants);
+print "the 7th harmonic number is ", 1+1/2+1/3+1/4+1/5+1/6+1/7, "\n";
+use GMP::Mpq qw(:noconstants);
+
+
+use GMP::Mpf qw(mpf);
+my $f = mpf(1,180);
+$f >>= 180;
+$f += 1;
+print "a sample mpf is $f\n";
diff --git a/third_party/gmp/demos/perl/test.pl b/third_party/gmp/demos/perl/test.pl
new file mode 100644
index 0000000..2b54089
--- /dev/null
+++ b/third_party/gmp/demos/perl/test.pl
@@ -0,0 +1,2179 @@
+#!/usr/bin/perl -w
+
+# GMP perl module tests
+
+# Copyright 2001-2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# These tests aim to exercise the many possible combinations of operands
+# etc, and to run all functions at least once, which if nothing else will
+# check everything intended is in the :all list.
+#
+# Use the following in .emacs to match test failure messages.
+#
+# ;; perl "Test" module error messages
+# (eval-after-load "compile"
+#   '(add-to-list
+#     'compilation-error-regexp-alist
+#     '("^.*Failed test [0-9]+ in \\([^ ]+\\) at line \\([0-9]+\\)" 1 2)))
+
+
+use strict;
+use Test;
+
+BEGIN {
+  plan tests => 123,
+  onfail => sub { print "there were failures\n" },
+}
+
+use GMP qw(:all);
+use GMP::Mpz qw(:all);
+use GMP::Mpq qw(:all);
+use GMP::Mpf qw(:all);
+use GMP::Rand qw(:all);
+
+use GMP::Mpz qw(:constants);
+use GMP::Mpz qw(:noconstants);
+use GMP::Mpq qw(:constants);
+use GMP::Mpq qw(:noconstants);
+use GMP::Mpf qw(:constants);
+use GMP::Mpf qw(:noconstants);
+
+package Mytie;
+use Exporter;
+use vars  qw($val $fetched $stored);
+$val = 0;
+$fetched = 0;
+$stored = 0;
+sub TIESCALAR {
+  my ($class, $newval) = @_;
+  my $var = 'mytie dummy refed var';
+  $val = $newval;
+  $fetched = 0;
+  $stored = 0;
+  return bless \$var, $class;
+}
+sub FETCH {
+  my ($self) = @_;
+  $fetched++;
+  return $val;
+}
+sub STORE {
+  my ($self, $newval) = @_;
+  $val = $newval;
+  $stored++;
+}
+package main;
+
+# check Mytie does what it should
+{ tie my $t, 'Mytie', 123;
+  ok ($Mytie::val == 123);
+  $Mytie::val = 456;
+  ok ($t == 456);
+  $t = 789;
+  ok ($Mytie::val == 789);
+}
+
+
+# Usage: str(x)
+# Return x forced to a string, not a PVIV.
+#
+sub str {
+  my $s = "$_[0]" . "";
+  return $s;
+}
+
+my $ivnv_2p128 = 65536.0 * 65536.0 * 65536.0 * 65536.0
+               * 65536.0 * 65536.0 * 65536.0 * 65536.0;
+kill (0, $ivnv_2p128);
+my $str_2p128 = '340282366920938463463374607431768211456';
+
+my $uv_max = ~ 0;
+my $uv_max_str = ~ 0;
+$uv_max_str = "$uv_max_str";
+$uv_max_str = "" . "$uv_max_str";
+
+
+#------------------------------------------------------------------------------
+# GMP::version
+
+use GMP qw(version);
+print '$GMP::VERSION ',$GMP::VERSION,' GMP::version() ',version(),"\n";
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::new
+
+ok (mpz(0) == 0);
+ok (mpz('0') == 0);
+ok (mpz(substr('101',1,1)) == 0);
+ok (mpz(0.0) == 0);
+ok (mpz(mpz(0)) == 0);
+ok (mpz(mpq(0)) == 0);
+ok (mpz(mpf(0)) == 0);
+
+{ tie my $t, 'Mytie', 0;
+  ok (mpz($t) == 0);
+  ok ($Mytie::fetched > 0);
+}
+{ tie my $t, 'Mytie', '0';
+  ok (mpz($t) == 0);
+  ok ($Mytie::fetched > 0);
+}
+{ tie my $t, 'Mytie', substr('101',1,1); ok (mpz($t) == 0); }
+{ tie my $t, 'Mytie', 0.0; ok (mpz($t) == 0); }
+{ tie my $t, 'Mytie', mpz(0); ok (mpz($t) == 0); }
+{ tie my $t, 'Mytie', mpq(0); ok (mpz($t) == 0); }
+{ tie my $t, 'Mytie', mpf(0); ok (mpz($t) == 0); }
+
+ok (mpz(-123) == -123);
+ok (mpz('-123') == -123);
+ok (mpz(substr('1-1231',1,4)) == -123);
+ok (mpz(-123.0) == -123);
+ok (mpz(mpz(-123)) == -123);
+ok (mpz(mpq(-123)) == -123);
+ok (mpz(mpf(-123)) == -123);
+
+{ tie my $t, 'Mytie', -123; ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', '-123'; ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', substr('1-1231',1,4); ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', -123.0; ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', mpz(-123); ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', mpq(-123); ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', mpf(-123); ok (mpz($t) == -123); }
+
+ok (mpz($ivnv_2p128) == $str_2p128);
+{ tie my $t, 'Mytie', $ivnv_2p128; ok (mpz($t) == $str_2p128); }
+
+ok (mpz($uv_max) > 0);
+ok (mpz($uv_max) == mpz($uv_max_str));
+{ tie my $t, 'Mytie', $uv_max; ok (mpz($t) > 0); }
+{ tie my $t, 'Mytie', $uv_max; ok (mpz($t) == mpz($uv_max_str)); }
+
+{ my $s = '999999999999999999999999999999';
+  kill (0, $s);
+  ok (mpz($s) == '999999999999999999999999999999');
+  tie my $t, 'Mytie', $s;
+  ok (mpz($t) == '999999999999999999999999999999');
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_abs
+
+ok (abs(mpz(0)) == 0);
+ok (abs(mpz(123)) == 123);
+ok (abs(mpz(-123)) == 123);
+
+{ my $x = mpz(-123); $x = abs($x); ok ($x == 123); }
+{ my $x = mpz(0);    $x = abs($x); ok ($x == 0);   }
+{ my $x = mpz(123);  $x = abs($x); ok ($x == 123); }
+
+{ tie my $t, 'Mytie', mpz(0); ok (abs($t) == 0); }
+{ tie my $t, 'Mytie', mpz(123); ok (abs($t) == 123); }
+{ tie my $t, 'Mytie', mpz(-123); ok (abs($t) == 123); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_add
+
+ok (mpz(0) + 1 == 1);
+ok (mpz(-1) + 1 == 0);
+ok (1 + mpz(0) == 1);
+ok (1 + mpz(-1) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_addeq
+
+{ my $a = mpz(7); $a += 1; ok ($a == 8); }
+{ my $a = mpz(7); my $b = $a; $a += 1; ok ($a == 8); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_and
+
+ok ((mpz(3) & 1) == 1);
+ok ((mpz(3) & 4) == 0);
+
+{ my $a = mpz(3); $a &= 1; ok ($a == 1); }
+{ my $a = mpz(3); $a &= 4; ok ($a == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_bool
+
+if (mpz(0))   { ok (0); } else { ok (1); }
+if (mpz(123)) { ok (1); } else { ok (0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_com
+
+ok (~ mpz(0) == -1);
+ok (~ mpz(1) == -2);
+ok (~ mpz(-2) == 1);
+ok (~ mpz(0xFF) == -0x100);
+ok (~ mpz(-0x100) == 0xFF);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_dec
+
+{ my $a = mpz(0); ok ($a-- == 0); ok ($a == -1); }
+{ my $a = mpz(0); ok (--$a == -1); }
+
+{ my $a = mpz(0); my $b = $a; $a--; ok ($a == -1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_div
+
+ok (mpz(6) / 2 == 3);
+ok (mpz(-6) / 2 == -3);
+ok (mpz(6) / -2 == -3);
+ok (mpz(-6) / -2 == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_diveq
+
+{ my $a = mpz(21); $a /= 3; ok ($a == 7); }
+{ my $a = mpz(21); my $b = $a; $a /= 3; ok ($a == 7); ok ($b == 21); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_eq
+
+{ my $a = mpz(0);
+  my $b = $a;
+  $a = mpz(1);
+  ok ($a == 1);
+  ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_inc
+
+{ my $a = mpz(0); ok ($a++ == 0); ok ($a == 1); }
+{ my $a = mpz(0); ok (++$a == 1); }
+
+{ my $a = mpz(0); my $b = $a; $a++; ok ($a == 1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_ior
+
+ok ((mpz(3) | 1) == 3);
+ok ((mpz(3) | 4) == 7);
+
+{ my $a = mpz(3); $a |= 1; ok ($a == 3); }
+{ my $a = mpz(3); $a |= 4; ok ($a == 7); }
+
+ok ((mpz("0xAA") | mpz("0x55")) == mpz("0xFF"));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_lshift
+
+{ my $a = mpz(7) << 1; ok ($a == 14); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_lshifteq
+
+{ my $a = mpz(7); $a <<= 1; ok ($a == 14); }
+{ my $a = mpz(7); my $b = $a; $a <<= 1; ok ($a == 14); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_mul
+
+ok (mpz(2) * 3 == 6);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_muleq
+
+{ my $a = mpz(7); $a *= 3;  ok ($a == 21); }
+{ my $a = mpz(7); my $b = $a; $a *= 3;  ok ($a == 21); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_neg
+
+ok (- mpz(0) == 0);
+ok (- mpz(123) == -123);
+ok (- mpz(-123) == 123);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_not
+
+if (not mpz(0))   { ok (1); } else { ok (0); }
+if (not mpz(123)) { ok (0); } else { ok (1); }
+
+ok ((! mpz(0)) == 1);
+ok ((! mpz(123)) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_pow
+
+ok (mpz(0) ** 1 == 0);
+ok (mpz(1) ** 1 == 1);
+ok (mpz(2) ** 0 == 1);
+ok (mpz(2) ** 1 == 2);
+ok (mpz(2) ** 2 == 4);
+ok (mpz(2) ** 3 == 8);
+ok (mpz(2) ** 4 == 16);
+
+ok (mpz(0) ** mpz(1) == 0);
+ok (mpz(1) ** mpz(1) == 1);
+ok (mpz(2) ** mpz(0) == 1);
+ok (mpz(2) ** mpz(1) == 2);
+ok (mpz(2) ** mpz(2) == 4);
+ok (mpz(2) ** mpz(3) == 8);
+ok (mpz(2) ** mpz(4) == 16);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_poweq
+
+{ my $a = mpz(3); $a **= 4; ok ($a == 81); }
+{ my $a = mpz(3); my $b = $a; $a **= 4; ok ($a == 81); ok ($b == 3); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_rem
+
+ok (mpz(-8) % 3 == -2);
+ok (mpz(-7) % 3 == -1);
+ok (mpz(-6) % 3 == 0);
+ok (mpz(6) % 3 == 0);
+ok (mpz(7) % 3 == 1);
+ok (mpz(8) % 3 == 2);
+
+{ my $a = mpz(24); $a %= 7; ok ($a == 3); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_rshift
+
+{ my $a = mpz(32) >> 1; ok ($a == 16); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_rshifteq
+
+{ my $a = mpz(32); $a >>= 1; ok ($a == 16); }
+{ my $a = mpz(32); my $b = $a; $a >>= 1; ok ($a == 16); ok ($b == 32); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_spaceship
+
+ok (mpz(0) < 1);
+ok (mpz(0) > -1);
+
+ok (mpz(0) != 1);
+ok (mpz(0) != -1);
+ok (mpz(1) != 0);
+ok (mpz(1) != -1);
+ok (mpz(-1) != 0);
+ok (mpz(-1) != 1);
+
+ok (mpz(0) < 1.0);
+ok (mpz(0) < '1');
+ok (mpz(0) < substr('-1',1,1));
+ok (mpz(0) < mpz(1));
+ok (mpz(0) < mpq(1));
+ok (mpz(0) < mpf(1));
+ok (mpz(0) < $uv_max);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_sqrt
+
+ok (sqrt(mpz(0)) == 0);
+ok (sqrt(mpz(1)) == 1);
+ok (sqrt(mpz(4)) == 2);
+ok (sqrt(mpz(81)) == 9);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_string
+
+{ my $x = mpz(0);    ok("$x" eq "0"); }
+{ my $x = mpz(123);  ok("$x" eq "123"); }
+{ my $x = mpz(-123); ok("$x" eq "-123"); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_sub
+
+ok (mpz(0) - 1 == -1);
+ok (mpz(1) - 1 == 0);
+ok (1 - mpz(0) == 1);
+ok (1 - mpz(1) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_subeq
+
+{ my $a = mpz(7); $a -= 1; ok ($a == 6); }
+{ my $a = mpz(7); my $b = $a; $a -= 1; ok ($a == 6); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_xor
+
+ok ((mpz(3) ^ 1) == 2);
+ok ((mpz(3) ^ 4) == 7);
+
+{ my $a = mpz(3); $a ^= 1; ok ($a == 2); }
+{ my $a = mpz(3); $a ^= 4; ok ($a == 7); }
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::bin
+
+ok (bin(2,0) == 1);
+ok (bin(2,1) == 2);
+ok (bin(2,2) == 1);
+
+ok (bin(3,0) == 1);
+ok (bin(3,1) == 3);
+ok (bin(3,2) == 3);
+ok (bin(3,3) == 1);
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::cdiv
+
+{ my ($q, $r);
+  ($q, $r) = cdiv (16, 3);
+  ok ($q == 6);
+  ok ($r == -2);
+  ($q, $r) = cdiv (16, -3);
+  ok ($q == -5);
+  ok ($r == 1);
+  ($q, $r) = cdiv (-16, 3);
+  ok ($q == -5);
+  ok ($r == -1);
+  ($q, $r) = cdiv (-16, -3);
+  ok ($q == 6);
+  ok ($r == 2);
+}
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::cdiv_2exp
+
+{ my ($q, $r);
+  ($q, $r) = cdiv_2exp (23, 2);
+  ok ($q == 6);
+  ok ($r == -1);
+  ($q, $r) = cdiv_2exp (-23, 2);
+  ok ($q == -5);
+  ok ($r == -3);
+}
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::clrbit
+
+{ my $a = mpz(3); clrbit ($a, 1); ok ($a == 1);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+{ my $a = mpz(3); clrbit ($a, 2); ok ($a == 3);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+
+{ my $a = 3; clrbit ($a, 1); ok ($a == 1);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+{ my $a = 3; clrbit ($a, 2); ok ($a == 3);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+
+# mutate only given variable
+{ my $a = mpz(3);
+  my $b = $a;
+  clrbit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+}
+{ my $a = 3;
+  my $b = $a;
+  clrbit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+}
+
+{ tie my $a, 'Mytie', mpz(3);
+  clrbit ($a, 1);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 1);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+{ tie my $a, 'Mytie', 3;
+  clrbit ($a, 1);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 1);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+
+{ my $b = mpz(3);
+  tie my $a, 'Mytie', $b;
+  clrbit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+  ok (tied($a));
+}
+{ my $b = 3;
+  tie my $a, 'Mytie', $b;
+  clrbit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+  ok (tied($a));
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::combit
+
+{ my $a = mpz(3); combit ($a, 1); ok ($a == 1);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+{ my $a = mpz(3); combit ($a, 2); ok ($a == 7);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+
+{ my $a = 3; combit ($a, 1); ok ($a == 1);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+{ my $a = 3; combit ($a, 2); ok ($a == 7);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+
+# mutate only given variable
+{ my $a = mpz(3);
+  my $b = $a;
+  combit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+}
+{ my $a = 3;
+  my $b = $a;
+  combit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+}
+
+{ tie my $a, 'Mytie', mpz(3);
+  combit ($a, 2);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 7);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+{ tie my $a, 'Mytie', 3;
+  combit ($a, 2);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 7);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+
+{ my $b = mpz(3);
+  tie my $a, 'Mytie', $b;
+  combit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+  ok (tied($a));
+}
+{ my $b = 3;
+  tie my $a, 'Mytie', $b;
+  combit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+  ok (tied($a));
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::congruent_p
+
+ok (  congruent_p (21, 0, 7));
+ok (! congruent_p (21, 1, 7));
+ok (  congruent_p (21, 5, 8));
+ok (! congruent_p (21, 6, 8));
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::congruent_2exp_p
+
+ok (  congruent_2exp_p (20, 0, 2));
+ok (! congruent_2exp_p (21, 0, 2));
+ok (! congruent_2exp_p (20, 1, 2));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::divexact
+
+ok (divexact(27,3) == 9);
+ok (divexact(27,-3) == -9);
+ok (divexact(-27,3) == -9);
+ok (divexact(-27,-3) == 9);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::divisible_p
+
+ok (  divisible_p (21, 7));
+ok (! divisible_p (21, 8));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::divisible_2exp_p
+
+ok (  divisible_2exp_p (20, 2));
+ok (! divisible_2exp_p (21, 2));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::even_p
+
+ok (! even_p(mpz(-3)));
+ok (  even_p(mpz(-2)));
+ok (! even_p(mpz(-1)));
+ok (  even_p(mpz(0)));
+ok (! even_p(mpz(1)));
+ok (  even_p(mpz(2)));
+ok (! even_p(mpz(3)));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::export
+
+{ my $s = mpz_export (1, 2, 1, 0, "0x61626364");
+  ok ($s eq 'abcd'); }
+{ my $s = mpz_export (-1, 2, 1, 0, "0x61626364");
+  ok ($s eq 'cdab'); }
+{ my $s = mpz_export (1, 2, -1, 0, "0x61626364");
+  ok ($s eq 'badc'); }
+{ my $s = mpz_export (-1, 2, -1, 0, "0x61626364");
+  ok ($s eq 'dcba'); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fac
+
+ok (fac(0) == 1);
+ok (fac(1) == 1);
+ok (fac(2) == 2);
+ok (fac(3) == 6);
+ok (fac(4) == 24);
+ok (fac(5) == 120);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fdiv
+
+{ my ($q, $r);
+  ($q, $r) = fdiv (16, 3);
+  ok ($q == 5);
+  ok ($r == 1);
+  ($q, $r) = fdiv (16, -3);
+  ok ($q == -6);
+  ok ($r == -2);
+  ($q, $r) = fdiv (-16, 3);
+  ok ($q == -6);
+  ok ($r == 2);
+  ($q, $r) = fdiv (-16, -3);
+  ok ($q == 5);
+  ok ($r == -1);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fdiv_2exp
+
+{ my ($q, $r);
+  ($q, $r) = fdiv_2exp (23, 2);
+  ok ($q == 5);
+  ok ($r == 3);
+  ($q, $r) = fdiv_2exp (-23, 2);
+  ok ($q == -6);
+  ok ($r == 1);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fib
+
+ok (fib(0) == 0);
+ok (fib(1) == 1);
+ok (fib(2) == 1);
+ok (fib(3) == 2);
+ok (fib(4) == 3);
+ok (fib(5) == 5);
+ok (fib(6) == 8);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fib2
+
+{ my ($a, $b) = fib2(0); ok($a==0); ok($b==1); }
+{ my ($a, $b) = fib2(1); ok($a==1); ok($b==0); }
+{ my ($a, $b) = fib2(2); ok($a==1); ok($b==1); }
+{ my ($a, $b) = fib2(3); ok($a==2); ok($b==1); }
+{ my ($a, $b) = fib2(4); ok($a==3); ok($b==2); }
+{ my ($a, $b) = fib2(5); ok($a==5); ok($b==3); }
+{ my ($a, $b) = fib2(6); ok($a==8); ok($b==5); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::gcd
+
+ok (gcd (21) == 21);
+ok (gcd (21,15) == 3);
+ok (gcd (21,15,30,57) == 3);
+ok (gcd (21,-15) == 3);
+ok (gcd (-21,15) == 3);
+ok (gcd (-21,-15) == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::gcdext
+
+{
+  my ($g, $x, $y) = gcdext (3,5);
+  ok ($g == 1);
+  ok ($x == 2);
+  ok ($y == -1);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::hamdist
+
+ok (hamdist(5,7) == 1);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::import
+
+{ my $z = mpz_import (1, 2, 1, 0, 'abcd');
+  ok ($z == 0x61626364); }
+{ my $z = mpz_import (-1, 2, 1, 0, 'abcd');
+  ok ($z == 0x63646162); }
+{ my $z = mpz_import (1, 2, -1, 0, 'abcd');
+  ok ($z == 0x62616463); }
+{ my $z = mpz_import (-1, 2, -1, 0, 'abcd');
+  ok ($z == 0x64636261); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::invert
+
+ok (invert(1,123) == 1);
+ok (invert(6,7) == 6);
+ok (! defined invert(2,8));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::jacobi, GMP::Mpz::kronecker
+
+foreach my $i ([  1, 19,  1 ],
+	       [  4, 19,  1 ],
+	       [  5, 19,  1 ],
+	       [  6, 19,  1 ],
+	       [  7, 19,  1 ],
+	       [  9, 19,  1 ],
+	       [ 11, 19,  1 ],
+	       [ 16, 19,  1 ],
+	       [ 17, 19,  1 ],
+	       [  2, 19, -1 ],
+	       [  3, 19, -1 ],
+	       [  8, 19, -1 ],
+	       [ 10, 19, -1 ],
+	       [ 12, 19, -1 ],
+	       [ 13, 19, -1 ],
+	       [ 14, 19, -1 ],
+	       [ 15, 19, -1 ],
+	       [ 18, 19, -1 ]) {
+  foreach my $fun (\&jacobi, \&kronecker) {
+    ok (&$fun ($$i[0], $$i[1]) == $$i[2]);
+
+    ok (&$fun ($$i[0],      str($$i[1])) == $$i[2]);
+    ok (&$fun (str($$i[0]),     $$i[1])  == $$i[2]);
+    ok (&$fun (str($$i[0]), str($$i[1])) == $$i[2]);
+
+    ok (&$fun ($$i[0],      mpz($$i[1])) == $$i[2]);
+    ok (&$fun (mpz($$i[0]), $$i[1]) == $$i[2]);
+    ok (&$fun (mpz($$i[0]), mpz($$i[1])) == $$i[2]);
+  }
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::lcm
+
+ok (lcm (2) == 2);
+ok (lcm (0) == 0);
+ok (lcm (0,0) == 0);
+ok (lcm (0,0,0) == 0);
+ok (lcm (0,0,0,0) == 0);
+ok (lcm (2,0) == 0);
+ok (lcm (-2,0) == 0);
+ok (lcm (2,3) == 6);
+ok (lcm (2,3,4) == 12);
+ok (lcm (2,-3) == 6);
+ok (lcm (-2,3) == 6);
+ok (lcm (-2,-3) == 6);
+ok (lcm (mpz(2)**512,1) == mpz(2)**512);
+ok (lcm (mpz(2)**512,-1) == mpz(2)**512);
+ok (lcm (-mpz(2)**512,1) == mpz(2)**512);
+ok (lcm (-mpz(2)**512,-1) == mpz(2)**512);
+ok (lcm (mpz(2)**512,mpz(2)**512) == mpz(2)**512);
+ok (lcm (mpz(2)**512,-mpz(2)**512) == mpz(2)**512);
+ok (lcm (-mpz(2)**512,mpz(2)**512) == mpz(2)**512);
+ok (lcm (-mpz(2)**512,-mpz(2)**512) == mpz(2)**512);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::lucnum
+
+ok (lucnum(0) == 2);
+ok (lucnum(1) == 1);
+ok (lucnum(2) == 3);
+ok (lucnum(3) == 4);
+ok (lucnum(4) == 7);
+ok (lucnum(5) == 11);
+ok (lucnum(6) == 18);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::lucnum2
+
+{ my ($a, $b) = lucnum2(0); ok($a==2);  ok($b==-1); }
+{ my ($a, $b) = lucnum2(1); ok($a==1);  ok($b==2); }
+{ my ($a, $b) = lucnum2(2); ok($a==3);  ok($b==1); }
+{ my ($a, $b) = lucnum2(3); ok($a==4);  ok($b==3); }
+{ my ($a, $b) = lucnum2(4); ok($a==7);  ok($b==4); }
+{ my ($a, $b) = lucnum2(5); ok($a==11); ok($b==7); }
+{ my ($a, $b) = lucnum2(6); ok($a==18); ok($b==11); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::nextprime
+
+ok (nextprime(2) == 3);
+ok (nextprime(3) == 5);
+ok (nextprime(5) == 7);
+ok (nextprime(7) == 11);
+ok (nextprime(11) == 13);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::perfect_power_p
+
+# ok (  perfect_power_p(mpz(-27)));
+# ok (! perfect_power_p(mpz(-9)));
+# ok (! perfect_power_p(mpz(-1)));
+ok (  perfect_power_p(mpz(0)));
+ok (  perfect_power_p(mpz(1)));
+ok (! perfect_power_p(mpz(2)));
+ok (! perfect_power_p(mpz(3)));
+ok (  perfect_power_p(mpz(4)));
+ok (  perfect_power_p(mpz(9)));
+ok (  perfect_power_p(mpz(27)));
+ok (  perfect_power_p(mpz(81)));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::perfect_square_p
+
+ok (! perfect_square_p(mpz(-9)));
+ok (! perfect_square_p(mpz(-1)));
+ok (  perfect_square_p(mpz(0)));
+ok (  perfect_square_p(mpz(1)));
+ok (! perfect_square_p(mpz(2)));
+ok (! perfect_square_p(mpz(3)));
+ok (  perfect_square_p(mpz(4)));
+ok (  perfect_square_p(mpz(9)));
+ok (! perfect_square_p(mpz(27)));
+ok (  perfect_square_p(mpz(81)));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::popcount
+
+ok (popcount(7) == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::powm
+
+ok (powm (3,2,8) == 1);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::probab_prime_p
+
+ok (  probab_prime_p(89,1));
+ok (! probab_prime_p(81,1));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::realloc
+
+{ my $z = mpz(123);
+  realloc ($z, 512); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::remove
+
+{
+  my ($rem, $mult);
+  ($rem, $mult) = remove(12,3);
+  ok ($rem == 4);
+  ok ($mult == 1);
+  ($rem, $mult) = remove(12,2);
+  ok ($rem == 3);
+  ok ($mult == 2);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::root
+
+ok (root(0,2) == 0);
+ok (root(8,3) == 2);
+ok (root(-8,3) == -2);
+ok (root(81,4) == 3);
+ok (root(243,5) == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::roote
+
+{ my ($r,$e);
+  ($r, $e) = roote(0,2);
+  ok ($r == 0);
+  ok ($e);
+  ($r, $e) = roote(81,4);
+  ok ($r == 3);
+  ok ($e);
+  ($r, $e) = roote(85,4);
+  ok ($r == 3);
+  ok (! $e);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::rootrem
+
+{ my ($root, $rem) = rootrem (mpz(0), 1);
+  ok ($root == 0); ok ($rem == 0); }
+{ my ($root, $rem) = rootrem (mpz(0), 2);
+  ok ($root == 0); ok ($rem == 0); }
+{ my ($root, $rem) = rootrem (mpz(64), 2);
+  ok ($root == 8); ok ($rem == 0); }
+{ my ($root, $rem) = rootrem (mpz(64), 3);
+  ok ($root == 4); ok ($rem == 0); }
+{ my ($root, $rem) = rootrem (mpz(65), 3);
+  ok ($root == 4); ok ($rem == 1); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::scan0
+
+ok (scan0 (0, 0) == 0);
+ok (scan0 (1, 0) == 1);
+ok (scan0 (3, 0) == 2);
+ok (scan0 (-1, 0) == ~0);
+ok (scan0 (-2, 1) == ~0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::scan1
+
+ok (scan1 (1, 0) == 0);
+ok (scan1 (2, 0) == 1);
+ok (scan1 (4, 0) == 2);
+ok (scan1 (0, 0) == ~0);
+ok (scan1 (3, 2) == ~0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::setbit
+
+{ my $a = mpz(3); setbit ($a, 1); ok ($a == 3); }
+{ my $a = mpz(3); setbit ($a, 2); ok ($a == 7); }
+
+{ my $a = 3; setbit ($a, 1); ok ($a == 3); }
+{ my $a = 3; setbit ($a, 2); ok ($a == 7); }
+
+# mutate only given variable
+{ my $a = mpz(0);
+  my $b = $a;
+  setbit ($a, 0);
+  ok ($a == 1);
+  ok ($b == 0);
+}
+{ my $a = 0;
+  my $b = $a;
+  setbit ($a, 0);
+  ok ($a == 1);
+  ok ($b == 0);
+}
+
+{ tie my $a, 'Mytie', mpz(3);
+  setbit ($a, 2);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 7);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+{ tie my $a, 'Mytie', 3;
+  setbit ($a, 2);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 7);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+
+{ my $b = mpz(2);
+  tie my $a, 'Mytie', $b;
+  setbit ($a, 0);
+  ok ($a == 3);
+  ok ($b == 2);
+  ok (tied($a));
+}
+{ my $b = 2;
+  tie my $a, 'Mytie', $b;
+  setbit ($a, 0);
+  ok ($a == 3);
+  ok ($b == 2);
+  ok (tied($a));
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::sizeinbase
+
+ok (sizeinbase(1,10) == 1);
+ok (sizeinbase(100,10) == 3);
+ok (sizeinbase(9999,10) == 5);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::sqrtrem
+
+{
+  my ($root, $rem) = sqrtrem(mpz(0));
+  ok ($root == 0);
+  ok ($rem == 0);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(1));
+  ok ($root == 1);
+  ok ($rem == 0);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(2));
+  ok ($root == 1);
+  ok ($rem == 1);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(9));
+  ok ($root == 3);
+  ok ($rem == 0);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(35));
+  ok ($root == 5);
+  ok ($rem == 10);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(0));
+  ok ($root == 0);
+  ok ($rem == 0);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::tdiv
+
+{ my ($q, $r);
+  ($q, $r) = tdiv (16, 3);
+  ok ($q == 5);
+  ok ($r == 1);
+  ($q, $r) = tdiv (16, -3);
+  ok ($q == -5);
+  ok ($r == 1);
+  ($q, $r) = tdiv (-16, 3);
+  ok ($q == -5);
+  ok ($r == -1);
+  ($q, $r) = tdiv (-16, -3);
+  ok ($q == 5);
+  ok ($r == -1);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::tdiv_2exp
+
+{ my ($q, $r);
+  ($q, $r) = tdiv_2exp (23, 2);
+  ok ($q == 5);
+  ok ($r == 3);
+  ($q, $r) = tdiv_2exp (-23, 2);
+  ok ($q == -5);
+  ok ($r == -3);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::tstbit
+
+ok (tstbit (6, 0) == 0);
+ok (tstbit (6, 1) == 1);
+ok (tstbit (6, 2) == 1);
+ok (tstbit (6, 3) == 0);
+
+
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpq
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::new
+
+ok (mpq(0) == 0);
+ok (mpq('0') == 0);
+ok (mpq(substr('101',1,1)) == 0);
+ok (mpq(0.0) == 0);
+ok (mpq(mpz(0)) == 0);
+ok (mpq(mpq(0)) == 0);
+ok (mpq(mpf(0)) == 0);
+
+{ tie my $t, 'Mytie', 0; ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', '0'; ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', substr('101',1,1); ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', 0.0; ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', mpz(0); ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', mpq(0); ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', mpf(0); ok (mpq($t) == 0); }
+
+ok (mpq(-123) == -123);
+ok (mpq('-123') == -123);
+ok (mpq(substr('1-1231',1,4)) == -123);
+ok (mpq(-123.0) == -123);
+ok (mpq(mpz(-123)) == -123);
+ok (mpq(mpq(-123)) == -123);
+ok (mpq(mpf(-123)) == -123);
+
+{ tie my $t, 'Mytie', -123; ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', '-123'; ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', substr('1-1231',1,4); ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', -123.0; ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', mpz(-123); ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', mpq(-123); ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', mpf(-123); ok (mpq($t) == -123); }
+
+ok (mpq($ivnv_2p128) == $str_2p128);
+{ tie my $t, 'Mytie', $ivnv_2p128; ok (mpq($t) == $str_2p128); }
+
+ok (mpq('3/2') == mpq(3,2));
+ok (mpq('3/1') == mpq(3,1));
+ok (mpq('-3/2') == mpq(-3,2));
+ok (mpq('-3/1') == mpq(-3,1));
+ok (mpq('0x3') == mpq(3,1));
+ok (mpq('0b111') == mpq(7,1));
+ok (mpq('0b0') == mpq(0,1));
+
+ok (mpq($uv_max) > 0);
+ok (mpq($uv_max) == mpq($uv_max_str));
+{ tie my $t, 'Mytie', $uv_max; ok (mpq($t) > 0); }
+{ tie my $t, 'Mytie', $uv_max; ok (mpq($t) == mpq($uv_max_str)); }
+
+{ my $x = 123.5;
+  kill (0, $x);
+  ok (mpq($x) == 123.5);
+  tie my $t, 'Mytie', $x;
+  ok (mpq($t) == 123.5);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_abs
+
+ok (abs(mpq(0)) == 0);
+ok (abs(mpq(123)) == 123);
+ok (abs(mpq(-123)) == 123);
+
+{ my $x = mpq(-123); $x = abs($x); ok ($x == 123); }
+{ my $x = mpq(0);    $x = abs($x); ok ($x == 0);   }
+{ my $x = mpq(123);  $x = abs($x); ok ($x == 123); }
+
+{ tie my $t, 'Mytie', mpq(0); ok (abs($t) == 0); }
+{ tie my $t, 'Mytie', mpq(123); ok (abs($t) == 123); }
+{ tie my $t, 'Mytie', mpq(-123); ok (abs($t) == 123); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_add
+
+ok (mpq(0) + 1 == 1);
+ok (mpq(-1) + 1 == 0);
+ok (1 + mpq(0) == 1);
+ok (1 + mpq(-1) == 0);
+
+ok (mpq(1,2)+mpq(1,3) == mpq(5,6));
+ok (mpq(1,2)+mpq(-1,3) == mpq(1,6));
+ok (mpq(-1,2)+mpq(1,3) == mpq(-1,6));
+ok (mpq(-1,2)+mpq(-1,3) == mpq(-5,6));
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_addeq
+
+{ my $a = mpq(7); $a += 1; ok ($a == 8); }
+{ my $a = mpq(7); my $b = $a; $a += 1; ok ($a == 8); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_bool
+
+if (mpq(0))   { ok (0); } else { ok (1); }
+if (mpq(123)) { ok (1); } else { ok (0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_dec
+
+{ my $a = mpq(0); ok ($a-- == 0); ok ($a == -1); }
+{ my $a = mpq(0); ok (--$a == -1); }
+
+{ my $a = mpq(0); my $b = $a; $a--; ok ($a == -1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_div
+
+ok (mpq(6) / 2 == 3);
+ok (mpq(-6) / 2 == -3);
+ok (mpq(6) / -2 == -3);
+ok (mpq(-6) / -2 == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_diveq
+
+{ my $a = mpq(21); $a /= 3; ok ($a == 7); }
+{ my $a = mpq(21); my $b = $a; $a /= 3; ok ($a == 7); ok ($b == 21); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_eq
+
+{ my $a = mpq(0);
+  my $b = $a;
+  $a = mpq(1);
+  ok ($a == 1);
+  ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_inc
+
+{ my $a = mpq(0); ok ($a++ == 0); ok ($a == 1); }
+{ my $a = mpq(0); ok (++$a == 1); }
+
+{ my $a = mpq(0); my $b = $a; $a++; ok ($a == 1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_lshift
+
+{ my $a = mpq(7) << 1; ok ($a == 14); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_lshifteq
+
+{ my $a = mpq(7); $a <<= 1; ok ($a == 14); }
+{ my $a = mpq(7); my $b = $a; $a <<= 1; ok ($a == 14); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_mul
+
+ok (mpq(2) * 3 == 6);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_muleq
+
+{ my $a = mpq(7); $a *= 3;  ok ($a == 21); }
+{ my $a = mpq(7); my $b = $a; $a *= 3;  ok ($a == 21); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_neg
+
+ok (- mpq(0) == 0);
+ok (- mpq(123) == -123);
+ok (- mpq(-123) == 123);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_not
+
+if (not mpq(0))   { ok (1); } else { ok (0); }
+if (not mpq(123)) { ok (0); } else { ok (1); }
+
+ok ((! mpq(0)) == 1);
+ok ((! mpq(123)) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_pow
+
+ok (mpq(0) ** 1 == 0);
+ok (mpq(1) ** 1 == 1);
+ok (mpq(2) ** 0 == 1);
+ok (mpq(2) ** 1 == 2);
+ok (mpq(2) ** 2 == 4);
+ok (mpq(2) ** 3 == 8);
+ok (mpq(2) ** 4 == 16);
+
+ok (mpq(0) ** mpq(1) == 0);
+ok (mpq(1) ** mpq(1) == 1);
+ok (mpq(2) ** mpq(0) == 1);
+ok (mpq(2) ** mpq(1) == 2);
+ok (mpq(2) ** mpq(2) == 4);
+ok (mpq(2) ** mpq(3) == 8);
+ok (mpq(2) ** mpq(4) == 16);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_poweq
+
+{ my $a = mpq(3); $a **= 4; ok ($a == 81); }
+{ my $a = mpq(3); my $b = $a; $a **= 4; ok ($a == 81); ok ($b == 3); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_rshift
+
+{ my $a = mpq(32) >> 1; ok ($a == 16); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_rshifteq
+
+{ my $a = mpq(32); $a >>= 1; ok ($a == 16); }
+{ my $a = mpq(32); my $b = $a; $a >>= 1; ok ($a == 16); ok ($b == 32); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_spaceship
+
+ok (mpq(0) < 1);
+ok (mpq(0) > -1);
+
+ok (mpq(0) != 1);
+ok (mpq(0) != -1);
+ok (mpq(1) != 0);
+ok (mpq(1) != -1);
+ok (mpq(-1) != 0);
+ok (mpq(-1) != 1);
+
+ok (mpq(3,2) > 1);
+ok (mpq(3,2) < 2);
+
+ok (mpq(0) < 1.0);
+ok (mpq(0) < '1');
+ok (mpq(0) < substr('-1',1,1));
+ok (mpq(0) < mpz(1));
+ok (mpq(0) < mpq(1));
+ok (mpq(0) < mpf(1));
+ok (mpq(0) < $uv_max);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_string
+
+{ my $x = mpq(0);    ok("$x" eq "0"); }
+{ my $x = mpq(123);  ok("$x" eq "123"); }
+{ my $x = mpq(-123); ok("$x" eq "-123"); }
+
+{ my $q = mpq(5,7);  ok("$q" eq "5/7"); }
+{ my $q = mpq(-5,7); ok("$q" eq "-5/7"); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_sub
+
+ok (mpq(0) - 1 == -1);
+ok (mpq(1) - 1 == 0);
+ok (1 - mpq(0) == 1);
+ok (1 - mpq(1) == 0);
+
+ok (mpq(1,2)-mpq(1,3) == mpq(1,6));
+ok (mpq(1,2)-mpq(-1,3) == mpq(5,6));
+ok (mpq(-1,2)-mpq(1,3) == mpq(-5,6));
+ok (mpq(-1,2)-mpq(-1,3) == mpq(-1,6));
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_subeq
+
+{ my $a = mpq(7); $a -= 1; ok ($a == 6); }
+{ my $a = mpq(7); my $b = $a; $a -= 1; ok ($a == 6); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::canonicalize
+
+{ my $q = mpq(21,15); canonicalize($q);
+  ok (num($q) == 7);
+  ok (den($q) == 5);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::den
+
+{ my $q = mpq(5,9); ok (den($q) == 9); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::num
+
+{ my $q = mpq(5,9); ok (num($q) == 5); }
+
+
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpf
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::new
+
+ok (mpf(0) == 0);
+ok (mpf('0') == 0);
+ok (mpf(substr('101',1,1)) == 0);
+ok (mpf(0.0) == 0);
+ok (mpf(mpz(0)) == 0);
+ok (mpf(mpq(0)) == 0);
+ok (mpf(mpf(0)) == 0);
+
+{ tie my $t, 'Mytie', 0; ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', '0'; ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', substr('101',1,1); ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', 0.0; ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', mpz(0); ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', mpq(0); ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', mpf(0); ok (mpf($t) == 0); }
+
+ok (mpf(-123) == -123);
+ok (mpf('-123') == -123);
+ok (mpf(substr('1-1231',1,4)) == -123);
+ok (mpf(-123.0) == -123);
+ok (mpf(mpz(-123)) == -123);
+ok (mpf(mpq(-123)) == -123);
+ok (mpf(mpf(-123)) == -123);
+
+{ tie my $t, 'Mytie', -123; ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', '-123'; ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', substr('1-1231',1,4); ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', -123.0; ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', mpz(-123); ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', mpq(-123); ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', mpf(-123); ok (mpf($t) == -123); }
+
+ok (mpf($ivnv_2p128) == $str_2p128);
+{ tie my $t, 'Mytie', $ivnv_2p128; ok (mpf($t) == $str_2p128); }
+
+ok (mpf(-1.5) == -1.5);
+ok (mpf(-1.0) == -1.0);
+ok (mpf(-0.5) == -0.5);
+ok (mpf(0) == 0);
+ok (mpf(0.5) == 0.5);
+ok (mpf(1.0) == 1.0);
+ok (mpf(1.5) == 1.5);
+
+ok (mpf("-1.5") == -1.5);
+ok (mpf("-1.0") == -1.0);
+ok (mpf("-0.5") == -0.5);
+ok (mpf("0") == 0);
+ok (mpf("0.5") == 0.5);
+ok (mpf("1.0") == 1.0);
+ok (mpf("1.5") == 1.5);
+
+ok (mpf($uv_max) > 0);
+ok (mpf($uv_max) == mpf($uv_max_str));
+{ tie my $t, 'Mytie', $uv_max; ok (mpf($t) > 0); }
+{ tie my $t, 'Mytie', $uv_max; ok (mpf($t) == mpf($uv_max_str)); }
+
+{ my $x = 123.5;
+  kill (0, $x);
+  ok (mpf($x) == 123.5);
+  tie my $t, 'Mytie', $x;
+  ok (mpf($t) == 123.5);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_abs
+
+ok (abs(mpf(0)) == 0);
+ok (abs(mpf(123)) == 123);
+ok (abs(mpf(-123)) == 123);
+
+{ my $x = mpf(-123); $x = abs($x); ok ($x == 123); }
+{ my $x = mpf(0);    $x = abs($x); ok ($x == 0);   }
+{ my $x = mpf(123);  $x = abs($x); ok ($x == 123); }
+
+{ tie my $t, 'Mytie', mpf(0); ok (abs($t) == 0); }
+{ tie my $t, 'Mytie', mpf(123); ok (abs($t) == 123); }
+{ tie my $t, 'Mytie', mpf(-123); ok (abs($t) == 123); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_add
+
+ok (mpf(0) + 1 == 1);
+ok (mpf(-1) + 1 == 0);
+ok (1 + mpf(0) == 1);
+ok (1 + mpf(-1) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_addeq
+
+{ my $a = mpf(7); $a += 1; ok ($a == 8); }
+{ my $a = mpf(7); my $b = $a; $a += 1; ok ($a == 8); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_bool
+
+if (mpf(0))   { ok (0); } else { ok (1); }
+if (mpf(123)) { ok (1); } else { ok (0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_dec
+
+{ my $a = mpf(0); ok ($a-- == 0); ok ($a == -1); }
+{ my $a = mpf(0); ok (--$a == -1); }
+
+{ my $a = mpf(0); my $b = $a; $a--; ok ($a == -1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_div
+
+ok (mpf(6) / 2 == 3);
+ok (mpf(-6) / 2 == -3);
+ok (mpf(6) / -2 == -3);
+ok (mpf(-6) / -2 == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_diveq
+
+{ my $a = mpf(21); $a /= 3; ok ($a == 7); }
+{ my $a = mpf(21); my $b = $a; $a /= 3; ok ($a == 7); ok ($b == 21); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_eq
+
+{ my $a = mpf(0);
+  my $b = $a;
+  $a = mpf(1);
+  ok ($a == 1);
+  ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_inc
+
+{ my $a = mpf(0); ok ($a++ == 0); ok ($a == 1); }
+{ my $a = mpf(0); ok (++$a == 1); }
+
+{ my $a = mpf(0); my $b = $a; $a++; ok ($a == 1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_lshift
+
+{ my $a = mpf(7) << 1; ok ($a == 14); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_lshifteq
+
+{ my $a = mpf(7); $a <<= 1; ok ($a == 14); }
+{ my $a = mpf(7); my $b = $a; $a <<= 1; ok ($a == 14); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_mul
+
+ok (mpf(2) * 3 == 6);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_muleq
+
+{ my $a = mpf(7); $a *= 3;  ok ($a == 21); }
+{ my $a = mpf(7); my $b = $a; $a *= 3;  ok ($a == 21); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_neg
+
+ok (- mpf(0) == 0);
+ok (- mpf(123) == -123);
+ok (- mpf(-123) == 123);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_not
+
+if (not mpf(0))   { ok (1); } else { ok (0); }
+if (not mpf(123)) { ok (0); } else { ok (1); }
+
+ok ((! mpf(0)) == 1);
+ok ((! mpf(123)) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_pow
+
+ok (mpf(0) ** 1 == 0);
+ok (mpf(1) ** 1 == 1);
+ok (mpf(2) ** 0 == 1);
+ok (mpf(2) ** 1 == 2);
+ok (mpf(2) ** 2 == 4);
+ok (mpf(2) ** 3 == 8);
+ok (mpf(2) ** 4 == 16);
+
+ok (mpf(0) ** mpf(1) == 0);
+ok (mpf(1) ** mpf(1) == 1);
+ok (mpf(2) ** mpf(0) == 1);
+ok (mpf(2) ** mpf(1) == 2);
+ok (mpf(2) ** mpf(2) == 4);
+ok (mpf(2) ** mpf(3) == 8);
+ok (mpf(2) ** mpf(4) == 16);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_poweq
+
+{ my $a = mpf(3); $a **= 4; ok ($a == 81); }
+{ my $a = mpf(3); my $b = $a; $a **= 4; ok ($a == 81); ok ($b == 3); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_rshift
+
+{ my $a = mpf(32) >> 1; ok ($a == 16); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_rshifteq
+
+{ my $a = mpf(32); $a >>= 1; ok ($a == 16); }
+{ my $a = mpf(32); my $b = $a; $a >>= 1; ok ($a == 16); ok ($b == 32); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_sqrt
+
+ok (sqrt(mpf(0)) == 0);
+ok (sqrt(mpf(1)) == 1);
+ok (sqrt(mpf(4)) == 2);
+ok (sqrt(mpf(81)) == 9);
+
+ok (sqrt(mpf(0.25)) == 0.5);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_spaceship
+
+ok (mpf(0) < 1);
+ok (mpf(0) > -1);
+
+ok (mpf(0) != 1);
+ok (mpf(0) != -1);
+ok (mpf(1) != 0);
+ok (mpf(1) != -1);
+ok (mpf(-1) != 0);
+ok (mpf(-1) != 1);
+
+ok (mpf(0) < 1.0);
+ok (mpf(0) < '1');
+ok (mpf(0) < substr('-1',1,1));
+ok (mpf(0) < mpz(1));
+ok (mpf(0) < mpq(1));
+ok (mpf(0) < mpf(1));
+ok (mpf(0) < $uv_max);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_string
+
+{ my $x = mpf(0);    ok ("$x" eq "0"); }
+{ my $x = mpf(123);  ok ("$x" eq "123"); }
+{ my $x = mpf(-123); ok ("$x" eq "-123"); }
+
+{ my $f = mpf(0.25);   	 ok ("$f" eq "0.25"); }
+{ my $f = mpf(-0.25);  	 ok ("$f" eq "-0.25"); }
+{ my $f = mpf(1.25);   	 ok ("$f" eq "1.25"); }
+{ my $f = mpf(-1.25);  	 ok ("$f" eq "-1.25"); }
+{ my $f = mpf(1000000);	 ok ("$f" eq "1000000"); }
+{ my $f = mpf(-1000000); ok ("$f" eq "-1000000"); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_sub
+
+ok (mpf(0) - 1 == -1);
+ok (mpf(1) - 1 == 0);
+ok (1 - mpf(0) == 1);
+ok (1 - mpf(1) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_subeq
+
+{ my $a = mpf(7); $a -= 1; ok ($a == 6); }
+{ my $a = mpf(7); my $b = $a; $a -= 1; ok ($a == 6); ok ($b == 7); }
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::ceil
+
+ok (ceil (mpf(-7.5)) == -7.0);
+ok (ceil (mpf(7.5)) == 8.0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::floor
+
+ok (floor(mpf(-7.5)) == -8.0);
+ok (floor(mpf(7.5)) == 7.0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::mpf_eq
+
+{ my $old_prec = get_default_prec();
+  set_default_prec(128);
+
+  ok (  mpf_eq (mpz("0x10000000000000001"), mpz("0x10000000000000002"), 1));
+  ok (! mpf_eq (mpz("0x11"), mpz("0x12"), 128));
+
+  set_default_prec($old_prec);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::get_default_prec
+
+get_default_prec();
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::get_prec
+
+{ my $x = mpf(1.0, 512);
+  ok (get_prec ($x) == 512);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::reldiff
+
+ok (reldiff (2,4) == 1);
+ok (reldiff (4,2) == 0.5);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::set_default_prec
+
+{ my $old_prec = get_default_prec();
+
+  set_default_prec(512);
+  ok (get_default_prec () == 512);
+
+  set_default_prec($old_prec);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::set_prec
+
+{ my $x = mpf(1.0, 512);
+  my $y = $x;
+  set_prec ($x, 1024);
+  ok (get_prec ($x) == 1024);
+  ok (get_prec ($y) == 512);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::trunc
+
+ok (trunc(mpf(-7.5)) == -7.0);
+ok (trunc(mpf(7.5)) == 7.0);
+
+
+
+#------------------------------------------------------------------------------
+# GMP::Rand
+
+#------------------------------------------------------------------------------
+# GMP::Rand::new
+
+{ my $r = randstate();                          ok (defined $r); }
+{ my $r = randstate('lc_2exp', 1, 2, 3);        ok (defined $r); }
+{ my $r = randstate('lc_2exp_size', 64);        ok (defined $r); }
+{ my $r = randstate('lc_2exp_size', 999999999); ok (! defined $r); }
+{ my $r = randstate('mt');                      ok (defined $r); }
+
+{ # copying a randstate results in same sequence
+  my $r1 = randstate('lc_2exp_size', 64);
+  $r1->seed(123);
+  my $r2 = randstate($r1);
+  for (1 .. 20) {
+    my $z1 = mpz_urandomb($r1, 20);
+    my $z2 = mpz_urandomb($r2, 20);
+    ok ($z1 == $z2);
+  }
+}
+
+#------------------------------------------------------------------------------
+# GMP::Rand::seed
+
+{ my $r = randstate();
+  $r->seed(123);
+  $r->seed(time());
+}
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpf_urandomb
+
+{ my $r = randstate();
+  my $f = mpf_urandomb($r,1024);
+  ok (UNIVERSAL::isa($f,"GMP::Mpf")); }
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_urandomb
+
+{ my $r = randstate();
+  my $z = mpz_urandomb($r, 1024);
+  ok (UNIVERSAL::isa($z,"GMP::Mpz")); }
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_rrandomb
+
+{ my $r = randstate();
+  my $z = mpz_rrandomb($r, 1024);
+  ok (UNIVERSAL::isa($z,"GMP::Mpz")); }
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_urandomm
+
+{ my $r = randstate();
+  my $z = mpz_urandomm($r, mpz(3)**100);
+  ok (UNIVERSAL::isa($z,"GMP::Mpz")); }
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_urandomb_ui
+
+{ my $r = randstate();
+  foreach (1 .. 20) {
+    my $u = gmp_urandomb_ui($r,8);
+    ok ($u >= 0);
+    ok ($u < 256);
+  }
+}
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_urandomm_ui
+
+{ my $r = randstate();
+  foreach (1 .. 20) {
+    my $u = gmp_urandomm_ui($r,8);
+    ok ($u >= 0);
+    ok ($u < 8);
+  }
+}
+
+
+
+
+#------------------------------------------------------------------------------
+# GMP module
+
+#------------------------------------------------------------------------------
+# GMP::fits_slong_p
+
+ok (GMP::fits_slong_p(0));
+
+# in perl 5.005 uv_max is only 32-bits on a 64-bit system, so won't exceed a
+# long
+# ok (! GMP::fits_slong_p($uv_max));
+
+ok (GMP::fits_slong_p(0.0));
+
+ok (GMP::fits_slong_p('0'));
+
+ok (GMP::fits_slong_p(substr('999999999999999999999999999999',1,1)));
+
+ok (! mpz("-9999999999999999999999999999999999999999999")->fits_slong_p());
+ok (  mpz(-123)->fits_slong_p());
+ok (  mpz(0)->fits_slong_p());
+ok (  mpz(123)->fits_slong_p());
+ok (! mpz("9999999999999999999999999999999999999999999")->fits_slong_p());
+
+ok (! mpq("-9999999999999999999999999999999999999999999")->fits_slong_p());
+ok (  mpq(-123)->fits_slong_p());
+ok (  mpq(0)->fits_slong_p());
+ok (  mpq(123)->fits_slong_p());
+ok (! mpq("9999999999999999999999999999999999999999999")->fits_slong_p());
+
+ok (! mpf("-9999999999999999999999999999999999999999999")->fits_slong_p());
+ok (  mpf(-123)->fits_slong_p());
+ok (  mpf(0)->fits_slong_p());
+ok (  mpf(123)->fits_slong_p());
+ok (! mpf("9999999999999999999999999999999999999999999")->fits_slong_p());
+
+#------------------------------------------------------------------------------
+# GMP::get_d
+
+ok (GMP::get_d(123) == 123.0);
+
+ok (GMP::get_d($uv_max) > 0);
+
+ok (GMP::get_d(123.0) == 123.0);
+
+ok (GMP::get_d('123') == 123.0);
+
+ok (GMP::get_d(mpz(123)) == 123.0);
+
+ok (GMP::get_d(mpq(123)) == 123.0);
+
+ok (GMP::get_d(mpf(123)) == 123.0);
+
+#------------------------------------------------------------------------------
+# GMP::get_d_2exp
+
+{ my ($dbl, $exp) = get_d_2exp (0);
+  ok ($dbl == 0); ok ($exp == 0); }
+{ my ($dbl, $exp) = get_d_2exp (1);
+  ok ($dbl == 0.5); ok ($exp == 1); }
+
+{ my ($dbl, $exp) = get_d_2exp ($uv_max);
+  ok ($dbl > 0.0); ok ($exp > 0); }
+
+{ my ($dbl, $exp) = get_d_2exp (0.5);
+  ok ($dbl == 0.5); ok ($exp == 0); }
+{ my ($dbl, $exp) = get_d_2exp (0.25);
+  ok ($dbl == 0.5); ok ($exp == -1); }
+
+{ my ($dbl, $exp) = get_d_2exp ("1.0");
+  ok ($dbl == 0.5); ok ($exp == 1); }
+
+{ my ($dbl, $exp) = get_d_2exp (mpz ("256"));
+  ok ($dbl == 0.5); ok ($exp == 9); }
+
+{ my ($dbl, $exp) = get_d_2exp (mpq ("1/16"));
+  ok ($dbl == 0.5); ok ($exp == -3); }
+
+{ my ($dbl, $exp) = get_d_2exp (mpf ("1.5"));
+  ok ($dbl == 0.75); ok ($exp == 1); }
+{ my ($dbl, $exp) = get_d_2exp (mpf ("3.0"));
+  ok ($dbl == 0.75); ok ($exp == 2); }
+
+#------------------------------------------------------------------------------
+# GMP::get_str
+
+ok (get_str(-123) eq '-123');
+ok (get_str('-123') eq '-123');
+ok (get_str(substr('x-123x',1,4)) eq '-123');
+ok (get_str(mpz(-123)) eq '-123');
+ok (get_str(mpq(-123)) eq '-123');
+
+ok (get_str(-123,10) eq '-123');
+ok (get_str('-123',10) eq '-123');
+ok (get_str(substr('x-123x',1,4),10) eq '-123');
+ok (get_str(mpz(-123),10) eq '-123');
+ok (get_str(mpq(-123),10) eq '-123');
+
+ok (get_str(-123,16) eq '-7b');
+ok (get_str('-123',16) eq '-7b');
+ok (get_str(substr('x-123x',1,4),16) eq '-7b');
+ok (get_str(mpz(-123),16) eq '-7b');
+ok (get_str(mpq(-123),16) eq '-7b');
+
+ok (get_str(-123,-16) eq '-7B');
+ok (get_str('-123',-16) eq '-7B');
+ok (get_str(substr('x-123x',1,4),-16) eq '-7B');
+ok (get_str(mpz(-123),-16) eq '-7B');
+ok (get_str(mpq(-123),-16) eq '-7B');
+
+# is a float in past versions of perl without UV type
+{ my ($str, $exp) = get_str($uv_max);
+  ok ($str eq $uv_max_str); }
+
+ok (get_str(mpq(5/8)) eq "5/8");
+ok (get_str(mpq(-5/8)) eq "-5/8");
+ok (get_str(mpq(255/256),16) eq "ff/100");
+ok (get_str(mpq(255/256),-16) eq "FF/100");
+ok (get_str(mpq(-255/256),16) eq "-ff/100");
+ok (get_str(mpq(-255/256),-16) eq "-FF/100");
+
+{ my ($s,$e) = get_str(1.5, 10);      ok ($s eq '15'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(1.5), 10); ok ($s eq '15'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(-1.5, 10);      ok ($s eq '-15'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(-1.5), 10); ok ($s eq '-15'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(1.5, 16);      ok ($s eq '18'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(1.5), 16); ok ($s eq '18'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(-1.5, 16);      ok ($s eq '-18'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(-1.5), 16); ok ($s eq '-18'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(65536.0, 16);      ok ($s eq '1'); ok ($e == 5); }
+{ my ($s,$e) = get_str(mpf(65536.0), 16); ok ($s eq '1'); ok ($e == 5); }
+
+{ my ($s,$e) = get_str(1.625, 16);      ok ($s eq '1a'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(1.625), 16); ok ($s eq '1a'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(1.625, -16);      ok ($s eq '1A'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(1.625), -16); ok ($s eq '1A'); ok ($e == 1); }
+
+{ my ($s, $e) = get_str(255.0,16,0);      ok ($s eq "ff"); ok ($e == 2); }
+{ my ($s, $e) = get_str(mpf(255.0),16,0); ok ($s eq "ff"); ok ($e == 2); }
+
+{ my ($s, $e) = get_str(255.0,-16,0);      ok ($s eq "FF"); ok ($e == 2); }
+{ my ($s, $e) = get_str(mpf(255.0),-16,0); ok ($s eq "FF"); ok ($e == 2); }
+
+#------------------------------------------------------------------------------
+# GMP::get_si
+
+ok (GMP::get_si(123) == 123.0);
+
+# better not assume anything about the relatives sizes of long and UV
+ok (GMP::get_si($uv_max) != 0);
+
+ok (GMP::get_si(123.0) == 123.0);
+
+ok (GMP::get_si('123') == 123.0);
+
+ok (GMP::get_si(mpz(123)) == 123.0);
+
+ok (GMP::get_si(mpq(123)) == 123.0);
+
+ok (GMP::get_si(mpf(123)) == 123.0);
+
+#------------------------------------------------------------------------------
+# GMP::integer_p
+
+ok (  GMP::integer_p (0));
+ok (  GMP::integer_p (123));
+ok (  GMP::integer_p (-123));
+
+ok (  GMP::integer_p ($uv_max));
+
+ok (  GMP::integer_p (0.0));
+ok (  GMP::integer_p (123.0));
+ok (  GMP::integer_p (-123.0));
+ok (! GMP::integer_p (0.5));
+ok (! GMP::integer_p (123.5));
+ok (! GMP::integer_p (-123.5));
+
+ok (  GMP::integer_p ('0'));
+ok (  GMP::integer_p ('123'));
+ok (  GMP::integer_p ('-123'));
+ok (! GMP::integer_p ('0.5'));
+ok (! GMP::integer_p ('123.5'));
+ok (! GMP::integer_p ('-123.5'));
+ok (! GMP::integer_p ('5/8'));
+
+ok (  GMP::integer_p (mpz(1)));
+
+ok (  GMP::integer_p (mpq(1)));
+ok (! GMP::integer_p (mpq(1,2)));
+
+ok (  GMP::integer_p (mpf(1.0)));
+ok (! GMP::integer_p (mpf(1.5)));
+
+#------------------------------------------------------------------------------
+# GMP::odd_p
+
+ok (! odd_p(0));
+ok (  odd_p(1));
+ok (! odd_p(2));
+
+ok (  odd_p($uv_max));
+
+ok (  odd_p(mpz(-3)));
+ok (! odd_p(mpz(-2)));
+ok (  odd_p(mpz(-1)));
+ok (! odd_p(mpz(0)));
+ok (  odd_p(mpz(1)));
+ok (! odd_p(mpz(2)));
+ok (  odd_p(mpz(3)));
+
+#------------------------------------------------------------------------------
+# GMP::printf
+
+GMP::printf ("hello world\n");
+
+sub via_printf {
+  my $s;
+  open TEMP, ">test.tmp" or die;
+  GMP::printf TEMP @_;
+  close TEMP or die;
+  open TEMP, "<test.tmp" or die;
+  read (TEMP, $s, 1024);
+  close TEMP or die;
+  unlink 'test.tmp';
+  return $s;
+}
+
+ok (sprintf ("%d", mpz(123)) eq '123');
+ok (sprintf ("%d %d %d", 456, mpz(123), 789) eq '456 123 789');
+ok (sprintf ("%d", mpq(15,16)) eq '15/16');
+ok (sprintf ("%f", mpf(1.5)) eq '1.500000');
+ok (sprintf ("%.2f", mpf(1.5)) eq '1.50');
+
+ok (sprintf ("%*d", 6, 123) eq '   123');
+ok (sprintf ("%*d", 6, mpz(123))  eq '   123');
+ok (sprintf ("%*d", 6, mpq(15,16))  eq ' 15/16');
+
+ok (sprintf ("%x", 123) eq '7b');
+ok (sprintf ("%x", mpz(123))  eq '7b');
+ok (sprintf ("%X", 123) eq '7B');
+ok (sprintf ("%X", mpz(123))  eq '7B');
+ok (sprintf ("%#x", 123) eq '0x7b');
+ok (sprintf ("%#x", mpz(123))  eq '0x7b');
+ok (sprintf ("%#X", 123) eq '0X7B');
+ok (sprintf ("%#X", mpz(123))  eq '0X7B');
+
+ok (sprintf ("%x", mpq(15,16))  eq 'f/10');
+ok (sprintf ("%X", mpq(15,16))  eq 'F/10');
+ok (sprintf ("%#x", mpq(15,16))  eq '0xf/0x10');
+ok (sprintf ("%#X", mpq(15,16))  eq '0XF/0X10');
+
+ok (sprintf ("%*.*f", 10, 3, 1.25) eq '     1.250');
+ok (sprintf ("%*.*f", 10, 3, mpf(1.5))   eq '     1.500');
+
+ok (via_printf ("%d", mpz(123)) eq '123');
+ok (via_printf ("%d %d %d", 456, mpz(123), 789) eq '456 123 789');
+ok (via_printf ("%d", mpq(15,16)) eq '15/16');
+ok (via_printf ("%f", mpf(1.5)) eq '1.500000');
+ok (via_printf ("%.2f", mpf(1.5)) eq '1.50');
+
+ok (via_printf ("%*d", 6, 123) eq '   123');
+ok (via_printf ("%*d", 6, mpz(123))  eq '   123');
+ok (via_printf ("%*d", 6, mpq(15,16))  eq ' 15/16');
+
+ok (via_printf ("%x", 123) eq '7b');
+ok (via_printf ("%x", mpz(123))  eq '7b');
+ok (via_printf ("%X", 123) eq '7B');
+ok (via_printf ("%X", mpz(123))  eq '7B');
+ok (via_printf ("%#x", 123) eq '0x7b');
+ok (via_printf ("%#x", mpz(123))  eq '0x7b');
+ok (via_printf ("%#X", 123) eq '0X7B');
+ok (via_printf ("%#X", mpz(123))  eq '0X7B');
+
+ok (via_printf ("%x", mpq(15,16))  eq 'f/10');
+ok (via_printf ("%X", mpq(15,16))  eq 'F/10');
+ok (via_printf ("%#x", mpq(15,16))  eq '0xf/0x10');
+ok (via_printf ("%#X", mpq(15,16))  eq '0XF/0X10');
+
+ok (via_printf ("%*.*f", 10, 3, 1.25) eq '     1.250');
+ok (via_printf ("%*.*f", 10, 3, mpf(1.5))   eq '     1.500');
+
+#------------------------------------------------------------------------------
+# GMP::sgn
+
+ok (sgn(-123) == -1);
+ok (sgn(0)    == 0);
+ok (sgn(123)  == 1);
+
+ok (sgn($uv_max) == 1);
+
+ok (sgn(-123.0) == -1);
+ok (sgn(0.0)    == 0);
+ok (sgn(123.0)  == 1);
+
+ok (sgn('-123') == -1);
+ok (sgn('0')    == 0);
+ok (sgn('123')  == 1);
+ok (sgn('-123.0') == -1);
+ok (sgn('0.0')    == 0);
+ok (sgn('123.0')  == 1);
+
+ok (sgn(substr('x-123x',1,4)) == -1);
+ok (sgn(substr('x0x',1,1))    == 0);
+ok (sgn(substr('x123x',1,3))  == 1);
+
+ok (mpz(-123)->sgn() == -1);
+ok (mpz(0)   ->sgn() == 0);
+ok (mpz(123) ->sgn() == 1);
+
+ok (mpq(-123)->sgn() == -1);
+ok (mpq(0)   ->sgn() == 0);
+ok (mpq(123) ->sgn() == 1);
+
+ok (mpf(-123)->sgn() == -1);
+ok (mpf(0)   ->sgn() == 0);
+ok (mpf(123) ->sgn() == 1);
+
+
+
+#------------------------------------------------------------------------------
+# overloaded constants
+
+if ($] > 5.00503) {
+  if (! do 'test2.pl') {
+    die "Cannot run test2.pl\n";
+  }
+}
+
+
+
+
+#------------------------------------------------------------------------------
+# $# stuff
+#
+# For some reason "local $#" doesn't leave $# back at its default undefined
+# state when exiting the block.
+
+{ local $# = 'hi %.0f there';
+  my $f = mpf(123);
+  ok ("$f" eq 'hi 123 there'); }
+
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/test2.pl b/third_party/gmp/demos/perl/test2.pl
new file mode 100644
index 0000000..31a1d6b
--- /dev/null
+++ b/third_party/gmp/demos/perl/test2.pl
@@ -0,0 +1,75 @@
+# GMP perl module tests (part 2)
+
+# Copyright 2001 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# The following uses of :constants seem to provoke segvs in perl 5.005_03,
+# so they're kept separate file to be run only on suitable perl versions.
+
+
+use GMP::Mpz qw(:constants);
+{
+  my $a = 123;
+  ok (UNIVERSAL::isa ($a, "GMP::Mpz"));
+}
+use GMP::Mpz qw(:noconstants);
+
+use GMP::Mpq qw(:constants);
+{
+  my $a = 123;
+  ok (UNIVERSAL::isa ($a, "GMP::Mpq"));
+}
+use GMP::Mpq qw(:noconstants);
+
+use GMP::Mpf qw(:constants);
+{
+  my $a = 123;
+  ok (UNIVERSAL::isa ($a, "GMP::Mpf"));
+}
+use GMP::Mpf qw(:noconstants);
+
+
+# compiled constants unchanged by clrbit etc when re-executed
+foreach (0, 1, 2) {
+  use GMP::Mpz qw(:constants);
+  my $a = 15;
+  my $b = 6;
+  use GMP::Mpz qw(:noconstants);
+  clrbit ($a, 0);
+  ok ($a == 14);
+  setbit ($b, 0);
+  ok ($b == 7);
+}
+
+1;
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/typemap b/third_party/gmp/demos/perl/typemap
new file mode 100644
index 0000000..e863a9c
--- /dev/null
+++ b/third_party/gmp/demos/perl/typemap
@@ -0,0 +1,108 @@
+# GMP module external subroutine type mappings.
+
+# Copyright 2001, 2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+TYPEMAP
+const_string		T_PV
+const_string_assume	CONST_STRING_ASSUME
+mpz			MPZ
+mpq			MPQ
+mpf			MPF
+mpz_assume		MPZ_ASSUME
+mpq_assume		MPQ_ASSUME
+mpf_assume		MPF_ASSUME
+mpz_coerce		MPZ_COERCE
+mpq_coerce		MPQ_COERCE
+mpf_coerce_st0		MPF_COERCE_ST0
+mpf_coerce_def		MPF_COERCE_DEF
+randstate		RANDSTATE
+ulong_coerce		ULONG_COERCE
+malloced_string		MALLOCED_STRING
+order_noswap		ORDER_NOSWAP
+dummy			DUMMY
+# perl 5.005 doesn't have UV in its standard typemap, so use this instead
+gmp_UV			GMP_UV
+
+
+INPUT
+MPZ
+	class_or_croak ($arg, mpz_class); $var = SvMPZ($arg);
+MPQ
+	class_or_croak ($arg, mpq_class); $var = SvMPQ($arg);
+MPF
+	class_or_croak ($arg, mpf_class); $var = SvMPF($arg);
+MPZ_ASSUME
+        MPZ_ASSUME ($var, $arg)
+MPQ_ASSUME
+        MPQ_ASSUME ($var, $arg)
+MPF_ASSUME
+        MPF_ASSUME ($var, $arg)
+MPZ_COERCE
+	$var = coerce_mpz (tmp_mpz_${(my $stnum=$arg)=~s/[^0-9]//g;\$stnum}, $arg)
+MPQ_COERCE
+	$var = coerce_mpq (tmp_mpq_${(my $stnum=$arg)=~s/[^0-9]//g;\$stnum}, $arg)
+MPF_COERCE_ST0
+        /* precision follows ST(0) */
+        assert (sv_derived_from (ST(0), mpf_class));
+	$var = coerce_mpf (tmp_mpf_${(my $stnum=$arg)=~s/[^0-9]//g;\$stnum},
+	                   $arg, mpf_get_prec (SvMPF(ST(0))))
+MPF_COERCE_DEF
+        /* default precision used */
+	$var = coerce_mpf (tmp_mpf_${(my $stnum=$arg)=~s/[^0-9]//g;\$stnum},
+	                   $arg, mpf_get_default_prec())
+RANDSTATE
+	class_or_croak ($arg, rand_class); $var = SvRANDSTATE($arg);
+ULONG_COERCE
+	$var = coerce_ulong ($arg)
+ORDER_NOSWAP
+	assert ($arg != &PL_sv_yes);
+DUMMY
+	/* dummy $var */
+CONST_STRING_ASSUME
+        /* No need to check for SvPOKp and use SvPV, this mapping is
+           only used for overload_constant, which always gets literal
+           strings.  */
+	assert (SvPOK ($arg));
+	$var = SvPVX ($arg);
+
+
+OUTPUT
+MPZ
+    sv_bless (sv_setref_pv ($arg, NULL, $var), mpz_class_hv);
+MPQ
+    sv_bless (sv_setref_pv ($arg, NULL, $var), mpq_class_hv);
+MPF
+    sv_bless (sv_setref_pv ($arg, NULL, $var), mpf_class_hv);
+RANDSTATE
+    sv_setref_pv ($arg, rand_class, $var);
+MALLOCED_STRING
+    sv_usepvn_mg ($arg, $var, strlen($var));
+GMP_UV
+    sv_setuv ($arg, (UV) ($var));
diff --git a/third_party/gmp/demos/pexpr-config-h.in b/third_party/gmp/demos/pexpr-config-h.in
new file mode 100644
index 0000000..b3e7f5d
--- /dev/null
+++ b/third_party/gmp/demos/pexpr-config-h.in
@@ -0,0 +1,45 @@
+/* Templates for pexpr program configuration.   -*- mode:c -*-
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Define if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H  @HAVE_SYS_RESOURCE_H_01@
+
+/* Define if you have the `clock' function. */
+#define HAVE_CLOCK  @HAVE_CLOCK_01@
+
+/* Define if you have the `cputime' function. */
+#define HAVE_CPUTIME  @HAVE_CPUTIME_01@
+
+/* Define if you have the `getrusage' function. */
+#define HAVE_GETRUSAGE  @HAVE_GETRUSAGE_01@
+
+/* Define if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY  @HAVE_GETTIMEOFDAY_01@
+
+/* Define if you have the `sigaction' function. */
+#define HAVE_SIGACTION  @HAVE_SIGACTION_01@
+
+/* Define if you have the `sigaltstack' function. */
+#define HAVE_SIGALTSTACK  @HAVE_SIGALTSTACK_01@
+
+/* Define if you have the `sigstack' function. */
+#define HAVE_SIGSTACK  @HAVE_SIGSTACK_01@
+
+/* Define if the system has the type `stack_t'. */
+#define HAVE_STACK_T  @HAVE_STACK_T_01@
diff --git a/third_party/gmp/demos/pexpr.c b/third_party/gmp/demos/pexpr.c
new file mode 100644
index 0000000..d5009e9
--- /dev/null
+++ b/third_party/gmp/demos/pexpr.c
@@ -0,0 +1,1380 @@
+/* Program for computing integer expressions using the GNU Multiple Precision
+   Arithmetic Library.
+
+Copyright 1997, 1999-2002, 2005, 2008, 2012, 2015 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* This expressions evaluator works by building an expression tree (using a
+   recursive descent parser) which is then evaluated.  The expression tree is
+   useful since we want to optimize certain expressions (like a^b % c).
+
+   Usage: pexpr [options] expr ...
+   (Assuming you called the executable `pexpr' of course.)
+
+   Command line options:
+
+   -b        print output in binary
+   -o        print output in octal
+   -d        print output in decimal (the default)
+   -x        print output in hexadecimal
+   -b<NUM>   print output in base NUM
+   -t        print timing information
+   -html     output html
+   -wml      output wml
+   -split    split long lines each 80th digit
+*/
+
+/* Define LIMIT_RESOURCE_USAGE if you want to make sure the program doesn't
+   use up extensive resources (cpu, memory).  Useful for the GMP demo on the
+   GMP web site, since we cannot load the server too much.  */
+
+#include "pexpr-config.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <ctype.h>
+
+#include <time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include "gmp.h"
+
+/* SunOS 4 and HPUX 9 don't define a canonical SIGSTKSZ, use a default. */
+#ifndef SIGSTKSZ
+#define SIGSTKSZ  4096
+#endif
+
+
+#define TIME(t,func)							\
+  do { int __t0, __tmp;							\
+    __t0 = cputime ();							\
+    {func;}								\
+    __tmp = cputime () - __t0;						\
+    (t) = __tmp;							\
+  } while (0)
+
+/* GMP version 1.x compatibility.  */
+#if ! (__GNU_MP_VERSION >= 2)
+typedef MP_INT __mpz_struct;
+typedef __mpz_struct mpz_t[1];
+typedef __mpz_struct *mpz_ptr;
+#define mpz_fdiv_q	mpz_div
+#define mpz_fdiv_r	mpz_mod
+#define mpz_tdiv_q_2exp	mpz_div_2exp
+#define mpz_sgn(Z) ((Z)->size < 0 ? -1 : (Z)->size > 0)
+#endif
+
+/* GMP version 2.0 compatibility.  */
+#if ! (__GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1)
+#define mpz_swap(a,b) \
+  do { __mpz_struct __t; __t = *a; *a = *b; *b = __t;} while (0)
+#endif
+
+jmp_buf errjmpbuf;
+
+enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW,
+	   AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC,
+	   LOG, LOG2, FERMAT, MERSENNE, FIBONACCI, RANDOM, NEXTPRIME, BINOM,
+	   TIMING};
+
+/* Type for the expression tree.  */
+struct expr
+{
+  enum op_t op;
+  union
+  {
+    struct {struct expr *lhs, *rhs;} ops;
+    mpz_t val;
+  } operands;
+};
+
+typedef struct expr *expr_t;
+
+void cleanup_and_exit (int);
+
+char *skipspace (char *);
+void makeexp (expr_t *, enum op_t, expr_t, expr_t);
+void free_expr (expr_t);
+char *expr (char *, expr_t *);
+char *term (char *, expr_t *);
+char *power (char *, expr_t *);
+char *factor (char *, expr_t *);
+int match (char *, char *);
+int matchp (char *, char *);
+int cputime (void);
+
+void mpz_eval_expr (mpz_ptr, expr_t);
+void mpz_eval_mod_expr (mpz_ptr, expr_t, mpz_ptr);
+
+char *error;
+int flag_print = 1;
+int print_timing = 0;
+int flag_html = 0;
+int flag_wml = 0;
+int flag_splitup_output = 0;
+char *newline = "";
+gmp_randstate_t rstate;
+
+
+
+/* cputime() returns user CPU time measured in milliseconds.  */
+#if ! HAVE_CPUTIME
+#if HAVE_GETRUSAGE
+int
+cputime (void)
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#else
+#if HAVE_CLOCK
+int
+cputime (void)
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+int
+cputime (void)
+{
+  return 0;
+}
+#endif
+#endif
+#endif
+
+
+int
+stack_downwards_helper (char *xp)
+{
+  char  y;
+  return &y < xp;
+}
+int
+stack_downwards_p (void)
+{
+  char  x;
+  return stack_downwards_helper (&x);
+}
+
+
+void
+setup_error_handler (void)
+{
+#if HAVE_SIGACTION
+  struct sigaction act;
+  act.sa_handler = cleanup_and_exit;
+  sigemptyset (&(act.sa_mask));
+#define SIGNAL(sig)  sigaction (sig, &act, NULL)
+#else
+  struct { int sa_flags; } act;
+#define SIGNAL(sig)  signal (sig, cleanup_and_exit)
+#endif
+  act.sa_flags = 0;
+
+  /* Set up a stack for signal handling.  A typical cause of error is stack
+     overflow, and in such situation a signal can not be delivered on the
+     overflown stack.  */
+#if HAVE_SIGALTSTACK
+  {
+    /* AIX uses stack_t, MacOS uses struct sigaltstack, various other
+       systems have both. */
+#if HAVE_STACK_T
+    stack_t s;
+#else
+    struct sigaltstack s;
+#endif
+    s.ss_sp = malloc (SIGSTKSZ);
+    s.ss_size = SIGSTKSZ;
+    s.ss_flags = 0;
+    if (sigaltstack (&s, NULL) != 0)
+      perror("sigaltstack");
+    act.sa_flags = SA_ONSTACK;
+  }
+#else
+#if HAVE_SIGSTACK
+  {
+    struct sigstack s;
+    s.ss_sp = malloc (SIGSTKSZ);
+    if (stack_downwards_p ())
+      s.ss_sp += SIGSTKSZ;
+    s.ss_onstack = 0;
+    if (sigstack (&s, NULL) != 0)
+      perror("sigstack");
+    act.sa_flags = SA_ONSTACK;
+  }
+#else
+#endif
+#endif
+
+#ifdef LIMIT_RESOURCE_USAGE
+  {
+    struct rlimit limit;
+
+    limit.rlim_cur = limit.rlim_max = 0;
+    setrlimit (RLIMIT_CORE, &limit);
+
+    limit.rlim_cur = 3;
+    limit.rlim_max = 4;
+    setrlimit (RLIMIT_CPU, &limit);
+
+    limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024;
+    setrlimit (RLIMIT_DATA, &limit);
+
+    getrlimit (RLIMIT_STACK, &limit);
+    limit.rlim_cur = 4 * 1024 * 1024;
+    setrlimit (RLIMIT_STACK, &limit);
+
+    SIGNAL (SIGXCPU);
+  }
+#endif /* LIMIT_RESOURCE_USAGE */
+
+  SIGNAL (SIGILL);
+  SIGNAL (SIGSEGV);
+#ifdef SIGBUS /* not in mingw */
+  SIGNAL (SIGBUS);
+#endif
+  SIGNAL (SIGFPE);
+  SIGNAL (SIGABRT);
+}
+
+int
+main (int argc, char **argv)
+{
+  struct expr *e;
+  int i;
+  mpz_t r;
+  int errcode = 0;
+  char *str;
+  int base = 10;
+
+  setup_error_handler ();
+
+  gmp_randinit (rstate, GMP_RAND_ALG_LC, 128);
+
+  {
+#if HAVE_GETTIMEOFDAY
+    struct timeval tv;
+    gettimeofday (&tv, NULL);
+    gmp_randseed_ui (rstate, tv.tv_sec + tv.tv_usec);
+#else
+    time_t t;
+    time (&t);
+    gmp_randseed_ui (rstate, t);
+#endif
+  }
+
+  mpz_init (r);
+
+  while (argc > 1 && argv[1][0] == '-')
+    {
+      char *arg = argv[1];
+
+      if (arg[1] >= '0' && arg[1] <= '9')
+	break;
+
+      if (arg[1] == 't')
+	print_timing = 1;
+      else if (arg[1] == 'b' && arg[2] >= '0' && arg[2] <= '9')
+	{
+	  base = atoi (arg + 2);
+	  if (base < 2 || base > 62)
+	    {
+	      fprintf (stderr, "error: invalid output base\n");
+	      exit (-1);
+	    }
+	}
+      else if (arg[1] == 'b' && arg[2] == 0)
+	base = 2;
+      else if (arg[1] == 'x' && arg[2] == 0)
+	base = 16;
+      else if (arg[1] == 'X' && arg[2] == 0)
+	base = -16;
+      else if (arg[1] == 'o' && arg[2] == 0)
+	base = 8;
+      else if (arg[1] == 'd' && arg[2] == 0)
+	base = 10;
+      else if (arg[1] == 'v' && arg[2] == 0)
+	{
+	  printf ("pexpr linked to gmp %s\n", __gmp_version);
+	}
+      else if (strcmp (arg, "-html") == 0)
+	{
+	  flag_html = 1;
+	  newline = "<br>";
+	}
+      else if (strcmp (arg, "-wml") == 0)
+	{
+	  flag_wml = 1;
+	  newline = "<br/>";
+	}
+      else if (strcmp (arg, "-split") == 0)
+	{
+	  flag_splitup_output = 1;
+	}
+      else if (strcmp (arg, "-noprint") == 0)
+	{
+	  flag_print = 0;
+	}
+      else
+	{
+	  fprintf (stderr, "error: unknown option `%s'\n", arg);
+	  exit (-1);
+	}
+      argv++;
+      argc--;
+    }
+
+  for (i = 1; i < argc; i++)
+    {
+      int s;
+      int jmpval;
+
+      /* Set up error handler for parsing expression.  */
+      jmpval = setjmp (errjmpbuf);
+      if (jmpval != 0)
+	{
+	  fprintf (stderr, "error: %s%s\n", error, newline);
+	  fprintf (stderr, "       %s%s\n", argv[i], newline);
+	  if (! flag_html)
+	    {
+	      /* ??? Dunno how to align expression position with arrow in
+		 HTML ??? */
+	      fprintf (stderr, "       ");
+	      for (s = jmpval - (long) argv[i]; --s >= 0; )
+		putc (' ', stderr);
+	      fprintf (stderr, "^\n");
+	    }
+
+	  errcode |= 1;
+	  continue;
+	}
+
+      str = expr (argv[i], &e);
+
+      if (str[0] != 0)
+	{
+	  fprintf (stderr,
+		   "error: garbage where end of expression expected%s\n",
+		   newline);
+	  fprintf (stderr, "       %s%s\n", argv[i], newline);
+	  if (! flag_html)
+	    {
+	      /* ??? Dunno how to align expression position with arrow in
+		 HTML ??? */
+	      fprintf (stderr, "        ");
+	      for (s = str - argv[i]; --s; )
+		putc (' ', stderr);
+	      fprintf (stderr, "^\n");
+	    }
+
+	  errcode |= 1;
+	  free_expr (e);
+	  continue;
+	}
+
+      /* Set up error handler for evaluating expression.  */
+      if (setjmp (errjmpbuf))
+	{
+	  fprintf (stderr, "error: %s%s\n", error, newline);
+	  fprintf (stderr, "       %s%s\n", argv[i], newline);
+	  if (! flag_html)
+	    {
+	      /* ??? Dunno how to align expression position with arrow in
+		 HTML ??? */
+	      fprintf (stderr, "       ");
+	      for (s = str - argv[i]; --s >= 0; )
+		putc (' ', stderr);
+	      fprintf (stderr, "^\n");
+	    }
+
+	  errcode |= 2;
+	  continue;
+	}
+
+      if (print_timing)
+	{
+	  int t;
+	  TIME (t, mpz_eval_expr (r, e));
+	  printf ("computation took %d ms%s\n", t, newline);
+	}
+      else
+	mpz_eval_expr (r, e);
+
+      if (flag_print)
+	{
+	  size_t out_len;
+	  char *tmp, *s;
+
+	  out_len = mpz_sizeinbase (r, base >= 0 ? base : -base) + 2;
+#ifdef LIMIT_RESOURCE_USAGE
+	  if (out_len > 100000)
+	    {
+	      printf ("result is about %ld digits, not printing it%s\n",
+		      (long) out_len - 3, newline);
+	      exit (-2);
+	    }
+#endif
+	  tmp = malloc (out_len);
+
+	  if (print_timing)
+	    {
+	      int t;
+	      printf ("output conversion ");
+	      TIME (t, mpz_get_str (tmp, base, r));
+	      printf ("took %d ms%s\n", t, newline);
+	    }
+	  else
+	    mpz_get_str (tmp, base, r);
+
+	  out_len = strlen (tmp);
+	  if (flag_splitup_output)
+	    {
+	      for (s = tmp; out_len > 80; s += 80)
+		{
+		  fwrite (s, 1, 80, stdout);
+		  printf ("%s\n", newline);
+		  out_len -= 80;
+		}
+
+	      fwrite (s, 1, out_len, stdout);
+	    }
+	  else
+	    {
+	      fwrite (tmp, 1, out_len, stdout);
+	    }
+
+	  free (tmp);
+	  printf ("%s\n", newline);
+	}
+      else
+	{
+	  printf ("result is approximately %ld digits%s\n",
+		  (long) mpz_sizeinbase (r, base >= 0 ? base : -base),
+		  newline);
+	}
+
+      free_expr (e);
+    }
+
+  mpz_clear (r);
+
+  exit (errcode);
+}
+
+char *
+expr (char *str, expr_t *e)
+{
+  expr_t e2;
+
+  str = skipspace (str);
+  if (str[0] == '+')
+    {
+      str = term (str + 1, e);
+    }
+  else if (str[0] == '-')
+    {
+      str = term (str + 1, e);
+      makeexp (e, NEG, *e, NULL);
+    }
+  else if (str[0] == '~')
+    {
+      str = term (str + 1, e);
+      makeexp (e, NOT, *e, NULL);
+    }
+  else
+    {
+      str = term (str, e);
+    }
+
+  for (;;)
+    {
+      str = skipspace (str);
+      switch (str[0])
+	{
+	case 'p':
+	  if (match ("plus", str))
+	    {
+	      str = term (str + 4, &e2);
+	      makeexp (e, PLUS, *e, e2);
+	    }
+	  else
+	    return str;
+	  break;
+	case 'm':
+	  if (match ("minus", str))
+	    {
+	      str = term (str + 5, &e2);
+	      makeexp (e, MINUS, *e, e2);
+	    }
+	  else
+	    return str;
+	  break;
+	case '+':
+	  str = term (str + 1, &e2);
+	  makeexp (e, PLUS, *e, e2);
+	  break;
+	case '-':
+	  str = term (str + 1, &e2);
+	  makeexp (e, MINUS, *e, e2);
+	  break;
+	default:
+	  return str;
+	}
+    }
+}
+
+char *
+term (char *str, expr_t *e)
+{
+  expr_t e2;
+
+  str = power (str, e);
+  for (;;)
+    {
+      str = skipspace (str);
+      switch (str[0])
+	{
+	case 'm':
+	  if (match ("mul", str))
+	    {
+	      str = power (str + 3, &e2);
+	      makeexp (e, MULT, *e, e2);
+	      break;
+	    }
+	  if (match ("mod", str))
+	    {
+	      str = power (str + 3, &e2);
+	      makeexp (e, MOD, *e, e2);
+	      break;
+	    }
+	  return str;
+	case 'd':
+	  if (match ("div", str))
+	    {
+	      str = power (str + 3, &e2);
+	      makeexp (e, DIV, *e, e2);
+	      break;
+	    }
+	  return str;
+	case 'r':
+	  if (match ("rem", str))
+	    {
+	      str = power (str + 3, &e2);
+	      makeexp (e, REM, *e, e2);
+	      break;
+	    }
+	  return str;
+	case 'i':
+	  if (match ("invmod", str))
+	    {
+	      str = power (str + 6, &e2);
+	      makeexp (e, REM, *e, e2);
+	      break;
+	    }
+	  return str;
+	case 't':
+	  if (match ("times", str))
+	    {
+	      str = power (str + 5, &e2);
+	      makeexp (e, MULT, *e, e2);
+	      break;
+	    }
+	  if (match ("thru", str))
+	    {
+	      str = power (str + 4, &e2);
+	      makeexp (e, DIV, *e, e2);
+	      break;
+	    }
+	  if (match ("through", str))
+	    {
+	      str = power (str + 7, &e2);
+	      makeexp (e, DIV, *e, e2);
+	      break;
+	    }
+	  return str;
+	case '*':
+	  str = power (str + 1, &e2);
+	  makeexp (e, MULT, *e, e2);
+	  break;
+	case '/':
+	  str = power (str + 1, &e2);
+	  makeexp (e, DIV, *e, e2);
+	  break;
+	case '%':
+	  str = power (str + 1, &e2);
+	  makeexp (e, MOD, *e, e2);
+	  break;
+	default:
+	  return str;
+	}
+    }
+}
+
+char *
+power (char *str, expr_t *e)
+{
+  expr_t e2;
+
+  str = factor (str, e);
+  while (str[0] == '!')
+    {
+      str++;
+      makeexp (e, FAC, *e, NULL);
+    }
+  str = skipspace (str);
+  if (str[0] == '^')
+    {
+      str = power (str + 1, &e2);
+      makeexp (e, POW, *e, e2);
+    }
+  return str;
+}
+
+int
+match (char *s, char *str)
+{
+  char *ostr = str;
+  int i;
+
+  for (i = 0; s[i] != 0; i++)
+    {
+      if (str[i] != s[i])
+	return 0;
+    }
+  str = skipspace (str + i);
+  return str - ostr;
+}
+
+int
+matchp (char *s, char *str)
+{
+  char *ostr = str;
+  int i;
+
+  for (i = 0; s[i] != 0; i++)
+    {
+      if (str[i] != s[i])
+	return 0;
+    }
+  str = skipspace (str + i);
+  if (str[0] == '(')
+    return str - ostr + 1;
+  return 0;
+}
+
+struct functions
+{
+  char *spelling;
+  enum op_t op;
+  int arity; /* 1 or 2 means real arity; 0 means arbitrary.  */
+};
+
+struct functions fns[] =
+{
+  {"sqrt", SQRT, 1},
+#if __GNU_MP_VERSION >= 2
+  {"root", ROOT, 2},
+  {"popc", POPCNT, 1},
+  {"hamdist", HAMDIST, 2},
+#endif
+  {"gcd", GCD, 0},
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+  {"lcm", LCM, 0},
+#endif
+  {"and", AND, 0},
+  {"ior", IOR, 0},
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+  {"xor", XOR, 0},
+#endif
+  {"plus", PLUS, 0},
+  {"pow", POW, 2},
+  {"minus", MINUS, 2},
+  {"mul", MULT, 0},
+  {"div", DIV, 2},
+  {"mod", MOD, 2},
+  {"rem", REM, 2},
+#if __GNU_MP_VERSION >= 2
+  {"invmod", INVMOD, 2},
+#endif
+  {"log", LOG, 2},
+  {"log2", LOG2, 1},
+  {"F", FERMAT, 1},
+  {"M", MERSENNE, 1},
+  {"fib", FIBONACCI, 1},
+  {"Fib", FIBONACCI, 1},
+  {"random", RANDOM, 1},
+  {"nextprime", NEXTPRIME, 1},
+  {"binom", BINOM, 2},
+  {"binomial", BINOM, 2},
+  {"fac", FAC, 1},
+  {"fact", FAC, 1},
+  {"factorial", FAC, 1},
+  {"time", TIMING, 1},
+  {"", NOP, 0}
+};
+
+char *
+factor (char *str, expr_t *e)
+{
+  expr_t e1, e2;
+
+  str = skipspace (str);
+
+  if (isalpha (str[0]))
+    {
+      int i;
+      int cnt;
+
+      for (i = 0; fns[i].op != NOP; i++)
+	{
+	  if (fns[i].arity == 1)
+	    {
+	      cnt = matchp (fns[i].spelling, str);
+	      if (cnt != 0)
+		{
+		  str = expr (str + cnt, &e1);
+		  str = skipspace (str);
+		  if (str[0] != ')')
+		    {
+		      error = "expected `)'";
+		      longjmp (errjmpbuf, (int) (long) str);
+		    }
+		  makeexp (e, fns[i].op, e1, NULL);
+		  return str + 1;
+		}
+	    }
+	}
+
+      for (i = 0; fns[i].op != NOP; i++)
+	{
+	  if (fns[i].arity != 1)
+	    {
+	      cnt = matchp (fns[i].spelling, str);
+	      if (cnt != 0)
+		{
+		  str = expr (str + cnt, &e1);
+		  str = skipspace (str);
+
+		  if (str[0] != ',')
+		    {
+		      error = "expected `,' and another operand";
+		      longjmp (errjmpbuf, (int) (long) str);
+		    }
+
+		  str = skipspace (str + 1);
+		  str = expr (str, &e2);
+		  str = skipspace (str);
+
+		  if (fns[i].arity == 0)
+		    {
+		      while (str[0] == ',')
+			{
+			  makeexp (&e1, fns[i].op, e1, e2);
+			  str = skipspace (str + 1);
+			  str = expr (str, &e2);
+			  str = skipspace (str);
+			}
+		    }
+
+		  if (str[0] != ')')
+		    {
+		      error = "expected `)'";
+		      longjmp (errjmpbuf, (int) (long) str);
+		    }
+
+		  makeexp (e, fns[i].op, e1, e2);
+		  return str + 1;
+		}
+	    }
+	}
+    }
+
+  if (str[0] == '(')
+    {
+      str = expr (str + 1, e);
+      str = skipspace (str);
+      if (str[0] != ')')
+	{
+	  error = "expected `)'";
+	  longjmp (errjmpbuf, (int) (long) str);
+	}
+      str++;
+    }
+  else if (str[0] >= '0' && str[0] <= '9')
+    {
+      expr_t res;
+      char *s, *sc;
+
+      res = malloc (sizeof (struct expr));
+      res -> op = LIT;
+      mpz_init (res->operands.val);
+
+      s = str;
+      while (isalnum (str[0]))
+	str++;
+      sc = malloc (str - s + 1);
+      memcpy (sc, s, str - s);
+      sc[str - s] = 0;
+
+      mpz_set_str (res->operands.val, sc, 0);
+      *e = res;
+      free (sc);
+    }
+  else
+    {
+      error = "operand expected";
+      longjmp (errjmpbuf, (int) (long) str);
+    }
+  return str;
+}
+
+char *
+skipspace (char *str)
+{
+  while (str[0] == ' ')
+    str++;
+  return str;
+}
+
+/* Make a new expression with operation OP and right hand side
+   RHS and left hand side lhs.  Put the result in R.  */
+void
+makeexp (expr_t *r, enum op_t op, expr_t lhs, expr_t rhs)
+{
+  expr_t res;
+  res = malloc (sizeof (struct expr));
+  res -> op = op;
+  res -> operands.ops.lhs = lhs;
+  res -> operands.ops.rhs = rhs;
+  *r = res;
+  return;
+}
+
+/* Free the memory used by expression E.  */
+void
+free_expr (expr_t e)
+{
+  if (e->op != LIT)
+    {
+      free_expr (e->operands.ops.lhs);
+      if (e->operands.ops.rhs != NULL)
+	free_expr (e->operands.ops.rhs);
+    }
+  else
+    {
+      mpz_clear (e->operands.val);
+    }
+}
+
+/* Evaluate the expression E and put the result in R.  */
+void
+mpz_eval_expr (mpz_ptr r, expr_t e)
+{
+  mpz_t lhs, rhs;
+
+  switch (e->op)
+    {
+    case LIT:
+      mpz_set (r, e->operands.val);
+      return;
+    case PLUS:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_add (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case MINUS:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_sub (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case MULT:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_mul (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case DIV:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_fdiv_q (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case MOD:
+      mpz_init (rhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_abs (rhs, rhs);
+      mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs);
+      mpz_clear (rhs);
+      return;
+    case REM:
+      /* Check if lhs operand is POW expression and optimize for that case.  */
+      if (e->operands.ops.lhs->op == POW)
+	{
+	  mpz_t powlhs, powrhs;
+	  mpz_init (powlhs);
+	  mpz_init (powrhs);
+	  mpz_init (rhs);
+	  mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs);
+	  mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs);
+	  mpz_eval_expr (rhs, e->operands.ops.rhs);
+	  mpz_powm (r, powlhs, powrhs, rhs);
+	  if (mpz_cmp_si (rhs, 0L) < 0)
+	    mpz_neg (r, r);
+	  mpz_clear (powlhs);
+	  mpz_clear (powrhs);
+	  mpz_clear (rhs);
+	  return;
+	}
+
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_fdiv_r (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#if __GNU_MP_VERSION >= 2
+    case INVMOD:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_invert (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#endif
+    case POW:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      if (mpz_cmpabs_ui (lhs, 1) <= 0)
+	{
+	  /* For 0^rhs and 1^rhs, we just need to verify that
+	     rhs is well-defined.  For (-1)^rhs we need to
+	     determine (rhs mod 2).  For simplicity, compute
+	     (rhs mod 2) for all three cases.  */
+	  expr_t two, et;
+	  two = malloc (sizeof (struct expr));
+	  two -> op = LIT;
+	  mpz_init_set_ui (two->operands.val, 2L);
+	  makeexp (&et, MOD, e->operands.ops.rhs, two);
+	  e->operands.ops.rhs = et;
+	}
+
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      if (mpz_cmp_si (rhs, 0L) == 0)
+	/* x^0 is 1 */
+	mpz_set_ui (r, 1L);
+      else if (mpz_cmp_si (lhs, 0L) == 0)
+	/* 0^y (where y != 0) is 0 */
+	mpz_set_ui (r, 0L);
+      else if (mpz_cmp_ui (lhs, 1L) == 0)
+	/* 1^y is 1 */
+	mpz_set_ui (r, 1L);
+      else if (mpz_cmp_si (lhs, -1L) == 0)
+	/* (-1)^y just depends on whether y is even or odd */
+	mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L);
+      else if (mpz_cmp_si (rhs, 0L) < 0)
+	/* x^(-n) is 0 */
+	mpz_set_ui (r, 0L);
+      else
+	{
+	  unsigned long int cnt;
+	  unsigned long int y;
+	  /* error if exponent does not fit into an unsigned long int.  */
+	  if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
+	    goto pow_err;
+
+	  y = mpz_get_ui (rhs);
+	  /* x^y == (x/(2^c))^y * 2^(c*y) */
+#if __GNU_MP_VERSION >= 2
+	  cnt = mpz_scan1 (lhs, 0);
+#else
+	  cnt = 0;
+#endif
+	  if (cnt != 0)
+	    {
+	      if (y * cnt / cnt != y)
+		goto pow_err;
+	      mpz_tdiv_q_2exp (lhs, lhs, cnt);
+	      mpz_pow_ui (r, lhs, y);
+	      mpz_mul_2exp (r, r, y * cnt);
+	    }
+	  else
+	    mpz_pow_ui (r, lhs, y);
+	}
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    pow_err:
+      error = "result of `pow' operator too large";
+      mpz_clear (lhs); mpz_clear (rhs);
+      longjmp (errjmpbuf, 1);
+    case GCD:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_gcd (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+    case LCM:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_lcm (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#endif
+    case AND:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_and (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case IOR:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_ior (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+    case XOR:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_xor (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#endif
+    case NEG:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      mpz_neg (r, r);
+      return;
+    case NOT:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      mpz_com (r, r);
+      return;
+    case SQRT:
+      mpz_init (lhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      if (mpz_sgn (lhs) < 0)
+	{
+	  error = "cannot take square root of negative numbers";
+	  mpz_clear (lhs);
+	  longjmp (errjmpbuf, 1);
+	}
+      mpz_sqrt (r, lhs);
+      return;
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+    case ROOT:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      if (mpz_sgn (rhs) <= 0)
+	{
+	  error = "cannot take non-positive root orders";
+	  mpz_clear (lhs); mpz_clear (rhs);
+	  longjmp (errjmpbuf, 1);
+	}
+      if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0)
+	{
+	  error = "cannot take even root orders of negative numbers";
+	  mpz_clear (lhs); mpz_clear (rhs);
+	  longjmp (errjmpbuf, 1);
+	}
+
+      {
+	unsigned long int nth = mpz_get_ui (rhs);
+	if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
+	  {
+	    /* If we are asked to take an awfully large root order, cheat and
+	       ask for the largest order we can pass to mpz_root.  This saves
+	       some error prone special cases.  */
+	    nth = ~(unsigned long int) 0;
+	  }
+	mpz_root (r, lhs, nth);
+      }
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#endif
+    case FAC:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      if (mpz_size (r) > 1)
+	{
+	  error = "result of `!' operator too large";
+	  longjmp (errjmpbuf, 1);
+	}
+      mpz_fac_ui (r, mpz_get_ui (r));
+      return;
+#if __GNU_MP_VERSION >= 2
+    case POPCNT:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      { long int cnt;
+	cnt = mpz_popcount (r);
+	mpz_set_si (r, cnt);
+      }
+      return;
+    case HAMDIST:
+      { long int cnt;
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	mpz_eval_expr (rhs, e->operands.ops.rhs);
+	cnt = mpz_hamdist (lhs, rhs);
+	mpz_clear (lhs); mpz_clear (rhs);
+	mpz_set_si (r, cnt);
+      }
+      return;
+#endif
+    case LOG2:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      { unsigned long int cnt;
+	if (mpz_sgn (r) <= 0)
+	  {
+	    error = "logarithm of non-positive number";
+	    longjmp (errjmpbuf, 1);
+	  }
+	cnt = mpz_sizeinbase (r, 2);
+	mpz_set_ui (r, cnt - 1);
+      }
+      return;
+    case LOG:
+      { unsigned long int cnt;
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	mpz_eval_expr (rhs, e->operands.ops.rhs);
+	if (mpz_sgn (lhs) <= 0)
+	  {
+	    error = "logarithm of non-positive number";
+	    mpz_clear (lhs); mpz_clear (rhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	if (mpz_cmp_ui (rhs, 256) >= 0)
+	  {
+	    error = "logarithm base too large";
+	    mpz_clear (lhs); mpz_clear (rhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs));
+	mpz_set_ui (r, cnt - 1);
+	mpz_clear (lhs); mpz_clear (rhs);
+      }
+      return;
+    case FERMAT:
+      {
+	unsigned long int t;
+	mpz_init (lhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	t = (unsigned long int) 1 << mpz_get_ui (lhs);
+	if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0)
+	  {
+	    error = "too large Mersenne number index";
+	    mpz_clear (lhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	mpz_set_ui (r, 1);
+	mpz_mul_2exp (r, r, t);
+	mpz_add_ui (r, r, 1);
+	mpz_clear (lhs);
+      }
+      return;
+    case MERSENNE:
+      mpz_init (lhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0)
+	{
+	  error = "too large Mersenne number index";
+	  mpz_clear (lhs);
+	  longjmp (errjmpbuf, 1);
+	}
+      mpz_set_ui (r, 1);
+      mpz_mul_2exp (r, r, mpz_get_ui (lhs));
+      mpz_sub_ui (r, r, 1);
+      mpz_clear (lhs);
+      return;
+    case FIBONACCI:
+      { mpz_t t;
+	unsigned long int n, i;
+	mpz_init (lhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
+	  {
+	    error = "Fibonacci index out of range";
+	    mpz_clear (lhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	n = mpz_get_ui (lhs);
+	mpz_clear (lhs);
+
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+	mpz_fib_ui (r, n);
+#else
+	mpz_init_set_ui (t, 1);
+	mpz_set_ui (r, 1);
+
+	if (n <= 2)
+	  mpz_set_ui (r, 1);
+	else
+	  {
+	    for (i = 3; i <= n; i++)
+	      {
+		mpz_add (t, t, r);
+		mpz_swap (t, r);
+	      }
+	  }
+	mpz_clear (t);
+#endif
+      }
+      return;
+    case RANDOM:
+      {
+	unsigned long int n;
+	mpz_init (lhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
+	  {
+	    error = "random number size out of range";
+	    mpz_clear (lhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	n = mpz_get_ui (lhs);
+	mpz_clear (lhs);
+	mpz_urandomb (r, rstate, n);
+      }
+      return;
+    case NEXTPRIME:
+      {
+	mpz_eval_expr (r, e->operands.ops.lhs);
+	mpz_nextprime (r, r);
+      }
+      return;
+    case BINOM:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      {
+	unsigned long int k;
+	if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
+	  {
+	    error = "k too large in (n over k) expression";
+	    mpz_clear (lhs); mpz_clear (rhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	k = mpz_get_ui (rhs);
+	mpz_bin_ui (r, lhs, k);
+      }
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case TIMING:
+      {
+	int t0;
+	t0 = cputime ();
+	mpz_eval_expr (r, e->operands.ops.lhs);
+	printf ("time: %d\n", cputime () - t0);
+      }
+      return;
+    default:
+      abort ();
+    }
+}
+
+/* Evaluate the expression E modulo MOD and put the result in R.  */
+void
+mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod)
+{
+  mpz_t lhs, rhs;
+
+  switch (e->op)
+    {
+      case POW:
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
+	mpz_eval_expr (rhs, e->operands.ops.rhs);
+	mpz_powm (r, lhs, rhs, mod);
+	mpz_clear (lhs); mpz_clear (rhs);
+	return;
+      case PLUS:
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
+	mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
+	mpz_add (r, lhs, rhs);
+	if (mpz_cmp_si (r, 0L) < 0)
+	  mpz_add (r, r, mod);
+	else if (mpz_cmp (r, mod) >= 0)
+	  mpz_sub (r, r, mod);
+	mpz_clear (lhs); mpz_clear (rhs);
+	return;
+      case MINUS:
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
+	mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
+	mpz_sub (r, lhs, rhs);
+	if (mpz_cmp_si (r, 0L) < 0)
+	  mpz_add (r, r, mod);
+	else if (mpz_cmp (r, mod) >= 0)
+	  mpz_sub (r, r, mod);
+	mpz_clear (lhs); mpz_clear (rhs);
+	return;
+      case MULT:
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
+	mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
+	mpz_mul (r, lhs, rhs);
+	mpz_mod (r, r, mod);
+	mpz_clear (lhs); mpz_clear (rhs);
+	return;
+      default:
+	mpz_init (lhs);
+	mpz_eval_expr (lhs, e);
+	mpz_mod (r, lhs, mod);
+	mpz_clear (lhs);
+	return;
+    }
+}
+
+void
+cleanup_and_exit (int sig)
+{
+  switch (sig) {
+#ifdef LIMIT_RESOURCE_USAGE
+  case SIGXCPU:
+    printf ("expression took too long to evaluate%s\n", newline);
+    break;
+#endif
+  case SIGFPE:
+    printf ("divide by zero%s\n", newline);
+    break;
+  default:
+    printf ("expression required too much memory to evaluate%s\n", newline);
+    break;
+  }
+  exit (-2);
+}
diff --git a/third_party/gmp/demos/primes.c b/third_party/gmp/demos/primes.c
new file mode 100644
index 0000000..3cb32e2
--- /dev/null
+++ b/third_party/gmp/demos/primes.c
@@ -0,0 +1,387 @@
+/* List and count primes.
+   Written by tege while on holiday in Rodupp, August 2001.
+   Between 10 and 500 times faster than previous program.
+
+Copyright 2001, 2002, 2006, 2012 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+
+/* IDEAS:
+ * Do not fill primes[] with real primes when the range [fr,to] is small,
+   when fr,to are relatively large.  Fill primes[] with odd numbers instead.
+   [Probably a bad idea, since the primes[] array would become very large.]
+ * Separate small primes and large primes when sieving.  Either the Montgomery
+   way (i.e., having a large array a multiple of L1 cache size), or just
+   separate loops for primes <= S and primes > S.  The latter primes do not
+   require an inner loop, since they will touch the sieving array at most once.
+ * Pre-fill sieving array with an appropriately aligned ...00100100... pattern,
+   then omit 3 from primes array.  (May require similar special handling of 3
+   as we now have for 2.)
+ * A large SIEVE_LIMIT currently implies very large memory usage, mainly due
+   to the sieving array in make_primelist, but also because of the primes[]
+   array.  We might want to stage the program, using sieve_region/find_primes
+   to build primes[].  Make report() a function pointer, as part of achieving
+   this.
+ * Store primes[] as two arrays, one array with primes represented as delta
+   values using just 8 bits (if gaps are too big, store bogus primes!)
+   and one array with "rem" values.  The latter needs 32-bit values.
+ * A new entry point, mpz_probab_prime_likely_p, would be useful.
+ * Improve command line syntax and versatility.  "primes -f FROM -t TO",
+   allow either to be omitted for open interval.  (But disallow
+   "primes -c -f FROM" since that would be infinity.)  Allow printing a
+   limited *number* of primes using syntax like "primes -f FROM -n NUMBER".
+ * When looking for maxgaps, we should not perform any primality testing until
+   we find possible record gaps.  Should speed up the searches tremendously.
+ */
+
+#include "gmp.h"
+
+struct primes
+{
+  unsigned int prime;
+  int rem;
+};
+
+struct primes *primes;
+unsigned long n_primes;
+
+void find_primes (unsigned char *, mpz_t, unsigned long, mpz_t);
+void sieve_region (unsigned char *, mpz_t, unsigned long);
+void make_primelist (unsigned long);
+
+int flag_print = 1;
+int flag_count = 0;
+int flag_maxgap = 0;
+unsigned long maxgap = 0;
+unsigned long total_primes = 0;
+
+void
+report (mpz_t prime)
+{
+  total_primes += 1;
+  if (flag_print)
+    {
+      mpz_out_str (stdout, 10, prime);
+      printf ("\n");
+    }
+  if (flag_maxgap)
+    {
+      static unsigned long prev_prime_low = 0;
+      unsigned long gap;
+      if (prev_prime_low != 0)
+	{
+	  gap = mpz_get_ui (prime) - prev_prime_low;
+	  if (maxgap < gap)
+	    maxgap = gap;
+	}
+      prev_prime_low = mpz_get_ui (prime);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  char *progname = argv[0];
+  mpz_t fr, to;
+  mpz_t fr2, to2;
+  unsigned long sieve_lim;
+  unsigned long est_n_primes;
+  unsigned char *s;
+  mpz_t tmp;
+  mpz_t siev_sqr_lim;
+
+  while (argc != 1)
+    {
+      if (strcmp (argv[1], "-c") == 0)
+	{
+	  flag_count = 1;
+	  argv++;
+	  argc--;
+	}
+      else if (strcmp (argv[1], "-p") == 0)
+	{
+	  flag_print = 2;
+	  argv++;
+	  argc--;
+	}
+      else if (strcmp (argv[1], "-g") == 0)
+	{
+	  flag_maxgap = 1;
+	  argv++;
+	  argc--;
+	}
+      else
+	break;
+    }
+
+  if (flag_count || flag_maxgap)
+    flag_print--;		/* clear unless an explicit -p  */
+
+  mpz_init (fr);
+  mpz_init (to);
+  mpz_init (fr2);
+  mpz_init (to2);
+
+  if (argc == 3)
+    {
+      mpz_set_str (fr, argv[1], 0);
+      if (argv[2][0] == '+')
+	{
+	  mpz_set_str (to, argv[2] + 1, 0);
+	  mpz_add (to, to, fr);
+	}
+      else
+	mpz_set_str (to, argv[2], 0);
+    }
+  else if (argc == 2)
+    {
+      mpz_set_ui (fr, 0);
+      mpz_set_str (to, argv[1], 0);
+    }
+  else
+    {
+      fprintf (stderr, "usage: %s [-c] [-p] [-g] [from [+]]to\n", progname);
+      exit (1);
+    }
+
+  mpz_set (fr2, fr);
+  if (mpz_cmp_ui (fr2, 3) < 0)
+    {
+      mpz_set_ui (fr2, 2);
+      report (fr2);
+      mpz_set_ui (fr2, 3);
+    }
+  mpz_setbit (fr2, 0);				/* make odd */
+  mpz_sub_ui (to2, to, 1);
+  mpz_setbit (to2, 0);				/* make odd */
+
+  mpz_init (tmp);
+  mpz_init (siev_sqr_lim);
+
+  mpz_sqrt (tmp, to2);
+#define SIEVE_LIMIT 10000000
+  if (mpz_cmp_ui (tmp, SIEVE_LIMIT) < 0)
+    {
+      sieve_lim = mpz_get_ui (tmp);
+    }
+  else
+    {
+      sieve_lim = SIEVE_LIMIT;
+      mpz_sub (tmp, to2, fr2);
+      if (mpz_cmp_ui (tmp, sieve_lim) < 0)
+	sieve_lim = mpz_get_ui (tmp);	/* limit sieving for small ranges */
+    }
+  mpz_set_ui (siev_sqr_lim, sieve_lim + 1);
+  mpz_mul_ui (siev_sqr_lim, siev_sqr_lim, sieve_lim + 1);
+
+  est_n_primes = (size_t) (sieve_lim / log((double) sieve_lim) * 1.13) + 10;
+  primes = malloc (est_n_primes * sizeof primes[0]);
+  make_primelist (sieve_lim);
+  assert (est_n_primes >= n_primes);
+
+#if DEBUG
+  printf ("sieve_lim = %lu\n", sieve_lim);
+  printf ("n_primes = %lu (3..%u)\n",
+	  n_primes, primes[n_primes - 1].prime);
+#endif
+
+#define S (1 << 15)		/* FIXME: Figure out L1 cache size */
+  s = malloc (S/2);
+  while (mpz_cmp (fr2, to2) <= 0)
+    {
+      unsigned long rsize;
+      rsize = S;
+      mpz_add_ui (tmp, fr2, rsize);
+      if (mpz_cmp (tmp, to2) > 0)
+	{
+	  mpz_sub (tmp, to2, fr2);
+	  rsize = mpz_get_ui (tmp) + 2;
+	}
+#if DEBUG
+      printf ("Sieving region ["); mpz_out_str (stdout, 10, fr2);
+      printf (","); mpz_add_ui (tmp, fr2, rsize - 2);
+      mpz_out_str (stdout, 10, tmp); printf ("]\n");
+#endif
+      sieve_region (s, fr2, rsize);
+      find_primes (s, fr2, rsize / 2, siev_sqr_lim);
+
+      mpz_add_ui (fr2, fr2, S);
+    }
+  free (s);
+
+  if (flag_count)
+    printf ("Pi(interval) = %lu\n", total_primes);
+
+  if (flag_maxgap)
+    printf ("max gap: %lu\n", maxgap);
+
+  return 0;
+}
+
+/* Find primes in region [fr,fr+rsize).  Requires that fr is odd and that
+   rsize is even.  The sieving array s should be aligned for "long int" and
+   have rsize/2 entries, rounded up to the nearest multiple of "long int".  */
+void
+sieve_region (unsigned char *s, mpz_t fr, unsigned long rsize)
+{
+  unsigned long ssize = rsize / 2;
+  unsigned long start, start2, prime;
+  unsigned long i;
+  mpz_t tmp;
+
+  mpz_init (tmp);
+
+#if 0
+  /* initialize sieving array */
+  for (ii = 0; ii < (ssize + sizeof (long) - 1) / sizeof (long); ii++)
+    ((long *) s) [ii] = ~0L;
+#else
+  {
+    long k;
+    long *se = (long *) (s + ((ssize + sizeof (long) - 1) & -sizeof (long)));
+    for (k = -((ssize + sizeof (long) - 1) / sizeof (long)); k < 0; k++)
+      se[k] = ~0L;
+  }
+#endif
+
+  for (i = 0; i < n_primes; i++)
+    {
+      prime = primes[i].prime;
+
+      if (primes[i].rem >= 0)
+	{
+	  start2 = primes[i].rem;
+	}
+      else
+	{
+	  mpz_set_ui (tmp, prime);
+	  mpz_mul_ui (tmp, tmp, prime);
+	  if (mpz_cmp (fr, tmp) <= 0)
+	    {
+	      mpz_sub (tmp, tmp, fr);
+	      if (mpz_cmp_ui (tmp, 2 * ssize) > 0)
+		break;		/* avoid overflow at next line, also speedup */
+	      start = mpz_get_ui (tmp);
+	    }
+	  else
+	    {
+	      start = (prime - mpz_tdiv_ui (fr, prime)) % prime;
+	      if (start % 2 != 0)
+		start += prime;		/* adjust if even divisible */
+	    }
+	  start2 = start / 2;
+	}
+
+#if 0
+      for (ii = start2; ii < ssize; ii += prime)
+	s[ii] = 0;
+      primes[i].rem = ii - ssize;
+#else
+      {
+	long k;
+	unsigned char *se = s + ssize; /* point just beyond sieving range */
+	for (k = start2 - ssize; k < 0; k += prime)
+	  se[k] = 0;
+	primes[i].rem = k;
+      }
+#endif
+    }
+  mpz_clear (tmp);
+}
+
+/* Find primes in region [fr,fr+rsize), using the previously sieved s[].  */
+void
+find_primes (unsigned char *s, mpz_t  fr, unsigned long ssize,
+	     mpz_t siev_sqr_lim)
+{
+  unsigned long j, ij;
+  mpz_t tmp;
+
+  mpz_init (tmp);
+  for (j = 0; j < (ssize + sizeof (long) - 1) / sizeof (long); j++)
+    {
+      if (((long *) s) [j] != 0)
+	{
+	  for (ij = 0; ij < sizeof (long); ij++)
+	    {
+	      if (s[j * sizeof (long) + ij] != 0)
+		{
+		  if (j * sizeof (long) + ij >= ssize)
+		    goto out;
+		  mpz_add_ui (tmp, fr, (j * sizeof (long) + ij) * 2);
+		  if (mpz_cmp (tmp, siev_sqr_lim) < 0 ||
+		      mpz_probab_prime_p (tmp, 10))
+		    report (tmp);
+		}
+	    }
+	}
+    }
+ out:
+  mpz_clear (tmp);
+}
+
+/* Generate a list of primes and store in the global array primes[].  */
+void
+make_primelist (unsigned long maxprime)
+{
+#if 1
+  unsigned char *s;
+  unsigned long ssize = maxprime / 2;
+  unsigned long i, ii, j;
+
+  s = malloc (ssize);
+  memset (s, ~0, ssize);
+  for (i = 3; ; i += 2)
+    {
+      unsigned long isqr = i * i;
+      if (isqr >= maxprime)
+	break;
+      if (s[i * i / 2 - 1] == 0)
+	continue;				/* only sieve with primes */
+      for (ii = i * i / 2 - 1; ii < ssize; ii += i)
+	s[ii] = 0;
+    }
+  n_primes = 0;
+  for (j = 0; j < ssize; j++)
+    {
+      if (s[j] != 0)
+	{
+	  primes[n_primes].prime = j * 2 + 3;
+	  primes[n_primes].rem = -1;
+	  n_primes++;
+	}
+    }
+  /* FIXME: This should not be needed if fencepost errors were fixed... */
+  if (primes[n_primes - 1].prime > maxprime)
+    n_primes--;
+  free (s);
+#else
+  unsigned long i;
+  n_primes = 0;
+  for (i = 3; i <= maxprime; i += 2)
+    {
+      if (i < 7 || (i % 3 != 0 && i % 5 != 0 && i % 7 != 0))
+	{
+	  primes[n_primes].prime = i;
+	  primes[n_primes].rem = -1;
+	  n_primes++;
+	}
+    }
+#endif
+}
diff --git a/third_party/gmp/demos/primes.h b/third_party/gmp/demos/primes.h
new file mode 100644
index 0000000..b85c7e1
--- /dev/null
+++ b/third_party/gmp/demos/primes.h
@@ -0,0 +1,552 @@
+P( 1, 0xaaaaaaaaaaaaaaabUL, 0x5555555555555555UL) /* 3 */
+P( 2, 0xcccccccccccccccdUL, 0x3333333333333333UL) /* 5 */
+P( 2, 0x6db6db6db6db6db7UL, 0x2492492492492492UL) /* 7 */
+P( 4, 0x2e8ba2e8ba2e8ba3UL, 0x1745d1745d1745d1UL) /* 11 */
+P( 2, 0x4ec4ec4ec4ec4ec5UL, 0x13b13b13b13b13b1UL) /* 13 */
+P( 4, 0xf0f0f0f0f0f0f0f1UL, 0x0f0f0f0f0f0f0f0fUL) /* 17 */
+P( 2, 0x86bca1af286bca1bUL, 0x0d79435e50d79435UL) /* 19 */
+P( 4, 0xd37a6f4de9bd37a7UL, 0x0b21642c8590b216UL) /* 23 */
+P( 6, 0x34f72c234f72c235UL, 0x08d3dcb08d3dcb08UL) /* 29 */
+P( 2, 0xef7bdef7bdef7bdfUL, 0x0842108421084210UL) /* 31 */
+P( 6, 0x14c1bacf914c1badUL, 0x06eb3e45306eb3e4UL) /* 37 */
+P( 4, 0x8f9c18f9c18f9c19UL, 0x063e7063e7063e70UL) /* 41 */
+P( 2, 0x82fa0be82fa0be83UL, 0x05f417d05f417d05UL) /* 43 */
+P( 4, 0x51b3bea3677d46cfUL, 0x0572620ae4c415c9UL) /* 47 */
+P( 6, 0x21cfb2b78c13521dUL, 0x04d4873ecade304dUL) /* 53 */
+P( 6, 0xcbeea4e1a08ad8f3UL, 0x0456c797dd49c341UL) /* 59 */
+P( 2, 0x4fbcda3ac10c9715UL, 0x04325c53ef368eb0UL) /* 61 */
+P( 6, 0xf0b7672a07a44c6bUL, 0x03d226357e16ece5UL) /* 67 */
+P( 4, 0x193d4bb7e327a977UL, 0x039b0ad12073615aUL) /* 71 */
+P( 2, 0x7e3f1f8fc7e3f1f9UL, 0x0381c0e070381c0eUL) /* 73 */
+P( 6, 0x9b8b577e613716afUL, 0x033d91d2a2067b23UL) /* 79 */
+P( 4, 0xa3784a062b2e43dbUL, 0x03159721ed7e7534UL) /* 83 */
+P( 6, 0xf47e8fd1fa3f47e9UL, 0x02e05c0b81702e05UL) /* 89 */
+P( 8, 0xa3a0fd5c5f02a3a1UL, 0x02a3a0fd5c5f02a3UL) /* 97 */
+P( 4, 0x3a4c0a237c32b16dUL, 0x0288df0cac5b3f5dUL) /* 101 */
+P( 2, 0xdab7ec1dd3431b57UL, 0x027c45979c95204fUL) /* 103 */
+P( 4, 0x77a04c8f8d28ac43UL, 0x02647c69456217ecUL) /* 107 */
+P( 2, 0xa6c0964fda6c0965UL, 0x02593f69b02593f6UL) /* 109 */
+P( 4, 0x90fdbc090fdbc091UL, 0x0243f6f0243f6f02UL) /* 113 */
+P(14, 0x7efdfbf7efdfbf7fUL, 0x0204081020408102UL) /* 127 */
+P( 4, 0x03e88cb3c9484e2bUL, 0x01f44659e4a42715UL) /* 131 */
+P( 6, 0xe21a291c077975b9UL, 0x01de5d6e3f8868a4UL) /* 137 */
+P( 2, 0x3aef6ca970586723UL, 0x01d77b654b82c339UL) /* 139 */
+P(10, 0xdf5b0f768ce2cabdUL, 0x01b7d6c3dda338b2UL) /* 149 */
+P( 2, 0x6fe4dfc9bf937f27UL, 0x01b2036406c80d90UL) /* 151 */
+P( 6, 0x5b4fe5e92c0685b5UL, 0x01a16d3f97a4b01aUL) /* 157 */
+P( 6, 0x1f693a1c451ab30bUL, 0x01920fb49d0e228dUL) /* 163 */
+P( 4, 0x8d07aa27db35a717UL, 0x01886e5f0abb0499UL) /* 167 */
+P( 6, 0x882383b30d516325UL, 0x017ad2208e0ecc35UL) /* 173 */
+P( 6, 0xed6866f8d962ae7bUL, 0x016e1f76b4337c6cUL) /* 179 */
+P( 2, 0x3454dca410f8ed9dUL, 0x016a13cd15372904UL) /* 181 */
+P(10, 0x1d7ca632ee936f3fUL, 0x01571ed3c506b39aUL) /* 191 */
+P( 2, 0x70bf015390948f41UL, 0x015390948f40feacUL) /* 193 */
+P( 4, 0xc96bdb9d3d137e0dUL, 0x014cab88725af6e7UL) /* 197 */
+P( 2, 0x2697cc8aef46c0f7UL, 0x0149539e3b2d066eUL) /* 199 */
+P(12, 0xc0e8f2a76e68575bUL, 0x013698df3de07479UL) /* 211 */
+P(12, 0x687763dfdb43bb1fUL, 0x0125e22708092f11UL) /* 223 */
+P( 4, 0x1b10ea929ba144cbUL, 0x0120b470c67c0d88UL) /* 227 */
+P( 2, 0x1d10c4c0478bbcedUL, 0x011e2ef3b3fb8744UL) /* 229 */
+P( 4, 0x63fb9aeb1fdcd759UL, 0x0119453808ca29c0UL) /* 233 */
+P( 6, 0x64afaa4f437b2e0fUL, 0x0112358e75d30336UL) /* 239 */
+P( 2, 0xf010fef010fef011UL, 0x010fef010fef010fUL) /* 241 */
+P(10, 0x28cbfbeb9a020a33UL, 0x0105197f7d734041UL) /* 251 */
+P( 6, 0xff00ff00ff00ff01UL, 0x00ff00ff00ff00ffUL) /* 257 */
+P( 6, 0xd624fd1470e99cb7UL, 0x00f92fb2211855a8UL) /* 263 */
+P( 6, 0x8fb3ddbd6205b5c5UL, 0x00f3a0d52cba8723UL) /* 269 */
+P( 2, 0xd57da36ca27acdefUL, 0x00f1d48bcee0d399UL) /* 271 */
+P( 6, 0xee70c03b25e4463dUL, 0x00ec979118f3fc4dUL) /* 277 */
+P( 4, 0xc5b1a6b80749cb29UL, 0x00e939651fe2d8d3UL) /* 281 */
+P( 2, 0x47768073c9b97113UL, 0x00e79372e225fe30UL) /* 283 */
+P(10, 0x2591e94884ce32adUL, 0x00dfac1f74346c57UL) /* 293 */
+P(14, 0xf02806abc74be1fbUL, 0x00d578e97c3f5fe5UL) /* 307 */
+P( 4, 0x7ec3e8f3a7198487UL, 0x00d2ba083b445250UL) /* 311 */
+P( 2, 0x58550f8a39409d09UL, 0x00d161543e28e502UL) /* 313 */
+P( 4, 0xec9e48ae6f71de15UL, 0x00cebcf8bb5b4169UL) /* 317 */
+P(14, 0x2ff3a018bfce8063UL, 0x00c5fe740317f9d0UL) /* 331 */
+P( 6, 0x7f9ec3fcf61fe7b1UL, 0x00c2780613c0309eUL) /* 337 */
+P(10, 0x89f5abe570e046d3UL, 0x00bcdd535db1cc5bUL) /* 347 */
+P( 2, 0xda971b23f1545af5UL, 0x00bbc8408cd63069UL) /* 349 */
+P( 4, 0x79d5f00b9a7862a1UL, 0x00b9a7862a0ff465UL) /* 353 */
+P( 6, 0x4dba1df32a128a57UL, 0x00b68d31340e4307UL) /* 359 */
+P( 8, 0x87530217b7747d8fUL, 0x00b2927c29da5519UL) /* 367 */
+P( 6, 0x30baae53bb5e06ddUL, 0x00afb321a1496fdfUL) /* 373 */
+P( 6, 0xee70206c12e9b5b3UL, 0x00aceb0f891e6551UL) /* 379 */
+P( 4, 0xcdde9462ec9dbe7fUL, 0x00ab1cbdd3e2970fUL) /* 383 */
+P( 6, 0xafb64b05ec41cf4dUL, 0x00a87917088e262bUL) /* 389 */
+P( 8, 0x02944ff5aec02945UL, 0x00a513fd6bb00a51UL) /* 397 */
+P( 4, 0x2cb033128382df71UL, 0x00a36e71a2cb0331UL) /* 401 */
+P( 8, 0x1ccacc0c84b1c2a9UL, 0x00a03c1688732b30UL) /* 409 */
+P(10, 0x19a93db575eb3a0bUL, 0x009c69169b30446dUL) /* 419 */
+P( 2, 0xcebeef94fa86fe2dUL, 0x009baade8e4a2f6eUL) /* 421 */
+P(10, 0x6faa77fb3f8df54fUL, 0x00980e4156201301UL) /* 431 */
+P( 2, 0x68a58af00975a751UL, 0x00975a750ff68a58UL) /* 433 */
+P( 6, 0xd56e36d0c3efac07UL, 0x009548e4979e0829UL) /* 439 */
+P( 4, 0xd8b44c47a8299b73UL, 0x0093efd1c50e726bUL) /* 443 */
+P( 6, 0x02d9ccaf9ba70e41UL, 0x0091f5bcb8bb02d9UL) /* 449 */
+P( 8, 0x0985e1c023d9e879UL, 0x008f67a1e3fdc261UL) /* 457 */
+P( 4, 0x2a343316c494d305UL, 0x008e2917e0e702c6UL) /* 461 */
+P( 2, 0x70cb7916ab67652fUL, 0x008d8be33f95d715UL) /* 463 */
+P( 4, 0xd398f132fb10fe5bUL, 0x008c55841c815ed5UL) /* 467 */
+P(12, 0x6f2a38a6bf54fa1fUL, 0x0088d180cd3a4133UL) /* 479 */
+P( 8, 0x211df689b98f81d7UL, 0x00869222b1acf1ceUL) /* 487 */
+P( 4, 0x0e994983e90f1ec3UL, 0x0085797b917765abUL) /* 491 */
+P( 8, 0xad671e44bed87f3bUL, 0x008355ace3c897dbUL) /* 499 */
+P( 4, 0xf9623a0516e70fc7UL, 0x00824a4e60b3262bUL) /* 503 */
+P( 6, 0x4b7129be9dece355UL, 0x0080c121b28bd1baUL) /* 509 */
+P(12, 0x190f3b7473f62c39UL, 0x007dc9f3397d4c29UL) /* 521 */
+P( 2, 0x63dacc9aad46f9a3UL, 0x007d4ece8fe88139UL) /* 523 */
+P(18, 0xc1108fda24e8d035UL, 0x0079237d65bcce50UL) /* 541 */
+P( 6, 0xb77578472319bd8bUL, 0x0077cf53c5f7936cUL) /* 547 */
+P(10, 0x473d20a1c7ed9da5UL, 0x0075a8accfbdd11eUL) /* 557 */
+P( 6, 0xfbe85af0fea2c8fbUL, 0x007467ac557c228eUL) /* 563 */
+P( 6, 0x58a1f7e6ce0f4c09UL, 0x00732d70ed8db8e9UL) /* 569 */
+P( 2, 0x1a00e58c544986f3UL, 0x0072c62a24c3797fUL) /* 571 */
+P( 6, 0x7194a17f55a10dc1UL, 0x007194a17f55a10dUL) /* 577 */
+P(10, 0x7084944785e33763UL, 0x006fa549b41da7e7UL) /* 587 */
+P( 6, 0xba10679bd84886b1UL, 0x006e8419e6f61221UL) /* 593 */
+P( 6, 0xebe9c6bb31260967UL, 0x006d68b5356c207bUL) /* 599 */
+P( 2, 0x97a3fe4bd1ff25e9UL, 0x006d0b803685c01bUL) /* 601 */
+P( 6, 0x6c6388395b84d99fUL, 0x006bf790a8b2d207UL) /* 607 */
+P( 6, 0x8c51da6a1335df6dUL, 0x006ae907ef4b96c2UL) /* 613 */
+P( 4, 0x46f3234475d5add9UL, 0x006a37991a23aeadUL) /* 617 */
+P( 2, 0x905605ca3c619a43UL, 0x0069dfbdd4295b66UL) /* 619 */
+P(12, 0xcee8dff304767747UL, 0x0067dc4c45c8033eUL) /* 631 */
+P(10, 0xff99c27f00663d81UL, 0x00663d80ff99c27fUL) /* 641 */
+P( 2, 0xacca407f671ddc2bUL, 0x0065ec17e3559948UL) /* 643 */
+P( 4, 0xe71298bac1e12337UL, 0x00654ac835cfba5cUL) /* 647 */
+P( 6, 0xfa1e94309cd09045UL, 0x00645c854ae10772UL) /* 653 */
+P( 6, 0xbebccb8e91496b9bUL, 0x006372990e5f901fUL) /* 659 */
+P( 2, 0x312fa30cc7d7b8bdUL, 0x006325913c07beefUL) /* 661 */
+P(12, 0x6160ff9e9f006161UL, 0x006160ff9e9f0061UL) /* 673 */
+P( 4, 0x6b03673b5e28152dUL, 0x0060cdb520e5e88eUL) /* 677 */
+P( 6, 0xfe802ffa00bfe803UL, 0x005ff4017fd005ffUL) /* 683 */
+P( 8, 0xe66fe25c9e907c7bUL, 0x005ed79e31a4dccdUL) /* 691 */
+P(10, 0x3f8b236c76528895UL, 0x005d7d42d48ac5efUL) /* 701 */
+P( 8, 0xf6f923bf01ce2c0dUL, 0x005c6f35ccba5028UL) /* 709 */
+P(10, 0x6c3d3d98bed7c42fUL, 0x005b2618ec6ad0a5UL) /* 719 */
+P( 8, 0x30981efcd4b010e7UL, 0x005a2553748e42e7UL) /* 727 */
+P( 6, 0x6f691fc81ebbe575UL, 0x0059686cf744cd5bUL) /* 733 */
+P( 6, 0xb10480ddb47b52cbUL, 0x0058ae97bab79976UL) /* 739 */
+P( 4, 0x74cd59ed64f3f0d7UL, 0x0058345f1876865fUL) /* 743 */
+P( 8, 0x0105cb81316d6c0fUL, 0x005743d5bb24795aUL) /* 751 */
+P( 6, 0x9be64c6d91c1195dUL, 0x005692c4d1ab74abUL) /* 757 */
+P( 4, 0x71b3f945a27b1f49UL, 0x00561e46a4d5f337UL) /* 761 */
+P( 8, 0x77d80d50e508fd01UL, 0x005538ed06533997UL) /* 769 */
+P( 4, 0xa5eb778e133551cdUL, 0x0054c807f2c0bec2UL) /* 773 */
+P(14, 0x18657d3c2d8a3f1bUL, 0x005345efbc572d36UL) /* 787 */
+P(10, 0x2e40e220c34ad735UL, 0x00523a758f941345UL) /* 797 */
+P(12, 0xa76593c70a714919UL, 0x005102370f816c89UL) /* 809 */
+P( 2, 0x1eef452124eea383UL, 0x0050cf129fb94acfUL) /* 811 */
+P(10, 0x38206dc242ba771dUL, 0x004fd31941cafdd1UL) /* 821 */
+P( 2, 0x4cd4c35807772287UL, 0x004fa1704aa75945UL) /* 823 */
+P( 4, 0x83de917d5e69ddf3UL, 0x004f3ed6d45a63adUL) /* 827 */
+P( 2, 0x882ef0403b4a6c15UL, 0x004f0de57154ebedUL) /* 829 */
+P(10, 0xf8fb6c51c606b677UL, 0x004e1cae8815f811UL) /* 839 */
+P(14, 0xb4abaac446d3e1fdUL, 0x004cd47ba5f6ff19UL) /* 853 */
+P( 4, 0xa9f83bbe484a14e9UL, 0x004c78ae734df709UL) /* 857 */
+P( 2, 0x0bebbc0d1ce874d3UL, 0x004c4b19ed85cfb8UL) /* 859 */
+P( 4, 0xbd418eaf0473189fUL, 0x004bf093221d1218UL) /* 863 */
+P(14, 0x44e3af6f372b7e65UL, 0x004aba3c21dc633fUL) /* 877 */
+P( 4, 0xc87fdace4f9e5d91UL, 0x004a6360c344de00UL) /* 881 */
+P( 2, 0xec93479c446bd9bbUL, 0x004a383e9f74d68aUL) /* 883 */
+P( 4, 0xdac4d592e777c647UL, 0x0049e28fbabb9940UL) /* 887 */
+P(20, 0xa63ea8c8f61f0c23UL, 0x0048417b57c78cd7UL) /* 907 */
+P( 4, 0xe476062ea5cbbb6fUL, 0x0047f043713f3a2bUL) /* 911 */
+P( 8, 0xdf68761c69daac27UL, 0x00474ff2a10281cfUL) /* 919 */
+P(10, 0xb813d737637aa061UL, 0x00468b6f9a978f91UL) /* 929 */
+P( 8, 0xa3a77aac1fb15099UL, 0x0045f13f1caff2e2UL) /* 937 */
+P( 4, 0x17f0c3e0712c5825UL, 0x0045a5228cec23e9UL) /* 941 */
+P( 6, 0xfd912a70ff30637bUL, 0x0045342c556c66b9UL) /* 947 */
+P( 6, 0xfbb3b5dc01131289UL, 0x0044c4a23feeced7UL) /* 953 */
+P(14, 0x856d560a0f5acdf7UL, 0x0043c5c20d3c9fe6UL) /* 967 */
+P( 4, 0x96472f314d3f89e3UL, 0x00437e494b239798UL) /* 971 */
+P( 6, 0xa76f5c7ed2253531UL, 0x0043142d118e47cbUL) /* 977 */
+P( 6, 0x816eae7c7bf69fe7UL, 0x0042ab5c73a13458UL) /* 983 */
+P( 8, 0xb6a2bea4cfb1781fUL, 0x004221950db0f3dbUL) /* 991 */
+P( 6, 0xa3900c53318e81edUL, 0x0041bbb2f80a4553UL) /* 997 */
+P(12, 0x60aa7f5d9f148d11UL, 0x0040f391612c6680UL) /* 1009 */
+P( 4, 0x6be8c0102c7a505dUL, 0x0040b1e94173fefdUL) /* 1013 */
+P( 6, 0x8ff3f0ed28728f33UL, 0x004050647d9d0445UL) /* 1019 */
+P( 2, 0x680e0a87e5ec7155UL, 0x004030241b144f3bUL) /* 1021 */
+P(10, 0xbbf70fa49fe829b7UL, 0x003f90c2ab542cb1UL) /* 1031 */
+P( 2, 0xd69d1e7b6a50ca39UL, 0x003f71412d59f597UL) /* 1033 */
+P( 6, 0x1a1e0f46b6d26aefUL, 0x003f137701b98841UL) /* 1039 */
+P(10, 0x7429f9a7a8251829UL, 0x003e79886b60e278UL) /* 1049 */
+P( 2, 0xd9c2219d1b863613UL, 0x003e5b1916a7181dUL) /* 1051 */
+P(10, 0x91406c1820d077adUL, 0x003dc4a50968f524UL) /* 1061 */
+P( 2, 0x521f4ec02e3d2b97UL, 0x003da6e4c9550321UL) /* 1063 */
+P( 6, 0xbb8283b63dc8eba5UL, 0x003d4e4f06f1def3UL) /* 1069 */
+P(18, 0x431eda153229ebbfUL, 0x003c4a6bdd24f9a4UL) /* 1087 */
+P( 4, 0xaf0bf78d7e01686bUL, 0x003c11d54b525c73UL) /* 1091 */
+P( 2, 0xa9ced0742c086e8dUL, 0x003bf5b1c5721065UL) /* 1093 */
+P( 4, 0xc26458ad9f632df9UL, 0x003bbdb9862f23b4UL) /* 1097 */
+P( 6, 0xbbff1255dff892afUL, 0x003b6a8801db5440UL) /* 1103 */
+P( 6, 0xcbd49a333f04d8fdUL, 0x003b183cf0fed886UL) /* 1109 */
+P( 8, 0xec84ed6f9cfdeff5UL, 0x003aabe394bdc3f4UL) /* 1117 */
+P( 6, 0x97980cc40bda9d4bUL, 0x003a5ba3e76156daUL) /* 1123 */
+P( 6, 0x777f34d524f5cbd9UL, 0x003a0c3e953378dbUL) /* 1129 */
+P(22, 0x2797051d94cbbb7fUL, 0x0038f03561320b1eUL) /* 1151 */
+P( 2, 0xea769051b4f43b81UL, 0x0038d6ecaef5908aUL) /* 1153 */
+P(10, 0xce7910f3034d4323UL, 0x003859cf221e6069UL) /* 1163 */
+P( 8, 0x92791d1374f5b99bUL, 0x0037f7415dc9588aUL) /* 1171 */
+P(10, 0x89a5645cc68ea1b5UL, 0x00377df0d3902626UL) /* 1181 */
+P( 6, 0x5f8aacf796c0cf0bUL, 0x00373622136907faUL) /* 1187 */
+P( 6, 0xf2e90a15e33edf99UL, 0x0036ef0c3b39b92fUL) /* 1193 */
+P( 8, 0x8e99e5feb897c451UL, 0x0036915f47d55e6dUL) /* 1201 */
+P(12, 0xaca2eda38fb91695UL, 0x0036072cf3f866fdUL) /* 1213 */
+P( 4, 0x5d9b737be5ea8b41UL, 0x0035d9b737be5ea8UL) /* 1217 */
+P( 6, 0x4aefe1db93fd7cf7UL, 0x0035961559cc81c7UL) /* 1223 */
+P( 6, 0xa0994ef20b3f8805UL, 0x0035531c897a4592UL) /* 1229 */
+P( 2, 0x103890bda912822fUL, 0x00353ceebd3e98a4UL) /* 1231 */
+P( 6, 0xb441659d13a9147dUL, 0x0034fad381585e5eUL) /* 1237 */
+P(12, 0x1e2134440c4c3f21UL, 0x00347884d1103130UL) /* 1249 */
+P(10, 0x263a27727a6883c3UL, 0x00340dd3ac39bf56UL) /* 1259 */
+P(18, 0x78e221472ab33855UL, 0x003351fdfecc140cUL) /* 1277 */
+P( 2, 0x95eac88e82e6faffUL, 0x00333d72b089b524UL) /* 1279 */
+P( 4, 0xf66c258317be8dabUL, 0x0033148d44d6b261UL) /* 1283 */
+P( 6, 0x09ee202c7cb91939UL, 0x0032d7aef8412458UL) /* 1289 */
+P( 2, 0x8d2fca1042a09ea3UL, 0x0032c3850e79c0f1UL) /* 1291 */
+P( 6, 0x82779c856d8b8bf1UL, 0x00328766d59048a2UL) /* 1297 */
+P( 4, 0x3879361cba8a223dUL, 0x00325fa18cb11833UL) /* 1301 */
+P( 2, 0xf23f43639c3182a7UL, 0x00324bd659327e22UL) /* 1303 */
+P( 4, 0xa03868fc474bcd13UL, 0x0032246e784360f4UL) /* 1307 */
+P(12, 0x651e78b8c5311a97UL, 0x0031afa5f1a33a08UL) /* 1319 */
+P( 2, 0x8ffce639c00c6719UL, 0x00319c63ff398e70UL) /* 1321 */
+P( 6, 0xf7b460754b0b61cfUL, 0x003162f7519a86a7UL) /* 1327 */
+P(34, 0x7b03f3359b8e63b1UL, 0x0030271fc9d3fc3cUL) /* 1361 */
+P( 6, 0xa55c5326041eb667UL, 0x002ff104ae89750bUL) /* 1367 */
+P( 6, 0x647f88ab896a76f5UL, 0x002fbb62a236d133UL) /* 1373 */
+P( 8, 0x8fd971434a55a46dUL, 0x002f74997d2070b4UL) /* 1381 */
+P(18, 0x9fbf969958046447UL, 0x002ed84aa8b6fce3UL) /* 1399 */
+P(10, 0x9986feba69be3a81UL, 0x002e832df7a46dbdUL) /* 1409 */
+P(14, 0xa668b3e6d053796fUL, 0x002e0e0846857cabUL) /* 1423 */
+P( 4, 0x97694e6589f4e09bUL, 0x002decfbdfb55ee6UL) /* 1427 */
+P( 2, 0x37890c00b7721dbdUL, 0x002ddc876f3ff488UL) /* 1429 */
+P( 4, 0x5ac094a235f37ea9UL, 0x002dbbc1d4c482c4UL) /* 1433 */
+P( 6, 0x31cff775f2d5d65fUL, 0x002d8af0e0de0556UL) /* 1439 */
+P( 8, 0xddad8e6b36505217UL, 0x002d4a7b7d14b30aUL) /* 1447 */
+P( 4, 0x5a27df897062cd03UL, 0x002d2a85073bcf4eUL) /* 1451 */
+P( 2, 0xe2396fe0fdb5a625UL, 0x002d1a9ab13e8be4UL) /* 1453 */
+P( 6, 0xb352a4957e82317bUL, 0x002ceb1eb4b9fd8bUL) /* 1459 */
+P(12, 0xd8ab3f2c60c2ea3fUL, 0x002c8d503a79794cUL) /* 1471 */
+P(10, 0x6893f702f0452479UL, 0x002c404d708784edUL) /* 1481 */
+P( 2, 0x9686fdc182acf7e3UL, 0x002c31066315ec52UL) /* 1483 */
+P( 4, 0x6854037173dce12fUL, 0x002c1297d80f2664UL) /* 1487 */
+P( 2, 0x7f0ded1685c27331UL, 0x002c037044c55f6bUL) /* 1489 */
+P( 4, 0xeeda72e1fe490b7dUL, 0x002be5404cd13086UL) /* 1493 */
+P( 6, 0x9e7bfc959a8e6e53UL, 0x002bb845adaf0cceUL) /* 1499 */
+P(12, 0x49b314d6d4753dd7UL, 0x002b5f62c639f16dUL) /* 1511 */
+P(12, 0x2e8f8c5ac4aa1b3bUL, 0x002b07e6734f2b88UL) /* 1523 */
+P( 8, 0xb8ef723481163d33UL, 0x002ace569d8342b7UL) /* 1531 */
+P(12, 0x6a2ec96a594287b7UL, 0x002a791d5dbd4dcfUL) /* 1543 */
+P( 6, 0xdba41c6d13aab8c5UL, 0x002a4eff8113017cUL) /* 1549 */
+P( 4, 0xc2adbe648dc3aaf1UL, 0x002a3319e156df32UL) /* 1553 */
+P( 6, 0x87a2bade565f91a7UL, 0x002a0986286526eaUL) /* 1559 */
+P( 8, 0x4d6fe8798c01f5dfUL, 0x0029d29551d91e39UL) /* 1567 */
+P( 4, 0x3791310c8c23d98bUL, 0x0029b7529e109f0aUL) /* 1571 */
+P( 8, 0xf80e446b01228883UL, 0x00298137491ea465UL) /* 1579 */
+P( 4, 0x9aed1436fbf500cfUL, 0x0029665e1eb9f9daUL) /* 1583 */
+P(14, 0x7839b54cc8b24115UL, 0x002909752e019a5eUL) /* 1597 */
+P( 4, 0xc128c646ad0309c1UL, 0x0028ef35e2e5efb0UL) /* 1601 */
+P( 6, 0x14de631624a3c377UL, 0x0028c815aa4b8278UL) /* 1607 */
+P( 2, 0x3f7b9fe68b0ecbf9UL, 0x0028bb1b867199daUL) /* 1609 */
+P( 4, 0x284ffd75ec00a285UL, 0x0028a13ff5d7b002UL) /* 1613 */
+P( 6, 0x37803cb80dea2ddbUL, 0x00287ab3f173e755UL) /* 1619 */
+P( 2, 0x86b63f7c9ac4c6fdUL, 0x00286dead67713bdUL) /* 1621 */
+P( 6, 0x8b6851d1bd99b9d3UL, 0x002847bfcda6503eUL) /* 1627 */
+P(10, 0xb62fda77ca343b6dUL, 0x002808c1ea6b4777UL) /* 1637 */
+P(20, 0x1f0dc009e34383c9UL, 0x00278d0e0f23ff61UL) /* 1657 */
+P( 6, 0x496dc21ddd35b97fUL, 0x002768863c093c7fUL) /* 1663 */
+P( 4, 0xb0e96ce17090f82bUL, 0x0027505115a73ca8UL) /* 1667 */
+P( 2, 0xaadf05acdd7d024dUL, 0x00274441a61dc1b9UL) /* 1669 */
+P(24, 0xcb138196746eafb5UL, 0x0026b5c166113cf0UL) /* 1693 */
+P( 4, 0x347f523736755d61UL, 0x00269e65ad07b18eUL) /* 1697 */
+P( 2, 0xd14a48a051f7dd0bUL, 0x002692c25f877560UL) /* 1699 */
+P(10, 0x474d71b1ce914d25UL, 0x002658fa7523cd11UL) /* 1709 */
+P(12, 0x386063f5e28c1f89UL, 0x0026148710cf0f9eUL) /* 1721 */
+P( 2, 0x1db7325e32d04e73UL, 0x002609363b22524fUL) /* 1723 */
+P(10, 0xfef748d3893b880dUL, 0x0025d1065a1c1122UL) /* 1733 */
+P( 8, 0x2f3351506e935605UL, 0x0025a48a382b863fUL) /* 1741 */
+P( 6, 0x7a3637fa2376415bUL, 0x0025837190eccdbcUL) /* 1747 */
+P( 6, 0x4ac525d2baa21969UL, 0x00256292e95d510cUL) /* 1753 */
+P( 6, 0x3a11c16b42cd351fUL, 0x002541eda98d068cUL) /* 1759 */
+P(18, 0x6c7abde0049c2a11UL, 0x0024e15087fed8f5UL) /* 1777 */
+P( 6, 0x54dad0303e069ac7UL, 0x0024c18b20979e5dUL) /* 1783 */
+P( 4, 0xebf1ac9fdfe91433UL, 0x0024ac7b336de0c5UL) /* 1787 */
+P( 2, 0xfafdda8237cec655UL, 0x0024a1fc478c60bbUL) /* 1789 */
+P(12, 0xdce3ff6e71ffb739UL, 0x002463801231c009UL) /* 1801 */
+P(10, 0xbed5737d6286db1bUL, 0x0024300fd506ed33UL) /* 1811 */
+P(12, 0xe479e431fe08b4dfUL, 0x0023f314a494da81UL) /* 1823 */
+P( 8, 0x9dd9b0dd7742f897UL, 0x0023cadedd2fad3aUL) /* 1831 */
+P(16, 0x8f09d7402c5a5e87UL, 0x00237b7ed2664a03UL) /* 1847 */
+P(14, 0x9216d5c4d958738dUL, 0x0023372967dbaf1dUL) /* 1861 */
+P( 6, 0xb3139ba11d34ca63UL, 0x00231a308a371f20UL) /* 1867 */
+P( 4, 0x47d54f7ed644afafUL, 0x002306fa63e1e600UL) /* 1871 */
+P( 2, 0x92a81d85cf11a1b1UL, 0x0022fd6731575684UL) /* 1873 */
+P( 4, 0x754b26533253bdfdUL, 0x0022ea507805749cUL) /* 1877 */
+P( 2, 0xbbe0efc980bfd467UL, 0x0022e0cce8b3d720UL) /* 1879 */
+P(10, 0xc0d8d594f024dca1UL, 0x0022b1887857d161UL) /* 1889 */
+P(12, 0x8238d43bcaac1a65UL, 0x00227977fcc49cc0UL) /* 1901 */
+P( 6, 0x27779c1fae6175bbUL, 0x00225db37b5e5f4fUL) /* 1907 */
+P( 6, 0xa746ca9af708b2c9UL, 0x0022421b91322ed6UL) /* 1913 */
+P(18, 0x93f3cd9f389be823UL, 0x0021f05b35f52102UL) /* 1931 */
+P( 2, 0x5cb4a4c04c489345UL, 0x0021e75de5c70d60UL) /* 1933 */
+P(16, 0xbf6047743e85b6b5UL, 0x0021a01d6c19be96UL) /* 1949 */
+P( 2, 0x61c147831563545fUL, 0x0021974a6615c81aUL) /* 1951 */
+P(22, 0xedb47c0ae62dee9dUL, 0x00213767697cf36aUL) /* 1973 */
+P( 6, 0x0a3824386673a573UL, 0x00211d9f7fad35f1UL) /* 1979 */
+P( 8, 0xa4a77d19e575a0ebUL, 0x0020fb7d9dd36c18UL) /* 1987 */
+P( 6, 0xa2bee045e066c279UL, 0x0020e2123d661e0eUL) /* 1993 */
+P( 4, 0xc23618de8ab43d05UL, 0x0020d135b66ae990UL) /* 1997 */
+P( 2, 0x266b515216cb9f2fUL, 0x0020c8cded4d7a8eUL) /* 1999 */
+P( 4, 0xe279edd9e9c2e85bUL, 0x0020b80b3f43ddbfUL) /* 2003 */
+P( 8, 0xd0c591c221dc9c53UL, 0x002096b9180f46a6UL) /* 2011 */
+P( 6, 0x06da8ee9c9ee7c21UL, 0x00207de7e28de5daUL) /* 2017 */
+P(10, 0x9dfebcaf4c27e8c3UL, 0x002054dec8cf1fb3UL) /* 2027 */
+P( 2, 0x49aeff9f19dd6de5UL, 0x00204cb630b3aab5UL) /* 2029 */
+P(10, 0x86976a57a296e9c7UL, 0x00202428adc37bebUL) /* 2039 */
+P(14, 0xa3b9abf4872b84cdUL, 0x001fec0c7834def4UL) /* 2053 */
+P(10, 0x34fca6483895e6efUL, 0x001fc46fae98a1d0UL) /* 2063 */
+P( 6, 0x34b5a333988f873dUL, 0x001facda430ff619UL) /* 2069 */
+P(12, 0xd9dd4f19b5f17be1UL, 0x001f7e17dd8e15e5UL) /* 2081 */
+P( 2, 0xb935b507fd0ce78bUL, 0x001f765a3556a4eeUL) /* 2083 */
+P( 4, 0xb450f5540660e797UL, 0x001f66ea49d802f1UL) /* 2087 */
+P( 2, 0x63ff82831ffc1419UL, 0x001f5f3800faf9c0UL) /* 2089 */
+P(10, 0x8992f718c22a32fbUL, 0x001f38f4e6c0f1f9UL) /* 2099 */
+P(12, 0x5f3253ad0d37e7bfUL, 0x001f0b8546752578UL) /* 2111 */
+P( 2, 0x007c0ffe0fc007c1UL, 0x001f03ff83f001f0UL) /* 2113 */
+P(16, 0x4d8ebadc0c0640b1UL, 0x001ec853b0a3883cUL) /* 2129 */
+P( 2, 0xe2729af831037bdbUL, 0x001ec0ee573723ebUL) /* 2131 */
+P( 6, 0xb8f64bf30feebfe9UL, 0x001eaad38e6f6894UL) /* 2137 */
+P( 4, 0xda93124b544c0bf5UL, 0x001e9c28a765fe53UL) /* 2141 */
+P( 2, 0x9cf7ff0b593c539fUL, 0x001e94d8758c2003UL) /* 2143 */
+P(10, 0xd6bd8861fa0e07d9UL, 0x001e707ba8f65e68UL) /* 2153 */
+P( 8, 0x5cfe75c0bd8ab891UL, 0x001e53a2a68f574eUL) /* 2161 */
+P(18, 0x43e808757c2e862bUL, 0x001e1380a56b438dUL) /* 2179 */
+P(24, 0x90caa96d595c9d93UL, 0x001dbf9f513a3802UL) /* 2203 */
+P( 4, 0x8fd550625d07135fUL, 0x001db1d1d58bc600UL) /* 2207 */
+P( 6, 0x76b010a86e209f2dUL, 0x001d9d358f53de38UL) /* 2213 */
+P( 8, 0xecc0426447769b25UL, 0x001d81e6df6165c7UL) /* 2221 */
+P(16, 0xe381339caabe3295UL, 0x001d4bdf7fd40e30UL) /* 2237 */
+P( 2, 0xd1b190a2d0c7673fUL, 0x001d452c7a1c958dUL) /* 2239 */
+P( 4, 0xc3bce3cf26b0e7ebUL, 0x001d37cf9b902659UL) /* 2243 */
+P( 8, 0x5f87e76f56c61ce3UL, 0x001d1d3a5791e97bUL) /* 2251 */
+P(16, 0xc06c6857a124b353UL, 0x001ce89fe6b47416UL) /* 2267 */
+P( 2, 0x38c040fcba630f75UL, 0x001ce219f3235071UL) /* 2269 */
+P( 4, 0xd078bc4fbd533b21UL, 0x001cd516dcf92139UL) /* 2273 */
+P( 8, 0xde8e15c5dd354f59UL, 0x001cbb33bd1c2b8bUL) /* 2281 */
+P( 6, 0xca61d53d7414260fUL, 0x001ca7e7d2546688UL) /* 2287 */
+P( 6, 0xb56bf5ba8eae635dUL, 0x001c94b5c1b3dbd3UL) /* 2293 */
+P( 4, 0x44a72cb0fb6e3949UL, 0x001c87f7f9c241c1UL) /* 2297 */
+P(12, 0x879839a714f45bcdUL, 0x001c6202706c35a9UL) /* 2309 */
+P( 2, 0x02a8994fde5314b7UL, 0x001c5bb8a9437632UL) /* 2311 */
+P(22, 0xb971920cf2b90135UL, 0x001c174343b4111eUL) /* 2333 */
+P( 6, 0x8a8fd0b7df9a6e8bUL, 0x001c04d0d3e46b42UL) /* 2339 */
+P( 2, 0xb31f9a84c1c6eaadUL, 0x001bfeb00fbf4308UL) /* 2341 */
+P( 6, 0x92293b02823c6d83UL, 0x001bec5dce0b202dUL) /* 2347 */
+P( 4, 0xeee77ff20fe5ddcfUL, 0x001be03444620037UL) /* 2351 */
+P( 6, 0x0e1ea0f6c496c11dUL, 0x001bce09c66f6fc3UL) /* 2357 */
+P(14, 0xfdf2d3d6f88ccb6bUL, 0x001ba40228d02b30UL) /* 2371 */
+P( 6, 0xfa9d74a3457738f9UL, 0x001b9225b1cf8919UL) /* 2377 */
+P( 4, 0xefc3ca3db71a5785UL, 0x001b864a2ff3f53fUL) /* 2381 */
+P( 2, 0x8e2071718d0d6dafUL, 0x001b80604150e49bUL) /* 2383 */
+P( 6, 0xbc0fdbfeb6cfabfdUL, 0x001b6eb1aaeaacf3UL) /* 2389 */
+P( 4, 0x1eeab613e5e5aee9UL, 0x001b62f48da3c8ccUL) /* 2393 */
+P( 6, 0x2d2388e90e9e929fUL, 0x001b516babe96092UL) /* 2399 */
+P(12, 0x81dbafba588ddb43UL, 0x001b2e9cef1e0c87UL) /* 2411 */
+P( 6, 0x52eebc51c4799791UL, 0x001b1d56bedc849bUL) /* 2417 */
+P( 6, 0x1c6bc4693b45a047UL, 0x001b0c267546aec0UL) /* 2423 */
+P(14, 0x06eee0974498874dUL, 0x001ae45f62024fa0UL) /* 2437 */
+P( 4, 0xd85b7377a9953cb9UL, 0x001ad917631b5f54UL) /* 2441 */
+P( 6, 0x4b6df412d4caf56fUL, 0x001ac83d18cb608fUL) /* 2447 */
+P(12, 0x6b8afbbb4a053493UL, 0x001aa6c7ad8c063fUL) /* 2459 */
+P( 8, 0xcc5299c96ac7720bUL, 0x001a90a7b1228e2aUL) /* 2467 */
+P( 6, 0xadce84b5c710aa99UL, 0x001a8027c03ba059UL) /* 2473 */
+P( 4, 0x9d673f5aa3804225UL, 0x001a7533289deb89UL) /* 2477 */
+P(26, 0xe6541268efbce7f7UL, 0x001a2ed7ce16b49fUL) /* 2503 */
+P(18, 0xfcf41e76cf5be669UL, 0x0019fefc0a279a73UL) /* 2521 */
+P(10, 0x5c3eb5dc31c383cbUL, 0x0019e4b0cd873b5fUL) /* 2531 */
+P( 8, 0x301832d11d8ad6c3UL, 0x0019cfcdfd60e514UL) /* 2539 */
+P( 4, 0x2e9c0942f1ce450fUL, 0x0019c56932d66c85UL) /* 2543 */
+P( 6, 0x97f3f2be37a39a5dUL, 0x0019b5e1ab6fc7c2UL) /* 2549 */
+P( 2, 0xe8b7d8a9654187c7UL, 0x0019b0b8a62f2a73UL) /* 2551 */
+P( 6, 0xb5d024d7da5b1b55UL, 0x0019a149fc98942cUL) /* 2557 */
+P(22, 0xb8ba9d6e7ae3501bUL, 0x001969517ec25b85UL) /* 2579 */
+P(12, 0xf50865f71b90f1dfUL, 0x00194b3083360ba8UL) /* 2591 */
+P( 2, 0x739c1682847df9e1UL, 0x00194631f4bebdc1UL) /* 2593 */
+P(16, 0xc470a4d842b90ed1UL, 0x00191e84127268fdUL) /* 2609 */
+P( 8, 0x1fb1be11698cc409UL, 0x00190adbb543984fUL) /* 2617 */
+P( 4, 0xd8d5512a7cd35d15UL, 0x001901130bd18200UL) /* 2621 */
+P(12, 0xa5496821723e07f9UL, 0x0018e3e6b889ac94UL) /* 2633 */
+P(14, 0xbcc8c6d7abaa8167UL, 0x0018c233420e1ec1UL) /* 2647 */
+P(10, 0x52c396c95eb619a1UL, 0x0018aa5872d92bd6UL) /* 2657 */
+P( 2, 0x6eb7e380878ec74bUL, 0x0018a5989945ccf9UL) /* 2659 */
+P( 4, 0x3d5513b504537157UL, 0x00189c1e60b57f60UL) /* 2663 */
+P( 8, 0x314391f8862e948fUL, 0x0018893fbc8690b9UL) /* 2671 */
+P( 6, 0xdc0b17cfcd81f5ddUL, 0x00187b2bb3e1041cUL) /* 2677 */
+P( 6, 0x2f6bea3ec89044b3UL, 0x00186d27c9cdcfb8UL) /* 2683 */
+P( 4, 0xce13a05869f1b57fUL, 0x001863d8bf4f2c1cUL) /* 2687 */
+P( 2, 0x7593474e8ace3581UL, 0x00185f33e2ad7593UL) /* 2689 */
+P( 4, 0x07fc329295a05e4dUL, 0x001855ef75973e13UL) /* 2693 */
+P( 6, 0xb05377cba4908d23UL, 0x001848160153f134UL) /* 2699 */
+P( 8, 0xe7b2131a628aa39bUL, 0x001835b72e6f0656UL) /* 2707 */
+P( 4, 0x9031dbed7de01527UL, 0x00182c922d83eb39UL) /* 2711 */
+P( 2, 0x76844b1c670aa9a9UL, 0x0018280243c0365aUL) /* 2713 */
+P( 6, 0x6a03f4533b08915fUL, 0x00181a5cd5898e73UL) /* 2719 */
+P(10, 0x1dbca579db0a3999UL, 0x001803c0961773aaUL) /* 2729 */
+P( 2, 0x002ffe800bffa003UL, 0x0017ff4005ffd001UL) /* 2731 */
+P(10, 0x478ab1a3e936139dUL, 0x0017e8d670433edbUL) /* 2741 */
+P( 8, 0x66e722bc4c5cc095UL, 0x0017d7066cf4bb5dUL) /* 2749 */
+P( 4, 0x7a8f63c717278541UL, 0x0017ce285b806b1fUL) /* 2753 */
+P(14, 0xdf6eee24d292bc2fUL, 0x0017af52cdf27e02UL) /* 2767 */
+P(10, 0x9fc20d17237dd569UL, 0x0017997d47d01039UL) /* 2777 */
+P(12, 0xcdf9932356bda2edUL, 0x00177f7ec2c6d0baUL) /* 2789 */
+P( 2, 0x97b5e332e80f68d7UL, 0x00177b2f3cd00756UL) /* 2791 */
+P( 6, 0x46eee26fd875e2e5UL, 0x00176e4a22f692a0UL) /* 2797 */
+P( 4, 0x3548a8e65157a611UL, 0x001765b94271e11bUL) /* 2801 */
+P( 2, 0xc288d03be9b71e3bUL, 0x001761732b044ae4UL) /* 2803 */
+P(16, 0x8151186db38937abUL, 0x00173f7a5300a2bcUL) /* 2819 */
+P(14, 0x7800b910895a45f1UL, 0x001722112b48be1fUL) /* 2833 */
+P( 4, 0xaee0b024182eec3dUL, 0x001719b7a16eb843UL) /* 2837 */
+P( 6, 0x96323eda173b5713UL, 0x00170d3c99cc5052UL) /* 2843 */
+P( 8, 0x0ed0dbd03ae77c8bUL, 0x0016fcad7aed3bb6UL) /* 2851 */
+P( 6, 0xf73800b7828dc119UL, 0x0016f051b8231ffdUL) /* 2857 */
+P( 4, 0x1b61715ec22b7ca5UL, 0x0016e81beae20643UL) /* 2861 */
+P(18, 0xa8533a991ead64bfUL, 0x0016c3721584c1d8UL) /* 2879 */
+P( 8, 0x7f6c7290e46c2e77UL, 0x0016b34c2ba09663UL) /* 2887 */
+P(10, 0x6325e8d907b01db1UL, 0x00169f3ce292ddcdUL) /* 2897 */
+P( 6, 0x28909f70152a1067UL, 0x00169344b2220a0dUL) /* 2903 */
+P( 6, 0xea7077af0997a0f5UL, 0x001687592593c1b1UL) /* 2909 */
+P( 8, 0x7e605cad10c32e6dUL, 0x00167787f1418ec9UL) /* 2917 */
+P(10, 0x471b33570635b38fUL, 0x001663e190395ff2UL) /* 2927 */
+P(12, 0xab559fa997a61bb3UL, 0x00164c7a4b6eb5b3UL) /* 2939 */
+P(14, 0xad4bdae562bddab9UL, 0x0016316a061182fdUL) /* 2953 */
+P( 4, 0x055e1b2f2ed62f45UL, 0x001629ba914584e4UL) /* 2957 */
+P( 6, 0x03cd328b1a2dca9bUL, 0x00161e3d57de21b2UL) /* 2963 */
+P( 6, 0xd28f4e08733218a9UL, 0x001612cc01b977f0UL) /* 2969 */
+P( 2, 0xb6800b077f186293UL, 0x00160efe30c525ffUL) /* 2971 */
+P(28, 0x6fbd138c3fd9c207UL, 0x0015da45249ec5deUL) /* 2999 */
+P( 2, 0xb117ccd12ae88a89UL, 0x0015d68ab4acff92UL) /* 3001 */
+P(10, 0x2f1a1a044046bcebUL, 0x0015c3f989d1eb15UL) /* 3011 */
+P( 8, 0x548aba0b060541e3UL, 0x0015b535ad11b8f0UL) /* 3019 */
+P( 4, 0xcf4e808cea111b2fUL, 0x0015addb3f424ec1UL) /* 3023 */
+P(14, 0xdbec1b4fa855a475UL, 0x00159445cb91be6bUL) /* 3037 */
+P( 4, 0xe3f794eb600d7821UL, 0x00158d0199771e63UL) /* 3041 */
+P( 8, 0x34fae0d9a11f7c59UL, 0x00157e87d9b69e04UL) /* 3049 */
+P(12, 0xf006b0ccbbac085dUL, 0x001568f58bc01ac3UL) /* 3061 */
+P( 6, 0x3f45076dc3114733UL, 0x00155e3c993fda9bUL) /* 3067 */
+P(12, 0xeef49bfa58a1a1b7UL, 0x001548eacc5e1e6eUL) /* 3079 */
+P( 4, 0x12c4218bea691fa3UL, 0x001541d8f91ba6a7UL) /* 3083 */
+P( 6, 0xbc7504e3bd5e64f1UL, 0x00153747060cc340UL) /* 3089 */
+P(20, 0x4ee21c292bb92fadUL, 0x001514569f93f7c4UL) /* 3109 */
+P(10, 0x34338b7327a4bacfUL, 0x00150309705d3d79UL) /* 3119 */
+P( 2, 0x3fe5c0833d6fccd1UL, 0x0014ff97020cf5bfUL) /* 3121 */
+P(16, 0xb1e70743535203c1UL, 0x0014e42c114cf47eUL) /* 3137 */
+P(26, 0xefbb5dcdfb4e43d3UL, 0x0014b835bdcb6447UL) /* 3163 */
+P( 4, 0xca68467ca5394f9fUL, 0x0014b182b53a9ab7UL) /* 3167 */
+P( 2, 0x8c51c081408b97a1UL, 0x0014ae2ad094a3d3UL) /* 3169 */
+P(12, 0x3275a899dfa5dd65UL, 0x00149a320ea59f96UL) /* 3181 */
+P( 6, 0x9e674cb62e1b78bbUL, 0x001490441de1a2fbUL) /* 3187 */
+P( 4, 0xa37ff5bb2a998d47UL, 0x001489aacce57200UL) /* 3191 */
+P(12, 0x792a999db131a22bUL, 0x001475f82ad6ff99UL) /* 3203 */
+P( 6, 0x1b48841bc30d29b9UL, 0x00146c2cfe53204fUL) /* 3209 */
+P( 8, 0xf06721d2011d3471UL, 0x00145f2ca490d4a1UL) /* 3217 */
+P( 4, 0x93fd2386dff85ebdUL, 0x001458b2aae0ec87UL) /* 3221 */
+P( 8, 0x4ce72f54c07ed9b5UL, 0x00144bcb0a3a3150UL) /* 3229 */
+P(22, 0xd6d0fd3e71dd827bUL, 0x001428a1e65441d4UL) /* 3251 */
+P( 2, 0x856405fb1eed819dUL, 0x00142575a6c210d7UL) /* 3253 */
+P( 4, 0x8ea8aceb7c443989UL, 0x00141f2025ba5c46UL) /* 3257 */
+P( 2, 0x34a13026f62e5873UL, 0x00141bf6e35420fdUL) /* 3259 */
+P(12, 0x1eea0208ec0af4f7UL, 0x001409141d1d313aUL) /* 3271 */
+P(28, 0x63679853cea598cbUL, 0x0013dd8bc19c3513UL) /* 3299 */
+P( 2, 0xc30b3ebd61f2d0edUL, 0x0013da76f714dc8fUL) /* 3301 */
+P( 6, 0x7eb9037bc7f43bc3UL, 0x0013d13e50f8f49eUL) /* 3307 */
+P( 6, 0xa583e6f6ce016411UL, 0x0013c80e37ca3819UL) /* 3313 */
+P( 6, 0xf1938d895f1a74c7UL, 0x0013bee69fa99ccfUL) /* 3319 */
+P( 4, 0x80cf1491c1e81e33UL, 0x0013b8d0ede55835UL) /* 3323 */
+P( 6, 0x3c0f12886ba8f301UL, 0x0013afb7680bb054UL) /* 3329 */
+P( 2, 0x0e4b786e0dfcc5abUL, 0x0013acb0c3841c96UL) /* 3331 */
+P(12, 0x672684c93f2d41efUL, 0x00139a9c5f434fdeUL) /* 3343 */
+P( 4, 0xe00757badb35c51bUL, 0x0013949cf33a0d9dUL) /* 3347 */
+P(12, 0xd6d84afe66472edfUL, 0x001382b4a00c31b0UL) /* 3359 */
+P( 2, 0xfbbc0eedcbbfb6e1UL, 0x00137fbbc0eedcbbUL) /* 3361 */
+P(10, 0x250f43aa08a84983UL, 0x001370ecf047b069UL) /* 3371 */
+P( 2, 0x04400e927b1acaa5UL, 0x00136df9790e3155UL) /* 3373 */
+P(16, 0x56572be34b9d3215UL, 0x0013567dd8defd5bUL) /* 3389 */
+P( 2, 0x87964ef7781c62bfUL, 0x0013539261fdbc34UL) /* 3391 */
+P(16, 0x29ed84051c06e9afUL, 0x00133c564292d28aUL) /* 3407 */
+P( 6, 0xb00acd11ed3f87fdUL, 0x001333ae178d6388UL) /* 3413 */
+P(20, 0x06307881744152d9UL, 0x0013170ad00d1fd7UL) /* 3433 */
+P(16, 0x7a786459f5c1ccc9UL, 0x0013005f01db0947UL) /* 3449 */
+P( 8, 0x1308125d74563281UL, 0x0012f51d40342210UL) /* 3457 */
+P( 4, 0x395310a480b3e34dUL, 0x0012ef815e4ed950UL) /* 3461 */
+P( 2, 0x35985baa8b202837UL, 0x0012ecb4abccd827UL) /* 3463 */
+P( 4, 0x96304a6e052b3223UL, 0x0012e71dc1d3d820UL) /* 3467 */
+P( 2, 0xbd8265fc9af8fd45UL, 0x0012e45389a16495UL) /* 3469 */
+P(22, 0x1b6d0b383ec58e0bUL, 0x0012c5d9226476ccUL) /* 3491 */
+P( 8, 0xc21a7c3b68b28503UL, 0x0012badc391156fdUL) /* 3499 */
+P(12, 0x236fa180fbfd6007UL, 0x0012aa78e412f522UL) /* 3511 */
+P( 6, 0xc42accd440ed9595UL, 0x0012a251f5f47fd1UL) /* 3517 */
+P(10, 0x7acf7128236ba3f7UL, 0x001294cb85c53534UL) /* 3527 */
+P( 2, 0xf909367a987b9c79UL, 0x0012921963beb65eUL) /* 3529 */
+P( 4, 0xb64efb252bfba705UL, 0x00128cb777c69ca8UL) /* 3533 */
+P( 6, 0x980d4f5a7e4cd25bUL, 0x001284aa6cf07294UL) /* 3539 */
+P( 2, 0xe1ecc4ef27b0c37dUL, 0x001281fcf6ac7f87UL) /* 3541 */
+P( 6, 0x9111aebb81d72653UL, 0x001279f937367db9UL) /* 3547 */
+P(10, 0x8951f985cb2c67edUL, 0x00126cad0488be94UL) /* 3557 */
+P( 2, 0xc439d4fc54e0b5d7UL, 0x00126a06794646a2UL) /* 3559 */
+P(12, 0xe857bf31896d533bUL, 0x00125a2f2bcd3e95UL) /* 3571 */
+P(10, 0xb614bb4cb5023755UL, 0x00124d108389e6b1UL) /* 3581 */
+P( 2, 0x938a89e5473bf1ffUL, 0x00124a73083771acUL) /* 3583 */
+P(10, 0xeac481aca34de039UL, 0x00123d6acda0620aUL) /* 3593 */
+P(14, 0x14b961badf4809a7UL, 0x00122b4b2917eafdUL) /* 3607 */
+P( 6, 0x76784fecba352435UL, 0x00122391bfce1e2fUL) /* 3613 */
+P( 4, 0xefa689bb58aef5e1UL, 0x00121e6f1ea579f2UL) /* 3617 */
+P( 6, 0xb2b2c4db9c3a8197UL, 0x001216c09e471568UL) /* 3623 */
+P( 8, 0x2503bc992279f8cfUL, 0x00120c8cb9d93909UL) /* 3631 */
+P( 6, 0xd2ab9aec5ca1541dUL, 0x001204ed58e64ef9UL) /* 3637 */
+P( 6, 0x3e78ba1460f99af3UL, 0x0011fd546578f00cUL) /* 3643 */
+P(16, 0x0a01426572cfcb63UL, 0x0011e9310b8b4c9cUL) /* 3659 */
+P(12, 0xbea857968f3cbd67UL, 0x0011da3405db9911UL) /* 3671 */
+P( 2, 0x78db213eefe659e9UL, 0x0011d7b6f4eb055dUL) /* 3673 */
+P( 4, 0x963e8541a74d35f5UL, 0x0011d2bee748c145UL) /* 3677 */
+P(14, 0x9e22d152776f2e43UL, 0x0011c1706ddce7a7UL) /* 3691 */
+P( 6, 0x05d10d39d1e1f291UL, 0x0011ba0fed2a4f14UL) /* 3697 */
+P( 4, 0x374468dccaced1ddUL, 0x0011b528538ed64aUL) /* 3701 */
+P( 8, 0x8d145c7d110c5ad5UL, 0x0011ab61404242acUL) /* 3709 */
+P(10, 0x3251a39f5acb5737UL, 0x00119f378ce81d2fUL) /* 3719 */
+P( 8, 0xa66e50171443506fUL, 0x001195889ece79daUL) /* 3727 */
+P( 6, 0x124f69ad91dd4cbdUL, 0x00118e4c65387077UL) /* 3733 */
+P( 6, 0xec24f8f2a61a2793UL, 0x001187161d70e725UL) /* 3739 */
+P(22, 0xb472148e656b7a51UL, 0x00116cd6d1c85239UL) /* 3761 */
+P( 6, 0x0adf9570e1142f07UL, 0x001165bbe7ce86b1UL) /* 3767 */
+P( 2, 0x89bf33b065119789UL, 0x0011635ee344ce36UL) /* 3769 */
+P(10, 0x8f0149803cb291ebUL, 0x0011579767b6d679UL) /* 3779 */
+P(14, 0x8334b63afd190a31UL, 0x00114734711e2b54UL) /* 3793 */
+P( 4, 0x920908d50d6aba7dUL, 0x0011428b90147f05UL) /* 3797 */
+P( 6, 0x57d8b018c5a33d53UL, 0x00113b92f3021636UL) /* 3803 */
+P(18, 0xea1773092dc27ee5UL, 0x001126cabc886884UL) /* 3821 */
+P( 2, 0xcae5f38b7bf2e00fUL, 0x0011247eb1b85976UL) /* 3823 */
+P(10, 0x2bd02df34f695349UL, 0x0011190bb01efd65UL) /* 3833 */
+P(14, 0xddfecd5be62e2eb7UL, 0x0011091de0fd679cUL) /* 3847 */
+P( 4, 0xdbf849ebec96c4a3UL, 0x001104963c7e4e0bUL) /* 3851 */
+P( 2, 0xda31d4d0187357c5UL, 0x00110253516420b0UL) /* 3853 */
+P(10, 0xe34e21cc2d5418a7UL, 0x0010f70db7c41797UL) /* 3863 */
+P(14, 0x68ca5137a9e574adUL, 0x0010e75ee2bf9ecdUL) /* 3877 */
+P( 4, 0x3eaa0d0f804bfd19UL, 0x0010e2e91c6e0676UL) /* 3881 */
+P( 8, 0x554fb753cc20e9d1UL, 0x0010da049b9d428dUL) /* 3889 */
+P(18, 0x797afcca1300756bUL, 0x0010c6248fe3b1a2UL) /* 3907 */
+P( 4, 0x8b8d950b52eeea77UL, 0x0010c1c03ed690ebUL) /* 3911 */
+P( 6, 0xfb6cd166acabc185UL, 0x0010bb2e1379e3a2UL) /* 3917 */
+P( 2, 0x4eb6c5ed9437a7afUL, 0x0010b8fe7f61228eUL) /* 3919 */
+P( 4, 0xd1eddbd91b790cdbUL, 0x0010b4a10d60a4f7UL) /* 3923 */
+P( 6, 0x93d714ea4d8948e9UL, 0x0010ae192681ec0fUL) /* 3929 */
+P( 2, 0x3ca13ed8145188d3UL, 0x0010abecfbe5b0aeUL) /* 3931 */
+P(12, 0x829086016da89c57UL, 0x00109eefd568b96dUL) /* 3943 */
+P( 4, 0xd7da1f432124a543UL, 0x00109a9ff178b40cUL) /* 3947 */
+P(20, 0x7ead5581632fb07fUL, 0x00108531e22f9ff9UL) /* 3967 */
+P(22, 0x35443837f63ec3bdUL, 0x00106ddec1af4417UL) /* 3989 */
+
+#undef FIRST_OMITTED_PRIME
+#define FIRST_OMITTED_PRIME 4001
diff --git a/third_party/gmp/demos/qcn.c b/third_party/gmp/demos/qcn.c
new file mode 100644
index 0000000..9d76446
--- /dev/null
+++ b/third_party/gmp/demos/qcn.c
@@ -0,0 +1,172 @@
+/* Use mpz_kronecker_ui() to calculate an estimate for the quadratic
+   class number h(d), for a given negative fundamental discriminant, using
+   Dirichlet's analytic formula.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3 of the License, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: qcn [-p limit] <discriminant>...
+
+   A fundamental discriminant means one of the form D or 4*D with D
+   square-free.  Each argument is checked to see it's congruent to 0 or 1
+   mod 4 (as all discriminants must be), and that it's negative, but there's
+   no check on D being square-free.
+
+   This program is a bit of a toy, there are better methods for calculating
+   the class number and class group structure.
+
+   Reference:
+
+   Daniel Shanks, "Class Number, A Theory of Factorization, and Genera",
+   Proc. Symp. Pure Math., vol 20, 1970, pages 415-440.
+
+*/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp.h"
+
+#ifndef M_PI
+#define M_PI  3.14159265358979323846
+#endif
+
+
+/* A simple but slow primality test.  */
+int
+prime_p (unsigned long n)
+{
+  unsigned long  i, limit;
+
+  if (n == 2)
+    return 1;
+  if (n < 2 || !(n&1))
+    return 0;
+
+  limit = (unsigned long) floor (sqrt ((double) n));
+  for (i = 3; i <= limit; i+=2)
+    if ((n % i) == 0)
+      return 0;
+
+  return 1;
+}
+
+
+/* The formula is as follows, with d < 0.
+
+	       w * sqrt(-d)      inf      p
+	h(d) = ------------ *  product --------
+		  2 * pi         p=2   p - (d/p)
+
+
+   (d/p) is the Kronecker symbol and the product is over primes p.  w is 6
+   when d=-3, 4 when d=-4, or 2 otherwise.
+
+   Calculating the product up to p=infinity would take a long time, so for
+   the estimate primes up to 132,000 are used.  Shanks found this giving an
+   accuracy of about 1 part in 1000, in normal cases.  */
+
+unsigned long  p_limit = 132000;
+
+double
+qcn_estimate (mpz_t d)
+{
+  double  h;
+  unsigned long  p;
+
+  /* p=2 */
+  h = sqrt (-mpz_get_d (d)) / M_PI
+    * 2.0 / (2.0 - mpz_kronecker_ui (d, 2));
+
+  if (mpz_cmp_si (d, -3) == 0)       h *= 3;
+  else if (mpz_cmp_si (d, -4) == 0)  h *= 2;
+
+  for (p = 3; p <= p_limit; p += 2)
+    if (prime_p (p))
+      h *= (double) p / (double) (p - mpz_kronecker_ui (d, p));
+
+  return h;
+}
+
+
+void
+qcn_str (char *num)
+{
+  mpz_t  z;
+
+  mpz_init_set_str (z, num, 0);
+
+  if (mpz_sgn (z) >= 0)
+    {
+      mpz_out_str (stdout, 0, z);
+      printf (" is not supported (negatives only)\n");
+    }
+  else if (mpz_fdiv_ui (z, 4) != 0 && mpz_fdiv_ui (z, 4) != 1)
+    {
+      mpz_out_str (stdout, 0, z);
+      printf (" is not a discriminant (must == 0 or 1 mod 4)\n");
+    }
+  else
+    {
+      printf ("h(");
+      mpz_out_str (stdout, 0, z);
+      printf (") approx %.1f\n", qcn_estimate (z));
+    }
+  mpz_clear (z);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int  i;
+  int  saw_number = 0;
+
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "-p") == 0)
+	{
+	  i++;
+	  if (i >= argc)
+	    {
+	      fprintf (stderr, "Missing argument to -p\n");
+	      exit (1);
+	    }
+	  p_limit = atoi (argv[i]);
+	}
+      else
+	{
+	  qcn_str (argv[i]);
+	  saw_number = 1;
+	}
+    }
+
+  if (! saw_number)
+    {
+      /* some default output */
+      qcn_str ("-85702502803");           /* is 16259   */
+      qcn_str ("-328878692999");          /* is 1499699 */
+      qcn_str ("-928185925902146563");    /* is 52739552 */
+      qcn_str ("-84148631888752647283");  /* is 496652272 */
+      return 0;
+    }
+
+  return 0;
+}