Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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:

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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);
}