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/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);
+}