Merge pull request #59 from louisrubet/mpfr

Mpfr
This commit is contained in:
Louis Rubet 2017-05-20 22:55:09 +02:00 committed by GitHub
commit ddd499873b
34 changed files with 1955 additions and 1434 deletions

View file

@ -16,6 +16,7 @@ rpn_SOURCES = src/rpn.cpp \
src/rpn-trig.h \
src/stack.h
rpn_LDFLAGS = -Wl,--no-as-needed -lreadline
rpn_CFLAGS = -g
rpn_LDFLAGS = -Wl,--no-as-needed -lreadline -lmpfr
dist_noinst_SCRIPTS = autogen.sh

View file

@ -1,7 +1,7 @@
# Makefile.in generated by automake 1.14.1 from Makefile.am.
# Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# 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,
@ -16,7 +16,17 @@
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
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 \
?) ;; \
@ -79,15 +89,13 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
bin_PROGRAMS = rpn$(EXEEXT)
subdir = .
DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \
$(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/configure $(am__configure_deps) \
$(srcdir)/config.h.in $(dist_noinst_SCRIPTS) depcomp COPYING \
TODO install-sh missing
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
$(am__configure_deps) $(dist_noinst_SCRIPTS) \
$(am__DIST_COMMON)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
@ -173,6 +181,9 @@ ETAGS = etags
CTAGS = ctags
CSCOPE = cscope
AM_RECURSIVE_TARGETS = cscope
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in AUTHORS \
COPYING ChangeLog INSTALL NEWS README TODO depcomp install-sh \
missing
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
@ -266,6 +277,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@ -289,7 +301,8 @@ rpn_SOURCES = src/rpn.cpp \
src/rpn-trig.h \
src/stack.h
rpn_LDFLAGS = -Wl,--no-as-needed -lreadline
rpn_CFLAGS = -g
rpn_LDFLAGS = -Wl,--no-as-needed -lreadline -lmpfr
dist_noinst_SCRIPTS = autogen.sh
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
@ -311,7 +324,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@ -539,15 +551,15 @@ dist-xz: distdir
$(am__post_remove_distdir)
dist-tarZ: distdir
@echo WARNING: "Support for shar distribution archives is" \
"deprecated." >&2
@echo WARNING: "Support for distribution archives compressed with" \
"legacy program 'compress' is deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__post_remove_distdir)
dist-shar: distdir
@echo WARNING: "Support for distribution archives compressed with" \
"legacy program 'compress' is deprecated." >&2
@echo WARNING: "Support for shar distribution archives is" \
"deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__post_remove_distdir)
@ -583,17 +595,17 @@ distcheck: dist
esac
chmod -R a-w $(distdir)
chmod u+w $(distdir)
mkdir $(distdir)/_build $(distdir)/_inst
mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
chmod a-w $(distdir)
test -d $(distdir)/_build || exit 0; \
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& am__cwd=`pwd` \
&& $(am__cd) $(distdir)/_build \
&& ../configure \
&& $(am__cd) $(distdir)/_build/sub \
&& ../../configure \
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
$(DISTCHECK_CONFIGURE_FLAGS) \
--srcdir=.. --prefix="$$dc_install_base" \
--srcdir=../.. --prefix="$$dc_install_base" \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
@ -776,6 +788,8 @@ uninstall-am: uninstall-binPROGRAMS
mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am uninstall-binPROGRAMS
.PRECIOUS: Makefile
# 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.

0
README Normal file
View file

View file

@ -10,16 +10,20 @@
- The special feature of this language is to make no difference between
keywords and functions, even user functions.
- Numbers (ie scalars) are in 128-bit quadruple precision format (long
double). Binaries are 64-bits longwords format (long long int).
- A GNU-readline-based interactive editor with autocompletion is provided.
- Language extensions will soon be included:
- file objects and functions,
- date and time objects and functions,
- shell-calling objects with return code, stdout and stderr treatment,
- loading and saving stack, variables, programs from / to filesystem
- file objects and functions,
- date and time objects and functions,
- shell-calling objects with return code, stdout and stderr treatment,
- loading and saving stack, variables, programs from / to filesystem
Multiple-precision floating-point computations with correct rounding are ensured by __MPFR library__ under GNU LGPL v3 or later
Integer calculations are ensured by __GNU MP library__ (__GMP__) under GNU LGPL v3 and GNU GPL v2
## Implemented commands
@ -30,7 +34,6 @@ This commands list match HP28s reserved words. Commands marked as 'new' do not e
| GENERAL | nop |yes| yes| yes|
| GENERAL | help/h/? | yes | yes| |
| GENERAL | quit/exit/q| yes| yes| |
| GENERAL | test | yes | yes| |
| GENERAL | verbose | yes | yes| |
| GENERAL | std | | yes| |
| GENERAL | fix | | yes| |
@ -38,6 +41,9 @@ This commands list match HP28s reserved words. Commands marked as 'new' do not e
| GENERAL | version | yes | yes| |
| GENERAL | uname | yes | yes| |
| GENERAL | edit | | yes| |
| GENERAL | type | yes | yes| yes |
| GENERAL | default | yes | yes| yes |
| TEST | test | yes | yes| yes |
| REAL | + | | yes| |
| REAL | - | | yes| |
| REAL | neg | | yes| |
@ -47,8 +53,10 @@ This commands list match HP28s reserved words. Commands marked as 'new' do not e
| REAL | % | | yes| |
| REAL | %CH | | yes| |
| REAL | ^ | | yes| |
| REAL | pow (_alias for_ ^) | | yes| yes |
| REAL | sqrt | yes | yes| |
| REAL | sq | yes | yes| |
| REAL | sqr (_alias for_ sq) | yes | yes| yes |
| REAL | mod |yes| yes| |
| STACK | drop | | yes| |
| STACK | swap | | yes| |
@ -202,7 +210,7 @@ This commands list match HP28s reserved words. Commands marked as 'new' do not e
| LOGS | tanh | | yes | |
| LOGS | atanh | | yes | | |
## HP28s commands which won't be implemented
## HP28s commands which are not (or won't be) implemented
**MEMORY**
mem, menu, order, path, home, crdir, clusr,
@ -237,6 +245,39 @@ This commands list match HP28s reserved words. Commands marked as 'new' do not e
**CUSTOM**
menu, custom
## Tests
Unit tests are given as txt files in the test subdirectory.
Use the command 'test' to run a test file, eg
```
# cd test_directory/
# rpn
rpn> "entry.txt"
rpn> test
## ENTRY TEST
# real decimal PASSED
# real hex PASSED
# real binary PASSED
(...)
```
or
```
# cd test_directory/
# rpn \"entry.txt\" test
## ENTRY TEST
# real decimal PASSED
# real hex PASSED
# real binary PASSED
(...)
```
The test output is done on stdout and is not stacked in rpn.
| __test sheet__ | __description__ |
| - | - |
| entry.txt | testing real, binary, symbol, string and program entries |
## Notes
Compiled with g++ Makefile generated by automake.
External dependencies needed: automake, readline (libreadline-dev)
External dependencies needed: automake, readline (libreadline-dev), MPFR library, GNU MP library

58
aclocal.m4 vendored
View file

@ -1,6 +1,6 @@
# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
# generated automatically by aclocal 1.15 -*- Autoconf -*-
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -20,7 +20,7 @@ You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
# Copyright (C) 2002-2013 Free Software Foundation, Inc.
# Copyright (C) 2002-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -32,10 +32,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.])
# generated from the m4 files accompanying Automake X.Y.
# (This private macro should not be called outside this file.)
AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.14'
[am__api_version='1.15'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
m4_if([$1], [1.14.1], [],
m4_if([$1], [1.15], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@ -51,14 +51,14 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
[AM_AUTOMAKE_VERSION([1.14.1])dnl
[AM_AUTOMAKE_VERSION([1.15])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -103,15 +103,14 @@ _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# configured tree to be moved without reconfiguration.
AC_DEFUN([AM_AUX_DIR_EXPAND],
[dnl Rely on autoconf to set up CDPATH properly.
AC_PREREQ([2.50])dnl
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
# Expand $ac_aux_dir to an absolute path.
am_aux_dir=`cd "$ac_aux_dir" && pwd`
])
# AM_CONDITIONAL -*- Autoconf -*-
# Copyright (C) 1997-2013 Free Software Foundation, Inc.
# Copyright (C) 1997-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -142,7 +141,7 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]])
fi])])
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -333,7 +332,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
# Generate code to set up dependency tracking. -*- Autoconf -*-
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -409,7 +408,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
# Do all the work for Automake. -*- Autoconf -*-
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -499,8 +498,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
# We need awk for the "check" target. The system "awk" is bad on
# some platforms.
# We need awk for the "check" target (and possibly the TAP driver). The
# system "awk" is bad on some platforms.
AC_REQUIRE([AC_PROG_AWK])dnl
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
@ -574,6 +573,9 @@ END
AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
fi
fi
dnl The trailing newline in this macro's definition is deliberate, for
dnl backward compatibility and to allow trailing 'dnl'-style comments
dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
])
dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
@ -603,7 +605,7 @@ for _am_header in $config_headers :; do
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -614,7 +616,7 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co
# Define $install_sh.
AC_DEFUN([AM_PROG_INSTALL_SH],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
if test x"${install_sh}" != xset; then
if test x"${install_sh+set}" != xset; then
case $am_aux_dir in
*\ * | *\ *)
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@ -624,7 +626,7 @@ if test x"${install_sh}" != xset; then
fi
AC_SUBST([install_sh])])
# Copyright (C) 2003-2013 Free Software Foundation, Inc.
# Copyright (C) 2003-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -645,7 +647,7 @@ AC_SUBST([am__leading_dot])])
# Check to see how 'make' treats includes. -*- Autoconf -*-
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -695,7 +697,7 @@ rm -f confinc confmf
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
# Copyright (C) 1997-2013 Free Software Foundation, Inc.
# Copyright (C) 1997-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -734,7 +736,7 @@ fi
# Helper functions for option handling. -*- Autoconf -*-
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -765,7 +767,7 @@ AC_DEFUN([_AM_IF_OPTION],
# Check to make sure that the build environment is sane. -*- Autoconf -*-
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -846,7 +848,7 @@ AC_CONFIG_COMMANDS_PRE(
rm -f conftest.file
])
# Copyright (C) 2009-2013 Free Software Foundation, Inc.
# Copyright (C) 2009-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -906,7 +908,7 @@ AC_SUBST([AM_BACKSLASH])dnl
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
])
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -934,7 +936,7 @@ fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
# Copyright (C) 2006-2013 Free Software Foundation, Inc.
# Copyright (C) 2006-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -953,7 +955,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
# Copyright (C) 2004-2013 Free Software Foundation, Inc.
# Copyright (C) 2004-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,

26
configure vendored
View file

@ -651,6 +651,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@ -723,6 +724,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@ -975,6 +977,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1112,7 +1123,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@ -1265,6 +1276,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -1786,7 +1798,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
am__api_version='1.14'
am__api_version='1.15'
ac_aux_dir=
for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
@ -1987,8 +1999,8 @@ test "$program_suffix" != NONE &&
ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
# Expand $ac_aux_dir to an absolute path.
am_aux_dir=`cd "$ac_aux_dir" && pwd`
if test x"${MISSING+set}" != xset; then
case $am_aux_dir in
@ -2007,7 +2019,7 @@ else
$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
fi
if test x"${install_sh}" != xset; then
if test x"${install_sh+set}" != xset; then
case $am_aux_dir in
*\ * | *\ *)
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@ -2326,8 +2338,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
mkdir_p='$(MKDIR_P)'
# We need awk for the "check" target. The system "awk" is bad on
# some platforms.
# We need awk for the "check" target (and possibly the TAP driver). The
# system "awk" is bad on some platforms.
# Always define AMTAR for backward compatibility. Yes, it's still used
# in the wild :-( We should find a proper way to deprecate it ...
AMTAR='$${TAR-tar}'

View file

@ -3,7 +3,7 @@
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-11-20.07; # UTC
scriptversion=2014-09-12.12; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" "" $nl"
IFS=" $tab$nl"
# set DOITPROG to echo to test this script
# Set DOITPROG to "echo" to test this script.
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
@ -68,17 +64,6 @@ mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
@ -97,7 +82,7 @@ dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@ -137,46 +122,57 @@ while test $# -ne 0; do
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
shift;;
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
@ -207,6 +203,15 @@ if test $# -eq 0; then
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
@ -223,16 +228,16 @@ if test -z "$dir_arg"; then
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw='% 200'
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw=,u+rw
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
@ -269,41 +274,15 @@ do
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
@ -314,74 +293,81 @@ do
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
# $RANDOM is not portable (e.g. dash); use it when possible to
# lower collision chance
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
# As "mkdir -p" follows symlinks and we work in /tmp possibly; so
# create the $tmpdir first (and fail if unsuccessful) to make sure
# that nobody tries to guess the $tmpdir name.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
@ -391,53 +377,51 @@ do
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set -f
set fnord $dstdir
shift
$posix_glob set +f
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
@ -472,15 +456,12 @@ do
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
@ -493,24 +474,24 @@ do
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1

View file

@ -3,7 +3,7 @@
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify

View file

@ -39,3 +39,7 @@ static void dump8(unsigned char* to_dump, unsigned long offset,
}
printf("\n");
}
//
#define TRACE(x) cout<<__FUNCTION__<<": "<<(x)<<endl;
#define TRACE2(x, y) cout<<__FUNCTION__<<": "<<(x)<<(y)<<endl;

View file

@ -27,7 +27,6 @@ static ret_value get_fn(const char* fn_name, program_fn_t& fn, cmd_type_t& type)
static bool _cut(const char* entry, vector<string>& entries)
{
string tmp;
//TODO borner
int len = strlen(entry);
for (int i=0; i < len; i++)
@ -168,9 +167,11 @@ static bool _cut(const char* entry, vector<string>& entries)
return entries.size()>0;
}
static bool get_keyword(const string& entry, object*& obj, unsigned int& obj_size, cmd_type_t& type)
static bool get_keyword(const string& entry, program& prog, string& remaining_entry)
{
program_fn_t fn;
unsigned int obj_len;
cmd_type_t type;
bool ret = false;
// could be a command
@ -179,17 +180,17 @@ static bool get_keyword(const string& entry, object*& obj, unsigned int& obj_siz
if (type == cmd_keyword)
{
// allocate keyword object
obj_size = sizeof(keyword)+entry.size()+1;
obj = (object*)malloc(obj_size);
((keyword*)obj)->set(fn, entry.c_str(), entry.size());
obj_len = sizeof(keyword)+entry.size()+1;
keyword* new_obj = (keyword*)prog.allocate_back(obj_len, cmd_keyword);
new_obj->set(fn, entry.c_str(), entry.size());
ret = true;
}
else if (type == cmd_branch)
{
// allocate branch object
obj_size = sizeof(branch)+entry.size()+1;
obj = (object*)malloc(obj_size);
((branch*)obj)->set((branch_fn_t)fn, entry.c_str(), entry.size());
obj_len = sizeof(branch)+entry.size()+1;
branch* new_obj = (branch*)prog.allocate_back(obj_len, cmd_branch);
new_obj->set((branch_fn_t)fn, entry.c_str(), entry.size());
ret = true;
}
}
@ -197,27 +198,28 @@ static bool get_keyword(const string& entry, object*& obj, unsigned int& obj_siz
return ret;
}
static bool get_symbol(const string& entry, object*& obj, unsigned int& obj_len)
static bool get_symbol(const string& entry, program& prog, string& remaining_entry)
{
bool ret = false;
int entry_len = entry.size();
unsigned int obj_len;
if (entry_len>=1 && entry[0]=='\'')
{
// symbol entry, like 'toto'
if (entry_len == 1)
{
// void symbol entry, like '
// total object length
obj_len = sizeof(symbol)+1;
// allocate object
obj = (symbol*)malloc(obj_len);
//set it
((symbol*)obj)->set("", 0);
// allocate and set object
// symbol beginning with ' is not autoevaluated
symbol* new_obj = (symbol*)prog.allocate_back(obj_len, cmd_symbol);
new_obj->set("", 0, false);
}
else
{
// symbol entry, like 'toto' or 'toto
int naked_entry_len;
// entry length without prefix / postfix
@ -225,11 +227,10 @@ static bool get_symbol(const string& entry, object*& obj, unsigned int& obj_len)
// total object length
obj_len = sizeof(symbol)+naked_entry_len+1;
// allocate object
obj = (symbol*)malloc(obj_len);
// set it
((symbol*)obj)->set(entry.substr(1, naked_entry_len).c_str(), naked_entry_len);
// allocate and set object
// symbol beginning with ' is not autoevaluated
symbol* new_obj = (symbol*)prog.allocate_back(obj_len, cmd_symbol);
new_obj->set(entry.substr(1, naked_entry_len).c_str(), naked_entry_len, false);
}
ret = true;
}
@ -237,10 +238,11 @@ static bool get_symbol(const string& entry, object*& obj, unsigned int& obj_len)
return ret;
}
static bool get_other(const string& entry, object*& obj, unsigned int& obj_len, cmd_type_t& type)
static bool get_other(const string& entry, program& prog, string& remaining_entry)
{
bool ret = false;
int entry_len = entry.size();
unsigned int obj_len;
if (entry_len>=1)
{
@ -252,22 +254,20 @@ static bool get_other(const string& entry, object*& obj, unsigned int& obj_len,
// total object length
obj_len = sizeof(symbol)+naked_entry_len+1;
// allocate object
obj = (symbol*)malloc(obj_len);
// set it
((symbol*)obj)->set(entry.c_str(), naked_entry_len);
((symbol*)obj)->_auto_eval = true;
type = cmd_symbol;
// allocate and set object
// symbol not beginning with ' is autoevaluated (ie is evaluated when pushed on stack)
symbol* new_obj = (symbol*)prog.allocate_back(obj_len, cmd_symbol);
new_obj->set(entry.c_str(), naked_entry_len, true);
ret = true;
}
return ret;
}
static bool get_string(const string& entry, object*& obj, unsigned int& obj_len)
static bool get_string(const string& entry, program& prog, string& remaining_entry)
{
bool ret = false;
unsigned int obj_len;
int entry_len = entry.size();
if (entry_len>=1 && entry[0]=='"')
{
@ -276,11 +276,9 @@ static bool get_string(const string& entry, object*& obj, unsigned int& obj_len)
// total object length
obj_len = sizeof(ostring)+1;
// allocate object
obj = (ostring*)malloc(obj_len);
//set it
((ostring*)obj)->set("", 0);
// allocate and set object
ostring* new_obj = (ostring*)prog.allocate_back(obj_len, cmd_string);
new_obj->set("", 0);
}
else
{
@ -292,11 +290,9 @@ static bool get_string(const string& entry, object*& obj, unsigned int& obj_len)
// total object length
obj_len = sizeof(ostring)+naked_entry_len+1;
// allocate object
obj = (ostring*)malloc(obj_len);
// set it
((ostring*)obj)->set(entry.substr(1, naked_entry_len).c_str(), naked_entry_len);
// allocate and set object
ostring* new_obj = (ostring*)prog.allocate_back(obj_len, cmd_string);
new_obj->set(entry.substr(1, naked_entry_len).c_str(), naked_entry_len);
}
ret = true;
}
@ -304,9 +300,10 @@ static bool get_string(const string& entry, object*& obj, unsigned int& obj_len)
return ret;
}
static bool get_program(const string& entry, object*& obj, unsigned int& obj_len)
static bool get_program(const string& entry, program& prog, string& remaining_entry)
{
bool ret = false;
unsigned int obj_len;
int entry_len = entry.size();
if (entry_len>=2 && entry[0]=='<' && entry[1]=='<')
{
@ -321,160 +318,83 @@ static bool get_program(const string& entry, object*& obj, unsigned int& obj_len
// total object length
obj_len = sizeof(oprogram)+naked_entry_len+1;
// allocate object
obj = (object*)malloc(obj_len);
// set it
((oprogram*)obj)->set(&entry[2], naked_entry_len);
// allocate and set object
oprogram* new_obj = (oprogram*)prog.allocate_back(obj_len, cmd_program);
new_obj->set(&entry[2], naked_entry_len);
ret = true;
}
return ret;
}
// care: not threadsafe
static bool get_float(const string& entry, object*& obj, unsigned int& obj_size, string& remaining_entry)
static bool get_number(const string& entry, program& prog, string& remaining_entry)
{
static number new_number;
floating_t val;
stringstream token;
char* endptr;
bool ret = false;
token<<entry;
token>>val;
if ( (!token.fail()) && (!token.bad()) )
if (entry.size() > 0)
{
new_number.set(val);
obj = &new_number;
obj_size = sizeof(number);
ret = true;
// remaining string if any
token>>remaining_entry;
}
return ret;
}
// care: not threadsafe
static bool get_binary(const string& entry, object*& obj, unsigned int& obj_size)
{
static binary new_binary;
integer_t val;
bool ret = false;
if ((entry.size() >= 2) && (entry[0] == '#'))
{
stringstream token;
char type = entry[entry.size() - 1];
bool syntax;
switch(type)
// pre parse to avoid doing a useless allocation
// detect the begining of a number, including nan, inf, @nan@, @inf@
if (entry.find_first_of("+-0123456789.ni@", 0) == 0)
{
case 'd':
token<<std::dec<<entry.substr(1);
syntax = true;
break;
case 'h':
token<<std::hex<<entry.substr(1);
syntax = true;
break;
case 'o':
token<<std::oct<<entry.substr(1);
syntax = true;
break;
default:
syntax = false;
break;
}
number* num = (number*)prog.allocate_back(number::calc_size(), cmd_number);
token>>val;
if(syntax && !token.fail())
{
new_binary.set(val);
obj = &new_binary;
obj_size = sizeof(binary);
ret = true;
}
}
return ret;
}
// care: not threadsafe
static bool get_binary_bin(const string& entry, object*& obj, unsigned int& obj_size)
{
static binary new_binary;
integer_t val;
int len = entry.size();
bool ret = false;
if ((len > 2) && (entry[0] == '#') && (entry[len - 1] == 'b'))
{
integer_t val(0);
integer_t exponent = (1 << (len-3));
for(int i=0; i<(len-2); i++)
{
if (entry.at(i+1)=='1')
int mpfr_ret = mpfr_strtofr(num->_value.mpfr, entry.c_str(), &endptr, 0, MPFR_DEF_RND);
if (endptr != NULL && endptr != entry.c_str())
{
val+=exponent;
exponent/=2;
// determine representation
string beg = entry.substr(0, 2);
if (beg == "0x" || beg == "0X")
num->_representation = number::hex;
else if (beg == "0b" || beg == "0B")
num->_representation = number::bin;
else
num->_representation = number::dec;
ret = true;
// remaining string if any
remaining_entry = endptr;
}
else
(void)prog.pop_back();
}
new_binary.set(val);
obj = &new_binary;
obj_size = sizeof(binary);
ret = true;
}
return ret;
}
static bool _obj_from_string(const string& entry, object*& obj, unsigned int& obj_size, cmd_type_t& type, string& remaining_entry)
static bool _obj_from_string(const string& entry, program& prog, string& remaining_entry)
{
bool ret = false;
remaining_entry.erase();
if (get_float(entry, obj, obj_size, remaining_entry))
if (get_number(entry, prog, remaining_entry))
{
type = cmd_number;
ret = true;
}
else if (get_binary(entry, obj, obj_size))
else if (get_symbol(entry, prog, remaining_entry))
{
type = cmd_binary;
ret = true;
}
else if (get_binary_bin(entry, obj, obj_size))
else if (get_string(entry, prog, remaining_entry))
{
type = cmd_binary;
ret = true;
}
else if (get_symbol(entry, obj, obj_size))
else if (get_program(entry, prog, remaining_entry))
{
type = cmd_symbol;
ret = true;
}
else if (get_string(entry, obj, obj_size))
{
type = cmd_string;
ret = true;
}
else if (get_program(entry, obj, obj_size))
{
type = cmd_program;
ret = true;
}
else if (get_keyword(entry, obj, obj_size, type))
else if (get_keyword(entry, prog, remaining_entry))
{
ret = true;
}
else
{
// nothing, considered as an auto-evaluated symbol
if (get_other(entry, obj, obj_size, type))
if (get_other(entry, prog, remaining_entry))
{
ret = true;
}
@ -483,22 +403,6 @@ static bool _obj_from_string(const string& entry, object*& obj, unsigned int& ob
return ret;
}
static void _delete_obj_from_string(object* obj)
{
if (obj != NULL)
{
switch (obj->_type)
{
case cmd_number:
case cmd_binary:
break;
default:
free(obj);
break;
}
}
}
static char* entry_completion_generator(const char* text, int state)
{
static int list_index, len, too_far;
@ -544,9 +448,6 @@ static ret_value parse(const char* entry, program& prog)
{
vector<string> entries;
ret_value ret = ret_ok;
cmd_type_t type;
unsigned int obj_size;
object* obj;
//1. cut global entry string into shorter strings
if (_cut(entry, entries))
@ -561,15 +462,9 @@ static ret_value parse(const char* entry, program& prog)
// remaining_entry is used only in case of concatenated entry
// ex: entry="1 2+" -> vector<string> = {"1", "2+"} -> first "1", second "2" and remaining_entry="+"
// this remaining entry is treated as an entry
if(_obj_from_string(main_entry, obj, obj_size, type, remaining_entry))
{
prog.push_back(obj, obj_size, type);
_delete_obj_from_string(obj);
}
else
{
// no syntax error for now, an unknown obj form is considered as a symbol
}
// TODO errors ?
_obj_from_string(main_entry, prog, remaining_entry);
main_entry = remaining_entry;
}
}
@ -601,5 +496,6 @@ static ret_value entry(program& prog)
else
ret = ret_internal;
//TODO
free(buf);
}

View file

@ -1,38 +0,0 @@
void dec()
{
binary::s_mode = binary::dec;
}
void hex()
{
binary::s_mode = binary::hex;
}
void oct()
{
binary::s_mode = binary::oct;
}
void bin()
{
binary::s_mode = binary::bin;
}
void rtob()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
binary bin;
bin.set(((integer_t)getf()));
_stack->push_back(&bin, bin.size(), cmd_binary);
}
void btor()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_binary);
putf((floating_t)getb());
}

View file

@ -3,9 +3,14 @@
int rpn_if(branch& myobj)
{
// myobj.arg1 = 'if' condition evaluation value
MIN_ARGUMENTS_RET(1, -1);
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -1);
myobj.arg1 = ((getf() != 0) ? 1 : 0);
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
if (mpfr_cmp_si(((number*)_stack->get_obj(0))->_value.mpfr, 0UL) != 0)
myobj.arg1 = 1;
else
myobj.arg1 = 0;
(void)_stack->pop_back();
return -1;
}
@ -44,37 +49,68 @@ void rpn_end(void)
int rpn_start(branch& myobj)
{
MIN_ARGUMENTS_RET(2, 1);
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -1);
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, -1);
int ret = -1;
MIN_ARGUMENTS_RET(2, -(int)ret_runtime_error);
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, -(int)ret_runtime_error);
// farg2 = last value of start command
stack::copy_and_push_back(*_stack, _stack->size()-1, _branch_stack);
myobj.farg2 = (number*)_branch_stack.back();
_stack->pop_back();
// farg1 = first value of start command
// farg2 = last value of start command
myobj.farg2 = getf();
myobj.farg1 = getf();
return -1;
stack::copy_and_push_back(*_stack, _stack->size()-1, _branch_stack);
myobj.farg1 = (number*)_branch_stack.back();
_stack->pop_back();
// test value
if (myobj.farg1->_value > myobj.farg2->_value)
// last boundary lower than first boundary
// -> next command shall be after 'next'
// arg2 holds index of 'next'
ret = myobj.arg2 + 1;
return ret;
}
int rpn_for(branch& myobj)
{
MIN_ARGUMENTS_RET(2, 1);
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -1);
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, -1);
int ret;
MIN_ARGUMENTS_RET(2, -(int)ret_runtime_error);
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
ARG_MUST_BE_OF_TYPE_RET(1, cmd_number, -(int)ret_runtime_error);
symbol* sym = ((symbol*)seq_obj(myobj.arg1));
// farg1 = first value of for command
// farg2 = last value of for command
// arg1 = index of symbol to increase
myobj.farg2 = getf();
myobj.farg1 = getf();
stack::copy_and_push_back(*_stack, _stack->size()-1, _branch_stack);
myobj.farg2 = (number*)_branch_stack.back();
_stack->pop_back();
// store symbol with first value
number num;
num.set(myobj.farg1);
_local_heap.add(string(sym->_value), &num, num.size(), cmd_number);
// farg1 = first value of for command
stack::copy_and_push_back(*_stack, _stack->size()-1, _branch_stack);
myobj.farg1 = (number*)_branch_stack.back();
_stack->pop_back();
return myobj.arg1 + 1;
// test value
if (myobj.farg1->_value > myobj.farg2->_value)
// last boundary lower than first boundary
// -> next command shall be after 'next'
// arg2 holds index of 'next'
ret = myobj.arg2 + 1;
else
{
// store symbol with first value
_local_heap.add(sym->_value, myobj.farg1, myobj.farg1->size());
(void)_stack->pop_back();
ret = myobj.arg1 + 1;
}
return ret;
}
int rpn_next(branch& myobj)
@ -89,25 +125,26 @@ int rpn_next(branch& myobj)
}
// increment then test
myobj.farg1++;
mpfr_add_si(myobj.farg1->_value.mpfr, myobj.farg1->_value.mpfr, 1UL, MPFR_DEF_RND);
// for command: increment symbol too
if (start_or_for->arg1 != -1)
{
void* obj;
object* obj;
unsigned int size;
int type;
symbol* var = (symbol*)seq_obj(start_or_for->arg1);
// check symbol variable is a number, then increase
if (_local_heap.get(string(var->_value), obj, size, type) && (type == cmd_number))
((number*)obj)->_value = myobj.farg1;
// increase symbol variable
_local_heap.replace_value(string(var->_value), myobj.farg1, myobj.farg1->size());
}
//test value
if (myobj.farg1 > start_or_for->farg2)
if (myobj.farg1->_value > start_or_for->farg2->_value)
{
// end of loop
myobj.arg_bool = false;// init again next time
_branch_stack.pop_back();
_branch_stack.pop_back();
return -1;
}
else
@ -123,46 +160,59 @@ int rpn_next(branch& myobj)
int rpn_step(branch& myobj)
{
// arg1 = index of start or for command in program
// farg1 = current count
floating_t step = getf();
branch* start_or_for = (branch*)seq_obj(myobj.arg1);
if (! myobj.arg_bool)
{
myobj.arg_bool = true;
myobj.farg1 = start_or_for->farg1;
}
int ret;
MIN_ARGUMENTS_RET(1, -(int)ret_runtime_error);
ARG_MUST_BE_OF_TYPE_RET(0, cmd_number, -(int)ret_runtime_error);
// increment then test
myobj.farg1 += step;
number* step = (number*)_stack->pop_back();
// for command: increment symbol too
if (start_or_for->arg1 != -1)
{
void* obj;
unsigned int size;
int type;
symbol* var = (symbol*)seq_obj(start_or_for->arg1);
// check symbol variable is a number, then increase
if (_local_heap.get(string(var->_value), obj, size, type) && (type == cmd_number))
((number*)obj)->_value = myobj.farg1;
}
//test value
if (((step>0) && (myobj.farg1 > start_or_for->farg2))
|| ((step<0) && (myobj.farg1 < start_or_for->farg2)))
{
// end of loop
myobj.arg_bool = false;// init again next time
return -1;
}
// end of loop if step is negative or zero
if (mpfr_cmp_d(step->_value.mpfr, 0.0)<=0)
ret = -1;
else
{
// for command: next instruction will be after symbol variable
// arg1 = index of start or for command in program
// farg1 = current count
branch* start_or_for = (branch*)seq_obj(myobj.arg1);
if (! myobj.arg_bool)
{
myobj.arg_bool = true;
myobj.farg1 = start_or_for->farg1;
}
// increment then test
mpfr_add(myobj.farg1->_value.mpfr, myobj.farg1->_value.mpfr, step->_value.mpfr, MPFR_DEF_RND);
// for command: increment symbol too
if (start_or_for->arg1 != -1)
return start_or_for->arg1 + 1;
// start command: next instruction will be after start command
{
object* obj;
unsigned int size;
symbol* var = (symbol*)seq_obj(start_or_for->arg1);
// increase symbol variable
_local_heap.replace_value(string(var->_value), myobj.farg1, myobj.farg1->size());
}
// test loop value is out of range
if (myobj.farg1->_value > start_or_for->farg2->_value)
{
// end of loop
myobj.arg_bool = false;// init again next time
_branch_stack.pop_back();
_branch_stack.pop_back();
ret = -1;
}
else
return myobj.arg1 + 1;
{
// for command: next instruction will be after symbol variable
if (start_or_for->arg1 != -1)
ret = start_or_for->arg1 + 1;
// start command: next instruction will be after start command
else
ret = myobj.arg1 + 1;
}
}
return ret;
}

View file

@ -10,12 +10,10 @@ program::keyword_t program::_keywords[] =
{ cmd_keyword, "quit", &program::good_bye, "(or q or exit) quit software" },
{ cmd_keyword, "exit", &program::good_bye, "" },
{ cmd_keyword, "test", &program::test, "" }, //not seen by user
{ cmd_keyword, "verbose", &program::verbose, "set verbosity, from 0 (not verbose) to > 0" },
{ cmd_keyword, "std", &program::std, "standard floating numbers representation. ex: [25] std" },
{ cmd_keyword, "fix", &program::fix, "fixed point representation. ex: 6 fix" },
{ cmd_keyword, "sci", &program::sci, "scientific floating point representation. ex: 20 sci" },
{ cmd_keyword, "version", &program::rpn_version, "show rpn version" },
{ cmd_keyword, "uname", &program::rpn_uname, "show rpn complete identification string" },
{ cmd_keyword, "type", &program::type, "show first stack entry type" },
{ cmd_keyword, "default", &program::rpn_default, "setting precision, float representation, float precision and verbosity to default" },
//REAL
{ cmd_undef, "", NULL, "\nREAL"},
@ -32,14 +30,14 @@ program::keyword_t program::_keywords[] =
{ cmd_keyword, "sq", &program::square, "unarity operator square" },
{ cmd_keyword, "mod", &program::modulo, "binary operator modulo" },
//BINARY
{ cmd_undef, "", NULL, "\nBINARY"},
{ cmd_keyword, "dec", &program::dec, "decimal representation for binaries" },
{ cmd_keyword, "hex", &program::hex, "hexadecimal representation for binaries" },
{ cmd_keyword, "oct", &program::oct, "octal representation for binaries" },
{ cmd_keyword, "bin", &program::bin, "binary representation for binaries" },
{ cmd_keyword, "r->b", &program::rtob, "real to binary" },
{ cmd_keyword, "b->r", &program::btor, "binary to real" },
//REAL representation
{ cmd_undef, "", NULL, "\nREAL REPRESENTATION"},
{ cmd_keyword, "dec", &program::dec, "decimal representation" },
{ cmd_keyword, "hex", &program::hex, "hexadecimal representation" },
{ cmd_keyword, "bin", &program::bin, "binary representation" },
{ cmd_keyword, "std", &program::std, "standard floating numbers representation. ex: [25] std" },
{ cmd_keyword, "fix", &program::fix, "fixed point representation. ex: 6 fix" },
{ cmd_keyword, "sci", &program::sci, "scientific floating point representation. ex: 20 sci" },
//TEST
{ cmd_undef, "", NULL, "\nTEST"},

View file

@ -11,22 +11,18 @@ void good_bye()
ERR_CONTEXT(ret_good_bye);
}
void verbose()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
g_verbose = (int)getf();
}
void help()
{
// software name
cout<<endl;
cout<<ATTR_BOLD<<uname<<ATTR_OFF<<endl;
cout<<endl;
// description
cout<<description<<endl<<endl;
// syntax
for (int i = 0; syntax[i] != NULL; i++)
cout<<syntax[i]<<endl;
cout<<syntax<<endl;
// keywords
for(unsigned int i=0; i<sizeof(_keywords)/sizeof(_keywords[0]); i++)
@ -45,8 +41,6 @@ void help()
cout<<endl;
// different modes
cout<<"Current verbosity is "<<g_verbose<<endl;
cout<<"Current float mode is ";
switch(number::s_mode)
{
@ -57,16 +51,6 @@ void help()
}
cout<<endl<<"Current float precision is "<<number::s_current_precision<<endl;
cout<<"Current binary mode is ";
switch(binary::s_mode)
{
case binary::dec: cout << "'dec'"; break;
case binary::hex: cout << "'hex'"; break;
case binary::oct: cout << "'oct'"; break;
case binary::bin: cout << "'bin'"; break;
default: cout << "unknown"; break;
}
cout<<endl<<endl;
}
@ -75,13 +59,18 @@ void std()
if (stack_size()>=1)
{
ARG_MUST_BE_OF_TYPE(0, cmd_number);
number::s_default_precision = (int)getf();
int precision = int(((number*)_stack->pop_back())->_value);
number::s_default_precision = int(precision);
}
number::s_current_precision = number::s_default_precision;
number::s_mode = number::std;
cout.precision(number::s_current_precision);
cout.unsetf(ios_base::floatfield);
// format for mpfr_printf
stringstream ss;
ss << number::s_current_precision;
s_mpfr_printf_format = s_mpfr_printf_format_beg + ss.str() + s_mpfr_printf_format_std;
}
void fix()
@ -89,10 +78,15 @@ void fix()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
number::s_current_precision = (int)getf();
int precision = int(((number*)_stack->pop_back())->_value);
number::s_current_precision = int(precision);
number::s_mode = number::fix;
cout << setprecision(number::s_current_precision) << fixed;
// format for mpfr_printf
stringstream ss;
ss << number::s_current_precision;
s_mpfr_printf_format = s_mpfr_printf_format_beg + ss.str() + s_mpfr_printf_format_fix;
}
void sci()
@ -100,54 +94,48 @@ void sci()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
number::s_current_precision = (int)getf();
int precision = int(((number*)_stack->pop_back())->_value);
number::s_current_precision = int(precision);
number::s_mode = number::sci;
cout << setprecision(number::s_current_precision) << scientific;
// format for mpfr_printf
stringstream ss;
ss << number::s_current_precision;
s_mpfr_printf_format = s_mpfr_printf_format_beg + ss.str() + s_mpfr_printf_format_sci;
}
void rpn_version()
{
int naked_entry_len;
int obj_len;
ostring* str;
// entry length without prefix / postfix
naked_entry_len = (int)strlen(version);
// total object length
obj_len = sizeof(ostring)+naked_entry_len+1;
// allocate object
str = (ostring*)malloc(obj_len);
// set it
// allocate and set object
unsigned int naked_entry_len = strlen(version);
ostring* str = (ostring*)_stack->allocate_back(sizeof(ostring)+naked_entry_len+1, cmd_string);
str->set(version, naked_entry_len);
// push in stack
_stack->push_back(str, str->size(), cmd_string);
free(str);
}
void rpn_uname()
{
int naked_entry_len;
int obj_len;
ostring* str;
// entry length without prefix / postfix
naked_entry_len = (int)strlen(uname);
// total object length
obj_len = sizeof(ostring)+naked_entry_len+1;
// allocate object
str = (ostring*)malloc(obj_len);
// set it
// allocate and set object
unsigned int naked_entry_len = strlen(uname);
ostring* str = (ostring*)_stack->allocate_back(sizeof(ostring)+naked_entry_len+1, cmd_string);
str->set(uname, naked_entry_len);
// push in stack
_stack->push_back(str, str->size(), cmd_string);
free(str);
}
void type()
{
MIN_ARGUMENTS(1);
int type = _stack->back()->_type;
if (type < 0 || type >= (int)cmd_max)
type = (int)cmd_undef;
unsigned int string_size = strlen(cmd_type_string[type]);
unsigned int size = sizeof(symbol)+string_size+1;
symbol* sym = (symbol*)_stack->allocate_back(size, cmd_symbol);
sym->set(cmd_type_string[type], string_size, false);
}
void rpn_default()
{
program::apply_default();
}

View file

@ -1,44 +1,53 @@
#define _USE_MATH_DEFINES
//
void rpn_e(void)
{
putf(M_E);
number* euler = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
euler->_value = 1L;
CHECK_MPFR(mpfr_exp(euler->_value.mpfr, euler->_value.mpfr, s_mpfr_rnd));
}
void rpn_log()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = log10(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_log10(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_alog()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = pow(((number*)_stack->get_obj(0))->_value, 10);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_exp10(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_ln()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = log(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_log(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_exp()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = exp(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_exp(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_sinh()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = sinh(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_sinh(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_asinh()
@ -46,20 +55,17 @@ void rpn_asinh()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
floating_t value = ((number*)_stack->get_obj(0))->_value;
if(value>0)
value = log(value + sqrt(value * value + 1));
else
value = -log(-value + sqrt(value * value + 1));
((number*)_stack->get_obj(0))->_value = value;
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_asinh(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_cosh()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = cosh(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_cosh(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_acosh()
@ -67,20 +73,17 @@ void rpn_acosh()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
floating_t value = ((number*)_stack->get_obj(0))->_value;
if(value>0)
value = log(value + sqrt(value * value - 1));
else
value = -log(-value + sqrt(value * value - 1));
((number*)_stack->get_obj(0))->_value = value;
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_cosh(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_tanh()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = tanh(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_tanh(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_atanh()
@ -88,7 +91,6 @@ void rpn_atanh()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
floating_t value = ((number*)_stack->get_obj(0))->_value;
value = (log(1 + value) - log(1 - value)) / 2;
((number*)_stack->get_obj(0))->_value = value;
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_atanh(left->mpfr, left->mpfr, s_mpfr_rnd));
}

View file

@ -8,28 +8,28 @@ void eval(void)
if (IS_ARG_TYPE(0, cmd_symbol))
{
// recall a variable
void* obj;
object* obj;
unsigned int size;
int type;
string variable(((symbol*)_stack->back())->_value);
// mind the order of heaps
if (_local_heap.get(variable, obj, size, type)
|| ((_parent_local_heap != NULL) && _parent_local_heap->get(variable, obj, size, type))
|| _global_heap->get(variable, obj, size, type))
if (_local_heap.get(variable, obj, size)
|| ((_parent_local_heap != NULL) && _parent_local_heap->get(variable, obj, size))
|| _global_heap->get(variable, obj, size))
{
// if variable holds a program, run this program
if (type == cmd_program)
{
prog_text = ((oprogram*)obj)->_value;
_stack->pop_back();
(void)_stack->pop_back();
run_prog = true;
}
else
{
// else recall variable (i.e. stack its content)
_stack->pop_back();
_stack->push_back(obj, size, type);
// else recall this variable (i.e. stack its content)
(void)_stack->pop_back();
stack::copy_and_push_back(obj, *_stack, size);
}
}
else
@ -38,8 +38,7 @@ void eval(void)
else if (IS_ARG_TYPE(0, cmd_program))
{
// eval a program
prog_text = ((oprogram*)_stack->back())->_value;
_stack->pop_back();
prog_text = ((oprogram*)_stack->pop_back())->_value;
run_prog = true;
}
else
@ -125,7 +124,7 @@ int inprog(branch& myobj)
for (unsigned int i = myobj.arg1 + count_symbols; i > myobj.arg1; i--)
{
local_heap.add(string(((symbol*)seq_obj(i))->_value), _stack->get_obj(0), _stack->get_len(0), _stack->get_type(0));
_stack->pop_back();
(void)_stack->pop_back();
}
// run the program

View file

@ -1,125 +1,54 @@
void plus()
{
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
// float
if (IS_ARG_TYPE(0, cmd_number))
{
ARG_MUST_BE_OF_TYPE(1, cmd_number);
//TODO really too slow
putf(getf() + getf());
}
// binary
else if (IS_ARG_TYPE(0, cmd_binary))
{
ARG_MUST_BE_OF_TYPE(1, cmd_binary);
//TODO really too slow
putb(getb() + getb());
}
//TODO
#if 0
// string
else if (IS_ARG_TYPE(0, cmd_string))
{
ARG_MUST_BE_OF_TYPE(1, cmd_string);
string& second = *((ostring*)_stack->back())->_value;
_stack->pop_back();
*((ostring*)_stack->back())->_value += second;
}
#endif
else
ERR_CONTEXT(ret_bad_operand_type);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_add(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, s_mpfr_rnd));
}
void minus()
{
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
// float
if (IS_ARG_TYPE(0, cmd_number))
{
ARG_MUST_BE_OF_TYPE(1, cmd_number);
//TODO really too slow
floating_t first = getf();
putf(getf() - first);
}
// binary
else if (IS_ARG_TYPE(0, cmd_binary))
{
ARG_MUST_BE_OF_TYPE(1, cmd_binary);
//TODO really too slow
integer_t first = getb();
putb(getb() - first);
}
else
ERR_CONTEXT(ret_bad_operand_type);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_sub(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, s_mpfr_rnd));
}
void mul()
{
// float
if (IS_ARG_TYPE(0, cmd_number))
{
ARG_MUST_BE_OF_TYPE(1, cmd_number);
//TODO really too slow
putf(getf() * getf());
}
// binary
else if (IS_ARG_TYPE(0, cmd_binary))
{
ARG_MUST_BE_OF_TYPE(1, cmd_binary);
//TODO really too slow
putb(getb() * getb());
}
else
ERR_CONTEXT(ret_bad_operand_type);
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_mul(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, s_mpfr_rnd));
}
void div()
{
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
// float
if (IS_ARG_TYPE(0, cmd_number))
{
ARG_MUST_BE_OF_TYPE(1, cmd_number);
//TODO really too slow
floating_t first = getf();
// arithmetic faults are managed by c++
putf(getf() / first);
}
// binary
else if (IS_ARG_TYPE(0, cmd_binary))
{
ARG_MUST_BE_OF_TYPE(1, cmd_binary);
if (((binary*)_stack->get_obj(0))->_value == 0)
{
ERR_CONTEXT(ret_div_by_zero);
}
else
{
//TODO really too slow
integer_t first = getb();
putb(getb() / first);
}
}
else
ERR_CONTEXT(ret_bad_operand_type);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_div(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, s_mpfr_rnd));
}
void neg()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
// float
if (IS_ARG_TYPE(0, cmd_number))
putf(-getf());
// binary
else if (IS_ARG_TYPE(0, cmd_binary))
putb(-getb());
else
ERR_CONTEXT(ret_bad_operand_type);
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_neg(left->_value.mpfr, left->_value.mpfr, s_mpfr_rnd));
}
void inv()
@ -127,8 +56,8 @@ void inv()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
// arithmetic faults are managed by c++
putf(1 / getf());
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_si_div(left->_value.mpfr, 1L, left->_value.mpfr, s_mpfr_rnd));
}
void purcent()
@ -137,7 +66,11 @@ void purcent()
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
putf((getf() * getf()) / 100);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_mul(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, s_mpfr_rnd));
CHECK_MPFR(mpfr_div_si(left->_value.mpfr, left->_value.mpfr, 100L, s_mpfr_rnd));
}
void purcentCH()
@ -146,9 +79,11 @@ void purcentCH()
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
// arithmetic faults are managed by c++
floating_t first = getf();
putf((100 * first) / getf());
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_mul_si(right->_value.mpfr, right->_value.mpfr, 100L, s_mpfr_rnd));
CHECK_MPFR(mpfr_div(left->_value.mpfr, right->_value.mpfr, left->_value.mpfr, s_mpfr_rnd));
}
void power()
@ -157,9 +92,9 @@ void power()
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
// arithmetic faults are managed by c++
floating_t first = getf();
putf(powl(getf(), first));
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_pow(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, s_mpfr_rnd));
}
void squareroot()
@ -167,8 +102,8 @@ void squareroot()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
// arithmetic faults are managed by c++
putf(sqrtl(getf()));
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_sqrt(left->_value.mpfr, left->_value.mpfr, s_mpfr_rnd));
}
void square()
@ -176,8 +111,8 @@ void square()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
floating_t first = getf();
putf(first * first);
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_sqr(left->_value.mpfr, left->_value.mpfr, s_mpfr_rnd));
}
void modulo()
@ -186,7 +121,29 @@ void modulo()
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
// arithmetic faults are managed by c++
floating_t first = getf();
putf(fmodl(getf(), first));
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
CHECK_MPFR(mpfr_fmod(left->_value.mpfr, left->_value.mpfr, right->_value.mpfr, s_mpfr_rnd));
}
void hex()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->back())->_representation = number::hex;
}
void bin()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->back())->_representation = number::bin;
}
void dec()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->back())->_representation = number::dec;
}

View file

@ -2,81 +2,86 @@
void swap(void)
{
MIN_ARGUMENTS(2);
_stack->copy_obj_to_local(0, 0);
_stack->copy_obj_to_local(1, 1);
_stack->pop_back();
_stack->pop_back();
_stack->push_obj_from_local(0);
_stack->push_obj_from_local(1);
stack::copy_and_push_back(*_stack, _stack->size()-1, _branch_stack);
stack::copy_and_push_back(*_stack, _stack->size()-2, _branch_stack);
(void)_stack->pop_back();
(void)_stack->pop_back();
stack::copy_and_push_back(_branch_stack, 0, *_stack);
stack::copy_and_push_back(_branch_stack, 1, *_stack);
(void)_branch_stack.pop_back();
(void)_branch_stack.pop_back();
}
void drop(void)
{
MIN_ARGUMENTS(1);
_stack->pop_back();
(void)_stack->pop_back();
}
void drop2(void)
{
MIN_ARGUMENTS(2);
_stack->pop_back();
_stack->pop_back();
(void)_stack->pop_back();
(void)_stack->pop_back();
}
void erase(void)
{
while(_stack->size()>0)
_stack->pop_back();
(void)_stack->pop_back();
}
void dup(void)
{
MIN_ARGUMENTS(1);
_stack->copy_obj_to_local(0, 0);
_stack->push_obj_from_local(0);
stack::copy_and_push_back(*_stack, _stack->size()-1, *_stack);
}
void dup2(void)
{
MIN_ARGUMENTS(2);
_stack->copy_obj_to_local(0, 0);
_stack->copy_obj_to_local(1, 1);
_stack->push_obj_from_local(1);
_stack->push_obj_from_local(0);
stack::copy_and_push_back(*_stack, _stack->size()-2, *_stack);
stack::copy_and_push_back(*_stack, _stack->size()-2, *_stack);
}
void pick(void)
{
MIN_ARGUMENTS(1);
unsigned int to_pick = (unsigned int)getf();
ARG_MUST_BE_OF_TYPE(0, cmd_number);
unsigned int to_pick = (unsigned int)int(((number*)_stack->pop_back())->_value);
// treat stack depth errors
if ((to_pick == 0) || (to_pick > _stack->size()))
{
ERR_CONTEXT(ret_missing_operand);
ERR_CONTEXT(ret_out_of_range);
return;
}
_stack->copy_obj_to_local(to_pick - 1, 0);
_stack->push_obj_from_local(0);
stack::copy_and_push_back(*_stack, _stack->size()-to_pick, *_stack);
}
void rot(void)
{
MIN_ARGUMENTS(3);
_stack->copy_obj_to_local(0, 0);
_stack->copy_obj_to_local(1, 1);
_stack->copy_obj_to_local(2, 2);
_stack->pop_back();
_stack->pop_back();
_stack->pop_back();
_stack->push_obj_from_local(1);
_stack->push_obj_from_local(0);
_stack->push_obj_from_local(2);
stack::copy_and_push_back(*_stack, _stack->size()-3, _branch_stack);
stack::copy_and_push_back(*_stack, _stack->size()-2, _branch_stack);
stack::copy_and_push_back(*_stack, _stack->size()-1, _branch_stack);
(void)_stack->pop_back();
(void)_stack->pop_back();
(void)_stack->pop_back();
stack::copy_and_push_back(_branch_stack, 1, *_stack);
stack::copy_and_push_back(_branch_stack, 2, *_stack);
stack::copy_and_push_back(_branch_stack, 0, *_stack);
(void)_branch_stack.pop_back();
(void)_branch_stack.pop_back();
(void)_branch_stack.pop_back();
}
void depth(void)
{
number num;
num.set((floating_t)_stack->size());
_stack->push_back(&num, num.size(), cmd_number);
unsigned long depth = (unsigned long)_stack->size();
number* num = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
num->set(depth);
}

View file

@ -4,10 +4,9 @@ void sto(void)
MIN_ARGUMENTS(2);
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
string name(((symbol*)_stack->get_obj(0))->_value);
_stack->pop_back();
_global_heap->add(name, _stack->get_obj(0), _stack->get_len(0), _stack->get_type(0));
_stack->pop_back();
string name(((symbol*)_stack->pop_back())->_value);
_global_heap->add(name, _stack->get_obj(0), _stack->get_len(0));
(void)_stack->pop_back();
}
void rcl(void)
@ -16,18 +15,19 @@ void rcl(void)
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
// recall a variable
void* obj;
object* obj;
unsigned int size;
int type;
string variable(((symbol*)_stack->back())->_value);
// mind the order of heaps
if (_local_heap.get(variable, obj, size, type)
|| ((_parent_local_heap != NULL) && (_parent_local_heap->get(variable, obj, size, type)))
|| _global_heap->get(variable, obj, size, type))
if (_local_heap.get(variable, obj, size)
|| ((_parent_local_heap != NULL) && (_parent_local_heap->get(variable, obj, size)))
|| _global_heap->get(variable, obj, size))
{
_stack->pop_back();
_stack->push_back(obj, size, type);
(void)_stack->pop_back();
object* new_obj = _stack->allocate_back(size, obj->_type);
stack::copy_and_push_back(obj, *_stack, size);
}
else
ERR_CONTEXT(ret_unknown_variable);
@ -57,8 +57,7 @@ void edit(void)
}
// re-write stack objet in a stream
((object*)_stack->back())->show(out);
_stack->pop_back();
((object*)_stack->pop_back())->show(out);
// edit: stuff chars using readline facility
string str = out.str();
@ -72,27 +71,29 @@ void auto_rcl(symbol* symb)
{
if (symb->_auto_eval)
{
void* obj;
object* obj;
unsigned int size;
int type;
string variable(symb->_value);
// mind the order of heaps
if (_local_heap.get(variable, obj, size, type)
|| ((_parent_local_heap != NULL) && (_parent_local_heap->get(variable, obj, size, type)))
|| _global_heap->get(variable, obj, size, type))
if (_local_heap.get(variable, obj, size)
|| ((_parent_local_heap != NULL) && (_parent_local_heap->get(variable, obj, size)))
|| _global_heap->get(variable, obj, size))
{
_stack->push_back(obj, size, type);
stack::copy_and_push_back(obj, *_stack, size);
if (type == cmd_program)
{
eval();
}
}
else
_stack->push_back(symb, symb->size(), cmd_symbol);
{
stack::copy_and_push_back(symb, *_stack, symb->size());
}
}
else
_stack->push_back(symb, symb->size(), cmd_symbol);
{
stack::copy_and_push_back(symb, *_stack, symb->size());
}
}
void purge(void)
@ -100,7 +101,7 @@ void purge(void)
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_symbol);
string name(((symbol*)_stack->back())->_value);
string name(((symbol*)_stack->pop_back())->_value);
// mind the order of heaps
bool done = false;
@ -114,7 +115,6 @@ void purge(void)
else
done = true;
_stack->pop_back();
if (!done)
ERR_CONTEXT(ret_unknown_variable);
}
@ -128,8 +128,8 @@ void vars(void)
for (int i=0; i<(int)_global_heap->size(); i++)
{
(void)_global_heap->get_by_index(i, name, (void*&)obj, size, type);
cout<<"var "<<i+1<<": name '"<<name<<"', type "<<cmd_type_string[type]<<", value ";
(void)_global_heap->get_by_index(i, name, obj, size);
cout<<"var "<<i+1<<": name '"<<name<<"', type "<<cmd_type_string[obj->_type]<<", value ";
obj->show();
cout<<endl;
}
@ -137,16 +137,16 @@ void vars(void)
{
for (int i=0; i<(int)_parent_local_heap->size(); i++)
{
(void)_parent_local_heap->get_by_index(i, name, (void*&)obj, size, type);
cout<<"local var "<<i+1<<": name '"<<name<<"', type "<<cmd_type_string[type]<<", value ";
(void)_parent_local_heap->get_by_index(i, name, obj, size);
cout<<"local var "<<i+1<<": name '"<<name<<"', type "<<cmd_type_string[obj->_type]<<", value ";
obj->show();
cout<<endl;
}
}
for (int i=0; i<(int)_local_heap.size(); i++)
{
(void)_local_heap.get_by_index(i, name, (void*&)obj, size, type);
cout<<"local var "<<i+1<<": name '"<<name<<"', type "<<cmd_type_string[type]<<", value ";
(void)_local_heap.get_by_index(i, name, obj, size);
cout<<"local var "<<i+1<<": name '"<<name<<"', type "<<cmd_type_string[obj->_type]<<", value ";
obj->show();
cout<<endl;
}

View file

@ -7,15 +7,14 @@ void instr()
{
// write the object in stack(0) in a string and remove this obj
stringstream out;
((object*)_stack->back())->show(out);
_stack->pop_back();
((object*)_stack->pop_back())->show(out);
// reserve the correct size in stack
_stack->push_back(NULL, out.str().size(), cmd_string, true);
unsigned int str_size = (unsigned int)out.str().size();
ostring* str = (ostring*)_stack->allocate_back(str_size+1+sizeof(ostring), cmd_string);
// fill the obj
ostring* str = (ostring*)_stack->get_obj(0);
str->set(out.str().c_str(), out.str().size());
str->set(out.str().c_str(), str_size);
}
}
@ -24,8 +23,7 @@ void strout()
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_string);
string entry(((ostring*)_stack->back())->_value);
_stack->pop_back();
string entry(((ostring*)_stack->pop_back())->_value);
program prog;

View file

@ -1,11 +1,19 @@
void program::test()
{
const string test_filename = "test.txt";
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_string);
const string stack_size("-> stack size should be ");
const string stack_value("-> stack should be ");
const string cmd_error("-> error should be ");
const string cmd_exit("exit test");
string test_filename = ((ostring*)_stack->pop_back())->_value;
ifstream test_file(test_filename.c_str());
int tests = 0;
int tests_failed = 0;
int steps = 0;
int steps_failed = 0;
if (test_file.is_open())
{
@ -14,9 +22,9 @@ void program::test()
ret_value ret;
stack stk;
heap hp;
bool indicate_passed = false;
bool failed = false;
int count_tests = 0;
bool is_first_step;
bool is_test_error_shown;
int last_err;
stringstream cerr_buffer;
streambuf* cerr_old_buffer;
@ -24,36 +32,35 @@ void program::test()
// redirect cerr
cerr_old_buffer = cerr.rdbuf(cerr_buffer.rdbuf());
while ((!failed) && (!test_file.eof()))
while (!test_file.eof())
{
getline(test_file, entry);
if (entry.substr(0,2)=="##")
{
// read a test section
if (indicate_passed)
{
if (g_verbose > 0)
cout << "\t";
cout << "passed " << count_tests << " tests"<< endl;
}
cout << entry;
if (g_verbose == 0)
cout << " .. ";
else
cout << endl;
indicate_passed = true;
count_tests = 0;
cout << endl;
}
else if (entry.substr(0,1)=="#")
else if (entry.substr(0,2)=="# ")
{
// indicates the status of previous test
if (failed == false && tests > 0)
cout<<FG_GREEN<<" PASSED"<<COLOR_OFF<<endl;
failed = false;
// read a test title
test_title = entry;
if (g_verbose > 0)
cout << "\t" << test_title << endl;
count_tests++;
is_first_step = true;
is_test_error_shown = false;
cout << test_title;
}
// treat "-> stack size should be "
else if (entry.find(stack_size, 0) == 0)
{
// count test and step
if (is_first_step)
tests++;
steps++;
// check current stack size
istringstream isub;
int size;
@ -62,22 +69,38 @@ void program::test()
isub>>size;
if (size != (int)stk.size())
{
cout<<endl<<endl<<test_title<<endl<<entry<<endl<<"FAIL, ";
cout<<"stack size is "<<stk.size()<<endl;
// count fail test and step
if (!is_test_error_shown)
{
cout<<FG_RED<<" FAIL"<<COLOR_OFF<<endl;
tests_failed++;
is_test_error_shown = true;
}
steps_failed++;
// show failure
cout<<"\t"<<entry<<endl;
cout<<"\tbut real stack size is "<<FG_RED<<stk.size()<<COLOR_OFF<<endl;
failed = true;
indicate_passed = false;
}
is_first_step = false;
}
// treat "-> stack should be "
else if (entry.find(stack_value, 0) == 0)
{
// count test
if (is_first_step)
tests++;
steps++;
// check current stack value
string stack_should_be = entry.substr(stack_value.size());
string stack_is;
string tmp;
for (int i = (int)stk.size() - 1; i >= 0; i--)
for (int i = 0; i < (int)stk.size(); i++)
{
stringstream os;
if (i < (int)(stk.size() - 1))
if (i > 0)
stack_is += ", ";
((object*)stk.seq_obj(i))->show(os);
getline(os, tmp);
@ -85,14 +108,30 @@ void program::test()
}
if (stack_is != stack_should_be)
{
cout<<endl<<endl<<test_title<<endl<<entry<<endl<<"FAIL, ";
cout<<"real stack is '"<<stack_is<<endl;
// count fail test and step
if (!is_test_error_shown)
{
cout<<FG_RED<<" FAIL"<<COLOR_OFF<<endl;
tests_failed++;
is_test_error_shown = true;
}
steps_failed++;
// show failure
cout<<"\t"<<entry<<endl;
cout<<"\tbut real stack is "<<FG_RED<<stack_is<<COLOR_OFF<<endl;
failed = true;
indicate_passed = false;
}
is_first_step = false;
}
// treat "-> error should be "
else if (entry.find(cmd_error, 0) == 0)
{
// count test
if (is_first_step)
tests++;
steps++;
// check current error
istringstream isub;
int err_should_be;
@ -100,11 +139,21 @@ void program::test()
isub>>err_should_be;
if (err_should_be != last_err)
{
cout<<endl<<endl<<test_title<<endl<<entry<<endl<<"FAIL, ";
cout<<"last error is "<<last_err<<endl;
// count fail test and step
if (!is_test_error_shown)
{
cout<<FG_RED<<" FAIL"<<COLOR_OFF<<endl;
tests_failed++;
is_test_error_shown = true;
}
steps_failed++;
// show failure
cout<<"\t"<<entry<<endl;
cout<<"\tbut last error is "<<FG_RED<<last_err<<COLOR_OFF<<endl;
failed = true;
indicate_passed = false;
}
is_first_step = false;
}
else if (entry.find(cmd_exit, 0) == 0)
{
@ -124,13 +173,30 @@ void program::test()
}
}
}
if (indicate_passed)
cout << "passed " << count_tests << " tests"<< endl;
if (! failed)
cout << "test file '"<<test_filename<<"' has passed" << endl;
// last test
// indicates the status of previous test
if (failed == false && tests > 0)
cout << FG_GREEN << " PASSED" << COLOR_OFF << endl;
// cerr back
cerr.rdbuf(cerr_old_buffer);
// conclusion
cout<<endl<<"Run "<<tests<<" tests: "<<tests-tests_failed<<" passed, ";
if(tests_failed>0)
cout<<FG_RED;
cout<<tests_failed<<" failed";
if(tests_failed>0)
cout<<COLOR_OFF;
cout<<" ("<<steps<<" steps: "<<steps-steps_failed<<" passed, ";
if(steps_failed>0)
cout<<FG_RED;
cout<<steps_failed<<" failed";
if(steps_failed>0)
cout<<COLOR_OFF;
cout<<")"<<endl;
}
else
cerr << "test file '"<<test_filename<<"' not found" << endl;

View file

@ -4,8 +4,13 @@ void sup(void)
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
floating_t first = getf();
putf(getf() > first);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) > 0)
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
void sup_eq(void)
@ -14,8 +19,13 @@ void sup_eq(void)
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
floating_t first = getf();
putf(getf() >= first);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) >= 0)
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
void inf(void)
@ -24,8 +34,13 @@ void inf(void)
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
floating_t first = getf();
putf(getf() < first);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) < 0)
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
void inf_eq(void)
@ -34,8 +49,13 @@ void inf_eq(void)
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
floating_t first = getf();
putf(getf() <= first);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) <= 0)
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
void diff(void)
@ -44,47 +64,28 @@ void diff(void)
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
floating_t first = getf();
putf(getf() != first);
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) != 0)
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
void eq(void)
{
MIN_ARGUMENTS(2);
int type = _stack->get_type(0);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
if (_stack->get_type(1) == type)
{
switch(type)
{
case cmd_number:
{
floating_t first = getf();
putf(getf() == first);
}
break;
//TODO
#if 0
case cmd_symbol:
{
string first = getn();
putf(getn() == first);
}
#endif
break;
default:
_stack->pop_back();
_stack->pop_back();
putf(0);
break;
}
}
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp(left->_value.mpfr, right->_value.mpfr) == 0)
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
{
_stack->pop_back();
_stack->pop_back();
putf(0);
}
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
void test_and(void)
@ -93,9 +94,14 @@ void test_and(void)
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
floating_t first = getf();
floating_t second = getf();
putf((first != 0) && (second != 0));
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if ((mpfr_cmp_si(left->_value.mpfr, 0) != 0)
&& (mpfr_cmp_si(right->_value.mpfr, 0) != 0))
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
void test_or(void)
@ -104,9 +110,14 @@ void test_or(void)
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
floating_t first = getf();
floating_t second = getf();
putf((first != 0) || (second != 0));
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if ((mpfr_cmp_si(left->_value.mpfr, 0) != 0)
|| (mpfr_cmp_si(right->_value.mpfr, 0) != 0))
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
void test_xor(void)
@ -115,9 +126,23 @@ void test_xor(void)
ARG_MUST_BE_OF_TYPE(0, cmd_number);
ARG_MUST_BE_OF_TYPE(1, cmd_number);
floating_t first = getf();
floating_t second = getf();
putf(((first == 0) && (second != 0)) || ((first != 0) && (second == 0)));
number* right = (number*)_stack->pop_back();
number* left = (number*)_stack->back();
if (mpfr_cmp_si(left->_value.mpfr, 0) == 0)
{
if (mpfr_cmp_si(right->_value.mpfr, 0) != 0)
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
else
{
if (mpfr_cmp_si(right->_value.mpfr, 0) == 0)
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
}
void test_not(void)
@ -125,8 +150,11 @@ void test_not(void)
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
floating_t first = getf();
putf((first == 0) ? 1 : 0);
number* left = (number*)_stack->back();
if (mpfr_cmp_si(left->_value.mpfr, 0) == 0)
mpfr_set_si(left->_value.mpfr, 1, s_mpfr_rnd);
else
mpfr_set_si(left->_value.mpfr, 0, s_mpfr_rnd);
}
void same(void)

View file

@ -1,63 +1,84 @@
#define _USE_MATH_DEFINES
//
void pi(void)
{
putf(M_PI);
number* pi = (number*)_stack->allocate_back(number::calc_size(), cmd_number);
CHECK_MPFR(mpfr_const_pi(pi->_value.mpfr, s_mpfr_rnd));
}
void d2r(void)
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value *= M_PI / 360;
floating_t pi;
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_const_pi(pi.mpfr, s_mpfr_rnd));
CHECK_MPFR(mpfr_mul(left->mpfr, left->mpfr, pi.mpfr, s_mpfr_rnd));
CHECK_MPFR(mpfr_div_si(left->mpfr, left->mpfr, 180, s_mpfr_rnd));
}
void r2d(void)
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value *= 360 / M_PI;
floating_t pi;
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_const_pi(pi.mpfr, s_mpfr_rnd));
CHECK_MPFR(mpfr_mul_si(left->mpfr, left->mpfr, 180, s_mpfr_rnd));
CHECK_MPFR(mpfr_div(left->mpfr, left->mpfr, pi.mpfr, s_mpfr_rnd));
}
void rpn_sin(void)
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = sin(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_sin(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_asin(void)
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = asin(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_asin(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_cos(void)
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = cos(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_cos(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_acos(void)
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = acos(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_acos(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_tan(void)
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = tan(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_tan(left->mpfr, left->mpfr, s_mpfr_rnd));
}
void rpn_atan(void)
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_number);
((number*)_stack->get_obj(0))->_value = atan(((number*)_stack->get_obj(0))->_value);
floating_t* left = &((number*)_stack->get_obj(0))->_value;
CHECK_MPFR(mpfr_atan(left->mpfr, left->mpfr, s_mpfr_rnd));
}

View file

@ -21,8 +21,12 @@
*
*/
#include <stdlib.h>
#include <stdint.h> //for intmax_t
#include <mpfr.h>
#include <math.h>
#include "debug.h"
extern "C" {
#include <readline/readline.h>
#include <readline/history.h>
@ -35,10 +39,23 @@ extern "C" {
#include <fstream>
using namespace std;
#include "stack.h"
// default number of printed digitis
#define DEFAULT_PRECISION 12
//
static int g_verbose = 0;
// MPFR related constants
// 128 bits significand storing length in byters, result of mpfr_custom_get_size(128)
#define MPFR_DEF_RND MPFR_RNDN
#define MPFR_128BITS_PREC 128
#define MPFR_128BITS_STORING_LENGTH 16
static string s_mpfr_printf_format_beg = "%.";
static string s_mpfr_printf_format_std = "Rg";
static string s_mpfr_printf_format_fix = "Rf";
static string s_mpfr_printf_format_sci = "Re";
static string s_mpfr_printf_format_hex = "%Ra";
static string s_mpfr_printf_format = "%.12Rg";
static mpfr_prec_t s_mpfr_prec = MPFR_128BITS_PREC;
static mpfr_rnd_t s_mpfr_rnd = MPFR_DEF_RND;
//
#include "escape.h"
@ -49,6 +66,7 @@ typedef enum {
ret_unknown_err,
ret_missing_operand,
ret_bad_operand_type,
ret_out_of_range,
ret_unknown_variable,
ret_internal,
ret_deadly,
@ -57,18 +75,18 @@ typedef enum {
ret_nop,
ret_syntax,
ret_div_by_zero,
ret_runtime_error,
ret_max
} ret_value;
const char* ret_value_string[ret_max] = {
"ok", "unknown command", "missing operand", "bad operand type", "unknown variable", "internal error, aborting",
"deadly", "goodbye", "not implemented", "no operation", "syntax", "division by zero"
"ok", "unknown command", "missing operand", "bad operand type", "out of range", "unknown variable", "internal error, aborting",
"deadly", "goodbye", "not implemented", "no operation", "syntax error", "division by zero", "runtime error"
};
typedef enum {
cmd_undef,
cmd_number,/* floating value to put in stack */
cmd_binary,/* binary (integer) value to put in stack */
cmd_string,/* string value to put in stack */
cmd_symbol,/* symbol value to put in stack */
cmd_program,/* program */
@ -78,20 +96,56 @@ typedef enum {
} cmd_type_t;
const char* cmd_type_string[cmd_max] = {
"undef", "number", "binary", "string", "symbol", "program", "keyword", "keyword"
"undef", "number", "string", "symbol", "program", "keyword", "keyword"
};
// MPFR object
struct floating_t
{
mpfr_t mpfr;
void init(void* significand)
{
mpfr_custom_init(significand, MPFR_128BITS_STORING_LENGTH);
mpfr_custom_init_set(mpfr, MPFR_ZERO_KIND, 0, s_mpfr_prec, significand);
}
void set_significand(void* significand)
{
mpfr->_mpfr_d = (mp_limb_t*)significand;
}
floating_t& operator=(const long int val)
{
mpfr_set_si(mpfr, val, s_mpfr_rnd);
}
floating_t& operator=(const unsigned long val)
{
mpfr_set_ui(mpfr, val, s_mpfr_rnd);
}
operator int()
{
return (int)mpfr_get_si(mpfr, s_mpfr_rnd);
}
bool operator>(const floating_t right)
{
return mpfr_cmp(mpfr, right.mpfr) > 0;
}
bool operator<(const floating_t right)
{
return mpfr_cmp(mpfr, right.mpfr) < 0;
}
};
//
typedef long double floating_t;
typedef long long integer_t;
class program;
class object;
class branch;
typedef void (program::*program_fn_t)(void);
typedef union
{
program_fn_t _fn;
} operand;
typedef int (program::*branch_fn_t)(branch&);
//
@ -99,22 +153,62 @@ struct object
{
// object type
cmd_type_t _type;
unsigned int _size;
//
unsigned int size() { return _size; }
void show(ostream& stream = cout);
} __attribute__((packed));
};
struct number : public object
{
number() { _type = cmd_number; }
floating_t _value;
void init(void* significand)
{
_type = cmd_number;
_representation = dec;
_value.init(significand);
}
void copy(number& op)
{
_value = op._value;
memcpy(_value.mpfr->_mpfr_d, op._value.mpfr->_mpfr_d, MPFR_128BITS_STORING_LENGTH);
}
//
void set(floating_t value)
void set(const floating_t& value)
{
_type = cmd_number;
_value.mpfr->_mpfr_d = value.mpfr->_mpfr_d;
}
void set(long value)
{
_type = cmd_number;
_value = value;
}
unsigned int size() { return sizeof(number); }
void set(unsigned long value)
{
_type = cmd_number;
_value = value;
}
static unsigned int calc_size()
{
return (unsigned int)(sizeof(number)+MPFR_128BITS_STORING_LENGTH);
}
//
number operator=(const number& op)
{
number num;
num.set((const floating_t&)op._value);
return num;
}
// representation mode
typedef enum {
@ -125,40 +219,22 @@ struct number : public object
static mode_enum s_default_mode;
static mode_enum s_mode;
enum {
dec,
hex,
bin
} _representation;
// precision
static int s_default_precision;
static int s_current_precision;
} __attribute__((packed));
};
number::mode_enum number::s_default_mode = number::std;
number::mode_enum number::s_mode = number::s_default_mode;
int number::s_default_precision = 12;
int number::s_default_precision = DEFAULT_PRECISION;
int number::s_current_precision = number::s_default_precision;
struct binary : public object
{
integer_t _value;
//
void set(integer_t value)
{
_type = cmd_binary;
_value = value;
}
unsigned int size() { return sizeof(binary); }
// representation mode
typedef enum {
dec,
hex,
oct,
bin,
} binary_enum;
static binary_enum s_default_mode;
static binary_enum s_mode;
} __attribute__((packed));
binary::binary_enum binary::s_default_mode = binary::dec;
binary::binary_enum binary::s_mode = binary::s_default_mode;
struct ostring : public object
{
//
@ -175,12 +251,11 @@ struct ostring : public object
else
len = 0;
}
int size() { return sizeof(ostring)+_len+1; }
//
unsigned int _len;
char _value[0];
} __attribute__((packed));
};
struct oprogram : public object
{
@ -198,20 +273,20 @@ struct oprogram : public object
else
len = 0;
}
int size() { return sizeof(oprogram)+_len+1; }
//
unsigned int _len;
char _value[0];
} __attribute__((packed));
};
struct symbol : public object
{
//
void set(const char* value, unsigned int len)
void set(const char* value, unsigned int len, bool auto_eval)
{
_type = cmd_symbol;
_auto_eval = false;
_auto_eval = auto_eval;
if (value != NULL)
{
if (len>0)
@ -222,13 +297,12 @@ struct symbol : public object
else
len = 0;
}
int size() { return sizeof(symbol)+_len+1; }
//
bool _auto_eval;
unsigned int _len;
char _value[0];
} __attribute__((packed));
};
struct keyword : public object
{
@ -247,13 +321,12 @@ struct keyword : public object
else
len = 0;
}
int size() { return sizeof(keyword)+_len+1; }
//
program_fn_t _fn;
unsigned int _len;
char _value[0];
} __attribute__((packed));
};
struct branch : public object
{
@ -265,8 +338,8 @@ struct branch : public object
arg1 = -1;
arg2 = -1;
arg3 = -1;
farg1 = 0;
farg2 = 0;
farg1 = NULL;
farg2 = NULL;
arg_bool = 0;
if (value != NULL)
{
@ -278,47 +351,37 @@ struct branch : public object
else
len = 0;
}
int size() { return sizeof(branch)+_len+1; }
// branch function
branch_fn_t _fn;
// args used by cmd_branch cmds
int arg1, arg2, arg3;
floating_t farg1, farg2;
number *farg1, *farg2;
bool arg_bool;
unsigned int _len;
char _value[0];
} __attribute__((packed));
};
void object::show(ostream& stream)
{
//TODO please NOOO
char buffer[512];
switch(_type)
{
case cmd_number:
stream << ((number*)this)->_value;
break;
case cmd_binary:
switch(((number*)this)->_representation)
{
cout << "# ";
switch(((binary*)this)->s_mode)
{
case binary::dec: stream<<std::right<<std::setw(8)<<std::dec<<((binary*)this)->_value<<" d"; break;
case binary::hex: stream<<std::right<<std::setw(8)<<std::hex<<((binary*)this)->_value<<" h"; break;
case binary::oct: stream<<std::right<<std::setw(8)<<std::oct<<((binary*)this)->_value<<" o"; break;
case binary::bin:
{
string mybin;
for (int i = (int)(log((floating_t)((binary*)this)->_value) / log(2.)); i>=0; i--)
{
if (((binary*)this)->_value & (1 << i))
mybin+='1';
else
mybin+='0';
}
stream<<std::right<<std::setw(20)<<std::oct<<mybin<<" b";
}
case number::dec:
(void)mpfr_sprintf(buffer, s_mpfr_printf_format.c_str(), ((number*)this)->_value.mpfr);
stream<<buffer;
break;
}
case number::hex:
(void)mpfr_sprintf(buffer, s_mpfr_printf_format_hex.c_str(), ((number*)this)->_value.mpfr);
stream<<buffer;
break;
case number::bin:
cout<<"<binary representation TODO>";
}
break;
case cmd_string:
@ -349,6 +412,8 @@ struct if_layout_t
int index_end;
};
#include "stack.h"
class program : public stack
{
public:
@ -383,14 +448,6 @@ public:
{
type = (cmd_type_t)seq_type(i);
//
if (g_verbose >= 2)
{
cout << "(" << i << ") ";
((object*)seq_obj(i))->show();
cout << endl;
}
// could be an auto-evaluated symbol
if (type == cmd_symbol)
{
@ -434,20 +491,32 @@ public:
{
// call matching function
branch* b = (branch*)seq_obj(i);
int tmp = (this->*(b->_fn))(*b);
if (tmp == -1)
i++;
else
i = tmp;
int next_cmd = (this->*(b->_fn))(*b);
switch (next_cmd)
{
case -1:
i++; // meaning 'next command'
break;
case -(int)ret_runtime_error:
// error: show it
(void)show_error(_err, _err_context);
go_out = true;// end of run
break;
default:
i = next_cmd;// new direction
break;
}
}
// not a command, but a stack entry, manage it
else
{
stk.push_back(seq_obj(i), seq_len(i), type);
// copy the program stack entry to the running stack
stack::copy_and_push_back(*this, i, stk);
i++;
}
}
return ret;
}
@ -471,7 +540,7 @@ public:
{
// for if-then-else-end
vector<struct if_layout_t> vlayout;
int layout_index=-1;// TODO remplacable par vlayout.size()-1
int layout_index=-1;
// for start-end-step
vector<int> vstartindex;
@ -505,8 +574,17 @@ public:
//fill 'end' branch of 'else'
((branch*)seq_obj(vlayout[layout_index].index_else))->arg2 = i;
else
{
//fill 'end' branch of 'then'
((branch*)seq_obj(vlayout[layout_index].index_then))->arg2 = i;
if (vlayout[layout_index].index_then != -1)
((branch*)seq_obj(vlayout[layout_index].index_then))->arg2 = i;
else
{
// error: show it
show_syntax_error("missing then before end");
return ret_syntax;
}
}
layout_index--;
}
}
@ -602,7 +680,8 @@ public:
show_syntax_error("missing start or for before next");
return ret_syntax;
}
k->arg1 = vstartindex[vstartindex.size() - 1];// fill 'next' branch1 = 'start' index
k->arg1 = vstartindex[vstartindex.size() - 1]; // 'next' arg1 = 'start' index
((branch*)seq_obj(vstartindex[vstartindex.size() - 1]))->arg2 = i; // 'for' or 'start' arg2 = 'next' index
vstartindex.pop_back();
}
else if (compare_branch(k, "step", 4))
@ -614,6 +693,7 @@ public:
return ret_syntax;
}
k->arg1 = vstartindex[vstartindex.size() - 1];// fill 'step' branch1 = 'start' index
((branch*)seq_obj(vstartindex[vstartindex.size() - 1]))->arg2 = i; // 'for' or 'start' arg2 = 'next' index
vstartindex.pop_back();
}
else if (compare_branch(k, "->", 2))
@ -637,28 +717,46 @@ public:
return ret_ok;
}
static ret_value show_error(ret_value err, string& context)
ret_value show_error()
{
cerr<<context<<": "<<ret_value_string[err]<<endl;
switch(err)
ret_value ret;
// show last recorded error
cerr<<ret_value_string[_err]<<"("<<_err<<"): "<<_err_context<<endl;
switch(_err)
{
case ret_internal:
case ret_deadly:
return ret_deadly;
ret = ret_deadly;
default:
return ret_ok;
ret = ret_ok;
}
return ret;
}
static ret_value show_error(ret_value err, char* context)
ret_value show_error(ret_value err, string& context)
{
string context_string(context);
return show_error(err, context_string);
// record error
_err = err;
_err_context = context;
return show_error();
}
static void show_syntax_error(const char* context)
ret_value show_error(ret_value err, const char* context)
{
cerr<<"syntax error: "<<context<<endl;
// record error
_err = err;
_err_context = context;
return show_error();
}
void show_syntax_error(const char* context)
{
// record error
_err = ret_syntax;
_err_context = context;
(void)show_error();
}
ret_value get_err(void) { return _err; }
@ -684,50 +782,30 @@ public:
}
}
}
static void apply_default()
{
//default float precision, float mode, verbosity
number::s_mode = number::s_default_mode;
number::s_current_precision = number::s_default_precision;
// format for mpfr_printf
stringstream ss;
ss << number::s_current_precision;
s_mpfr_printf_format = s_mpfr_printf_format_beg + ss.str() + s_mpfr_printf_format_std;
}
private:
ret_value _err;
string _err_context;
stack* _stack;
stack _branch_stack;
heap* _global_heap;
heap _local_heap;
heap* _parent_local_heap;
// helpers for keywords implementation
floating_t getf()
{
/* warning, caller must check object type before */
floating_t a = ((number*)_stack->back())->_value;
_stack->pop_back();
return a;
}
void putf(floating_t value)
{
/* warning, caller must check object type before */
number num;
num.set(value);
_stack->push_back(&num, num.size(), cmd_number);
}
integer_t getb()
{
/* warning, caller must check object type before */
integer_t a = ((binary*)_stack->back())->_value;
_stack->pop_back();
return a;
}
void putb(integer_t value)
{
/* warning, caller must check object type before */
binary num;
num.set(value);
_stack->push_back(&num, num.size(), cmd_binary);
}
int stack_size()
{
return _stack->size();
@ -741,11 +819,11 @@ private:
#define ARG_MUST_BE_OF_TYPE(num, type) do { if (_stack->get_type(num) != (type)) { ERR_CONTEXT(ret_bad_operand_type); return; } } while(0)
#define ARG_MUST_BE_OF_TYPE_RET(num, type, ret) do { if (_stack->get_type(num) != (type)) { ERR_CONTEXT(ret_bad_operand_type); return (ret); } } while(0)
#define IS_ARG_TYPE(num, type) (_stack->get_type(num) == (type))
#define CHECK_MPFR(op) do { (void)(op); } while(0)
// keywords implementation
#include "rpn-general.h"
#include "rpn-real.h"
#include "rpn-binary.h"
#include "rpn-test.h"
#include "rpn-stack.h"
#include "rpn-string.h"
@ -758,20 +836,8 @@ private:
//keywords declaration
#include "rpn-cmd.h"
#include "rpn-test-core.h"
//
static void apply_default(void)
{
//default precision
cout << setprecision(number::s_default_precision);
number::s_mode = number::s_default_mode;
//default binary mode
binary::s_mode = binary::s_default_mode;
}
//
int main(int argc, char* argv[])
{
@ -780,7 +846,7 @@ int main(int argc, char* argv[])
int ret = 0;
// apply default configuration
apply_default();
program::apply_default();
// run with interactive prompt
if (argc == 1)
@ -827,6 +893,8 @@ int main(int argc, char* argv[])
program::show_stack(global_stack, separator);
}
}
mpfr_free_cache();
return ret;
}

View file

@ -8,61 +8,101 @@
#include <map>
using namespace std;
#include "debug.h"
#define ALLOC_BLOB (2*1024)
#define LOCAL_COPY_PLACES 3
#define LOCAL_COPY_SIZE 128
// allocation base size
#define ALLOC_STACK_CHUNK (64*1024)
//
class stack
{
private:
struct local_copy
{
unsigned int length;
int type;
int blob;
};
public:
stack()
{
_base = (char*)malloc(ALLOC_BLOB);
_total_size = ALLOC_BLOB;
_current = _base;
_count = 0;
}
virtual ~stack() { free(_base); }
void push_back(void* obj, unsigned int size, int type = 0, bool dont_copy = false)
{
if (_current + size > _base + _total_size)
{
//TODO gerer les pbs de memoire
_total_size += ALLOC_BLOB;
_base = (char*)realloc(_base, _total_size);
}
if (!dont_copy)
memcpy(_current, obj, size);
_vlen.push_back(size);
_vpointer.push_back(_current);
_vtype.push_back(type);
_count++;
_current += size;
_base = NULL;
_total_size = 0;
erase();
}
void pop_back()
virtual ~stack()
{
if (_base != NULL)
free(_base);
}
void erase()
{
_current = _base;
_vpointer.clear();
_vlen.clear();
_count = 0;
}
//
static void copy_and_push_back(stack& from, unsigned int index_from, stack& to)
{
// copy a whole stack entry and push it back to another stack
object* allocated = to.allocate_back(from.seq_len(index_from), from.seq_type(index_from));
memcpy(allocated, from.seq_obj(index_from), from.seq_len(index_from));
if (allocated->_type == cmd_number)
((number*)allocated)->_value.set_significand(((number*)allocated)+1);
}
//
static void copy_and_push_back(object* from, stack& to, unsigned int size)
{
// copy a whole stack entry and push it back to another stack
object* allocated = to.allocate_back(size, from->_type);
memcpy(allocated, from, size);
if (allocated->_type == cmd_number)
((number*)allocated)->_value.set_significand(((number*)allocated)+1);
}
object* allocate_back(unsigned int size, cmd_type_t type)
{
object* allocated;
// manage memory allocation
if (_current + size > _base + _total_size)
{
unsigned long offset = _current - _base;
_total_size += ALLOC_STACK_CHUNK;
_base = (char*)realloc(_base, _total_size);
_current = _base + offset;
}
// manage stack itself
_vlen.push_back(size);
_vpointer.push_back((object*)_current);
allocated = (object*)_current;
_current += size;
_count++;
// init object
allocated->_type = type;
allocated->_size = size;
if (type == cmd_number)
((number*)allocated)->_value.init(((number*)allocated)+1);
return allocated;
}
object* pop_back()
{
object* back = NULL;
if (_count > 0)
{
_current = _vpointer[_count - 1];
_current = (char*)_vpointer[_count - 1];
_vlen.pop_back();
_vpointer.pop_back();
_vtype.pop_back();
_count--;
back = (object*)_current;
}
return back;
}
unsigned int size()
@ -71,7 +111,7 @@ public:
}
// stack access (index is counted from back)
void* get_obj(unsigned int index)
object* get_obj(unsigned int index)
{
if (index<_count)
return _vpointer[_count-index-1];
@ -79,12 +119,12 @@ public:
return NULL;
}
void* operator[](unsigned int index)
object* operator[](unsigned int index)
{
return get_obj(index);
}
void* back()
object* back()
{
if (_count>0)
return _vpointer[_count-1];
@ -100,16 +140,16 @@ public:
return 0;
}
int get_type(unsigned int index)
cmd_type_t get_type(unsigned int index)
{
if (index<_count)
return _vtype[_count-index-1];
return _vpointer[_count-index-1]->_type;
else
return 0;
return cmd_undef;
}
// sequential access (index is counted from front)
void* seq_obj(unsigned int index)
object* seq_obj(unsigned int index)
{
if (index<_count)
return _vpointer[index];
@ -125,46 +165,22 @@ public:
return 0;
}
int seq_type(unsigned int index)
cmd_type_t seq_type(unsigned int index)
{
if (index<_count)
return _vtype[index];
return _vpointer[index]->_type;
else
return 0;
}
// local objects copy
void copy_obj_to_local(unsigned int index, unsigned int to_place)
{
assert(to_place < LOCAL_COPY_PLACES);
struct local_copy* local = (struct local_copy*)_places[to_place];
local->length = get_len(index);
local->type= get_type(index);
memcpy(&local->blob, get_obj(index), local->length);
}
void push_obj_from_local(unsigned int from_place)
{
assert(from_place < LOCAL_COPY_PLACES);
struct local_copy* local = (struct local_copy*)_places[from_place];
push_back(&local->blob, local->length, local->type);
}
void dump(void)
{
dump8((unsigned char*)_base, 0, (unsigned long)(_current - _base));
return cmd_undef;
}
private:
char* _base;
char* _current;
vector<unsigned int> _vlen;// size of each entry in bytes
vector<char*> _vpointer;//pointer on each entry
vector<int> _vtype;//type of each entry
unsigned int _count;// =_vlen.size()=_vpointer.size()=_vtype.size()
unsigned int _total_size;//total allocated size in bytes
char _places[LOCAL_COPY_PLACES][LOCAL_COPY_SIZE];
vector<object*> _vpointer;//pointer on each entry
vector<unsigned int> _vlen;// size of each entry in bytes
unsigned int _count;// =_vlen.size()=_vpointer.size()
unsigned int _total_size;//total allocated size in bytes
};
//
@ -174,8 +190,7 @@ private:
struct local_var
{
unsigned int length;
int type;
int blob;
object obj[0];
};
public:
@ -186,36 +201,42 @@ public:
free(i->second);
}
void add(const string name, void* obj, unsigned int size, int type = 0)
object* add(const string name, object* obj, unsigned int size, int type = 0)
{
struct local_var* blob = _map[name];
if (blob == NULL)
struct local_var* local = _map[name];
if (local == NULL)
{
//TODO gerer les pbs de memoire
blob = (struct local_var*)malloc(size + sizeof(local_var));
_map[name] = blob;
local = (struct local_var*)malloc(size + sizeof(local_var));
_map[name] = local;
}
else if (size != blob->length)
else if (size != local->length)
{
//TODO gerer les pbs de memoire
blob = (struct local_var*)realloc(blob, size + sizeof(local_var));
_map[name] = blob;
local = (struct local_var*)realloc(local, size + sizeof(local_var));
_map[name] = local;
}
blob->length = size;
blob->type= type;
memcpy(&blob->blob, obj, size);
}
local->length = size;
bool get(const string name, void*& obj, unsigned int& size, int& type)
if (obj != NULL)
{
memcpy(local->obj, obj, size);
if (local->obj->_type == cmd_number)
((number*)local->obj)->_value.set_significand(((number*)local->obj)+1);
}
return local->obj;
}
bool get(const string name, object*& obj, unsigned int& size)
{
map<string, struct local_var*>::iterator i = _map.find(name);
if (i != _map.end())
{
if (i->second != NULL)
{
obj = &i->second->blob;
obj = i->second->obj;
size = i->second->length;
type = i->second->type;
}
return true;
}
@ -223,29 +244,46 @@ public:
return false;
}
bool replace_value(const string name, object* obj, unsigned int size)
{
bool ret=false;
map<string, struct local_var*>::iterator i = _map.find(name);
if (i != _map.end())
{
if (i->second != NULL && size==i->second->length)
{
(void)memcpy(i->second->obj, obj, size);
if (i->second->obj->_type == cmd_number)
((number*)i->second->obj)->_value.set_significand(((number*)i->second->obj)+1);
}
return true;
}
return ret;
}
bool exist(const string name)
{
return (_map.find(name) != _map.end());
}
bool get_by_index(int num, string& name, void*& obj, unsigned int& size, int& type)
bool get_by_index(int num, string& name, object*& obj, unsigned int& size)
{
if (num>=0 && num<(int)_map.size())
{
struct local_var* blob;
struct local_var* local;
map<string, struct local_var*>::iterator i=_map.begin();
//TODO moche moche moche
for(int j=0;j<num;j++)
i++;
blob = (struct local_var*)i->second;
assert(blob != NULL);
local = (struct local_var*)i->second;
assert(local != NULL);
name = i->first;
obj = &blob->blob;
size = blob->length;
type = blob->type;
obj = local->obj;
size = local->length;
return true;
}
else

View file

@ -1,19 +1,23 @@
// version and soft name
static const char version[] = "1.3.3";
static const char uname[] = "rpn v1.3.3, (c) 2013 <louis@rubet.fr>, GNU General Public License";
static const char version[] = "2.0 RC1";
static const char uname[] =
"rpn v2.0 RC1, (c) 2013 <louis@rubet.fr>, GNU LGPL v3";
static const char g_cursor[] = "> ";
static const string g_show_stack_separator = "> ";
// syntax
static const char* syntax[] = {
// description
static const char description[] =
ATTR_BOLD "R" ATTR_OFF "everse "
ATTR_BOLD "P" ATTR_OFF "olish "
ATTR_BOLD "N" ATTR_OFF "otation language, based on hewlett-Packard RPL",
"",
"Syntax: rpn [command]",
"with optional command = list of commands",
NULL
};
ATTR_BOLD "N" ATTR_OFF "otation language, based on "
"Hewlett-Packard RPL language\n\n"
"using " ATTR_BOLD "MPFR library v" ATTR_OFF MPFR_VERSION_STRING " under GNU LGPL v3\n"
"for multiple-precision floating-point computations with correct rounding\n";
// syntax
static const char syntax[] =
ATTR_BOLD "Syntax" ATTR_OFF ": rpn [command]\n"
"with optional command = list of commands";
static const char prompt[] = ATTR_BOLD "rpn" ATTR_OFF "> ";

226
test/branch.txt Normal file
View file

@ -0,0 +1,226 @@
## BRANCH
# if then else end (1)
1 if then 'ok' end
-> stack should be 'ok'
erase
# if then else end (2)
1 if 'before' then 'ok' end
-> stack should be 'before', 'ok'
erase
# if then else end (3)
0 if then 'ok' end
-> stack size should be 0
erase
# if then else end (4)
0 if then 'ok' end
-> stack size should be 0
erase
# if then else end (5)
1 if then 'ok' else 'KO' end
-> stack should be 'ok'
erase
# if then else end (6)
1 if then 'ok' 'dokey' else 'KO' end
-> stack should be 'ok', 'dokey'
erase
# if then else end (7)
0 if then 'ok' else 'KO' end
-> stack should be 'KO'
erase
# if then else end - error case (1)
if then end
-> error should be 2
erase
# if then else end - error case (2)
0 if then
-> error should be 11
erase
# if then else end - error case (3)
0 if end
-> error should be 11
erase
# if then else end - error case (4)
0 if end
-> error should be 11
erase
# if then else end - error case (5)
then
-> error should be 11
erase
# if then else end - error case (6)
1 if
-> error should be 11
erase
# if then else end - error case (7)
else
-> error should be 11
erase
# if then else end - error case (8)
end
-> error should be 11
erase
# if then else end - error case (9)
"1" if then end
-> error should be 3
erase
# start next (1)
1 2 start 0 next
-> stack should be 0, 0
erase
# start next (2)
2 1 start 0 next
-> stack size should be 0
erase
# start next (3)
-2 -1 start 0 next
-> stack should be 0, 0
erase
# start next (4)
-1 -2 start 0 next
-> stack size should be 0
erase
# start next (5)
1 1 start 0 next
-> stack should be 0
erase
# start next - error case (1)
1 start next
->error should be 2
erase
# start next - error case (2)
start next
->error should be 2
erase
# start next - error case (3)
start
->error should be 11
erase
# start next - error case (4)
next
->error should be 11
erase
# start next - error case (5)
"1" 2 start next
->error should be 3
erase
# start next - error case (5)
1 "2" start next
->error should be 3
erase
# for next (1)
23 27 for i i next
-> stack should be 23, 24, 25, 26, 27
erase
# for next (2)
1 1 for i i next
-> stack should be 1
erase
# for next (3)
27 23 for i i next
-> stack size should be 0
erase
# for next (4)
-2 -1 for i i next
-> stack should be -2, -1
erase
# for next (5)
-1 -2 for i i next
-> stack size should be 0
erase
# for next - error case (1)
1 for i i next
-> error should be 2
erase
# for next - error case (2)
for i i next
-> error should be 2
erase
# for next - error case (3)
"1" 2 for i i next
-> error should be 3
erase
# for next - error case (4)
1 "2" for i i next
-> error should be 3
erase
# for next - error case (5)
1 2 for i i
-> error should be 11
erase
# for next - error case (6)
for
-> error should be 11
erase
# for step (1)
23 27 for i i 1 step
-> stack should be 23, 24, 25, 26, 27
erase
# for step (2)
0 1 for i i 0.25 step
-> stack should be 0, 0.25, 0.5, 0.75, 1
erase
# for step (3)
-1 0 for i i 0.25 step
-> stack should be -1, -0.75, -0.5, -0.25, 0
erase
# for step (4)
0 -1 for i i 0.25 step
-> stack size should be 0
erase
# for step (5)
0 -1 for i i -0.25 step
-> stack size should be 0
erase
# for step - error case (1)
0 1 for i i "0.5" step
-> error should be 3
erase
# for step - error case (2)
step
-> error should be 11
erase

90
test/entry.txt Normal file
View file

@ -0,0 +1,90 @@
## ENTRY TEST
default
erase
# real decimal
1
-> stack size should be 1
-> stack should be 1
drop
2.345
-> stack should be 2.345
erase
1 2.345 3 4.9
-> stack size should be 4
-> stack should be 1, 2.345, 3, 4.9
# real hex
erase
0x1234
-> stack should be 4660
drop
0x10.10
-> stack should be 16.0625
# real binary
erase
0b11001100
-> stack should be 204
erase
0b11001100.1101
-> stack should be 204.8125
# real inf, nan
erase
inf
@inf@
+inf
+@inf@
-inf
-@inf@
nan
@nan@
-> stack should be inf, inf, inf, inf, -inf, -inf, nan, nan
# symbol
erase
'test'
-> stack size should be 1
-> stack should be 'test'
erase
'test
-> stack size should be 1
-> stack should be 'test'
erase
''
-> stack size should be 1
-> stack should be ''
# string
erase
"test string"
-> stack size should be 1
-> stack should be "test string"
erase
"test string
-> stack size should be 1
-> stack should be "test string"
# program
erase
<< 'one' >>
-> stack size should be 1
-> stack should be << 'one' >>
erase
<< 'one' 2
-> stack size should be 1
-> stack should be << 'one' 2 >>
erase
<< -> n << n 2 + >> >>
-> stack size should be 1
-> stack should be << -> n << n 2 + >> >>

33
test/general.txt Normal file
View file

@ -0,0 +1,33 @@
## GENERAL
# version
version
-> stack size should be 1
uname
-> stack size should be 2
erase
# type
1
type
-> stack should be 1, 'number'
erase
"hey"
type
-> stack should be "hey", 'string'
erase
<< -> n << n >> >>
type
-> stack should be << -> n << n >> >>, 'program'
erase
# default
2 sci
1
-> stack should be 1.00e+00
default
-> stack should be 1
erase

View file

@ -0,0 +1,32 @@
## REAL representation
# std
erase
1
10 std
-> stack should be 1
3 /
-> stack should be 0.3333333333
3 std
-> stack should be 0.333
# fix
drop
10 fix
1
-> stack should be 1.0000000000
4 fix
-> stack should be 1.0000
# sci
12 sci
-> stack should be 1.000000000000e+00
2 sci
-> stack should be 1.00e+00
drop
default

67
test/stack.txt Normal file
View file

@ -0,0 +1,67 @@
## STACK TEST
# entry depth 1
1
-> stack size should be 1
# entry depth 2
2 3
-> stack size should be 3
-> stack should be 1, 2, 3
# drop
drop
-> stack size should be 2
# drop2
drop2
-> stack size should be 0
# drop error
drop
-> error should be 2
# drop2 error
drop2
-> error should be 2
# drop2 error
1 drop2
-> error should be 2
drop
# test dup
1 dup
-> stack size should be 2
-> stack should be 1, 1
# test dup2
drop 2 dup2
-> stack size should be 4
-> stack should be 1, 2, 1, 2
drop2 drop2
# test rot
1 2 3 rot
-> stack size should be 3
-> stack should be 2, 3, 1
erase
# test depth
1 2 3
depth
-> stack size should be 4
-> stack should be 1, 2, 3, 3
erase
# test pick
1 2 3 4 2 pick
-> stack size should be 5
-> stack should be 1, 2, 3, 4, 3
0 pick
-> error should be 4
7 pick
-> error should be 4
# test erase
erase
-> stack size should be 0

90
test/string.txt Normal file
View file

@ -0,0 +1,90 @@
## STRING
default
erase
# ->str on real (1)
1
->str
-> stack should be "1"
drop
# ->str on real (2)
1.234
25 std
->str
-> stack should be "1.234"
drop
# ->str on real (3)
1.234
20 fix
->str
-> stack should be "1.23400000000000000000"
drop
# ->str on symbol (1)
toto
->str
-> stack should be "'toto'"
drop
# ->str on symbol (2)
'toto'
->str
-> stack should be "'toto'"
drop
default
# str-> on real (1)
"1"
str->
-> stack should be 1
drop
# str-> on real (2)
"1 2.345 3 4.9"
str->
-> stack should be 1, 2.345, 3, 4.9
erase
# str-> on real (3)
4 fix
"1 2.345 3 4.9"
str->
-> stack should be 1.0000, 2.3450, 3.0000, 4.9000
erase
default
# str-> on constant (1)
"pi"
str->
-> stack should be 3.141592653589793238462643
erase
# str-> on constant (2)
"'pi' 'e'"
str->
-> stack should be 'pi', 'e'
erase
# str-> on command (1)
"2 dup"
str->
-> stack should be 2, 2
erase
# str-> on command (2)
"3.14 my_pi sto"
str->
-> stack size should be 0
my_pi
-> stack should be 3.14
erase
# str-> on program
"<< -> n << n >> >>"
str->
-> stack should be << -> n << n >> >>
erase

View file

@ -1,327 +1,175 @@
## 1 ## ENTRY and STACK
# test entry 1
1
-> stack size should be 1
# test entry 2
2 3
-> stack size should be 3
-> stack should be 3, 2, 1
# test drop
drop
-> stack size should be 2
# test drop2
drop2
-> stack size should be 0
# test drop error
drop
-> error should be 2
# test drop2 error
drop2
-> error should be 2
# test drop2 error
1 drop2
-> error should be 2
drop
# test symbol entry 1
1 '2'
-> stack size should be 2
-> stack should be '2', 1
drop2
# test symbol entry 2
1 '2
-> stack size should be 2
-> stack should be '2', 1
drop2
# test symbol entry 3
''
-> stack should be ''
drop
# test symbol entry 4
'
-> stack should be ''
drop
# test dup
1 dup
-> stack size should be 2
-> stack should be 1, 1
# test dup2
drop 2 dup2
-> stack size should be 4
-> stack should be 2, 1, 2, 1
drop2 drop2
# test rot
1 2 3 rot
-> stack size should be 3
-> stack should be 1, 3, 2
# test depth
depth
-> stack size should be 4
-> stack should be 3, 1, 3, 2
drop2 drop2
# test pick
1 2 3 4 2 pick
-> stack size should be 5
-> stack should be 3, 4, 3, 2, 1
# test erase
erase
-> stack size should be 0
## 2 ## TEST
# and
## TESTS
# and (1)
and
-> error should be 2
1 and
-> error should be 2
drop
# and (2)
0 0 and
-> stack size should be 1
-> stack should be 0
drop
# and (3)
1 0 and
-> stack size should be 1
-> stack should be 0
drop
# and (4)
0 1 and
-> stack size should be 1
-> stack should be 0
drop
# and (5)
1 1 and
-> stack size should be 1
-> stack should be 1
drop
# or
# or (1)
or
-> error should be 2
1 or
-> error should be 2
drop
# or (2)
0 0 or
-> stack size should be 1
-> stack should be 0
drop
# or (3)
0 1 or
-> stack size should be 1
-> stack should be 1
drop
# or (4)
1 0 or
-> stack size should be 1
-> stack should be 1
drop
# or (5)
1 1 or
-> stack size should be 1
-> stack should be 1
drop
# xor
# xor (1)
xor
-> error should be 2
1 xor
-> error should be 2
drop
# xor (2)
0 0 xor
-> stack size should be 1
-> stack should be 0
drop
# xor (3)
0 1 xor
-> stack size should be 1
-> stack should be 1
drop
# xor (4)
1 0 xor
-> stack size should be 1
-> stack should be 1
drop
# xor (5)
1 1 xor
-> stack size should be 1
-> stack should be 0
drop
## 3 ## BRANCH
# if-then-else-end test 1
1 if then 'ok' end
-> stack size should be 1
-> stack should be 'ok'
drop
# if-then-else-end test 2
0 if then 'ok' end
-> stack size should be 0
# if-then-else-end test 3
1 if 0 1 then 'ok' end
-> stack size should be 3
-> stack should be 'ok', 1, 0
drop2 drop
# if-then-else-end test 4
1 if then 'ok' else 0 end
-> stack size should be 1
-> stack should be 'ok'
drop
# if-then-else-end test 5
0 if then 'ok' else 0 end
# not (1)
not
-> error should be 2
1 not
-> stack size should be 1
-> stack should be 0
drop
# if-then-else-end test 6
1 if then 1 if then 'ok' else 0 end end
-> stack size should be 1
-> stack should be 'ok'
drop
# if-then-else-end test 7
1 if then 0 if then 'ok' else 0 end end
-> stack size should be 1
-> stack should be 0
drop
# if-then-else-end test 8
0 if then 0 if then 'ok' else 0 end else 'OK' end
-> stack size should be 1
-> stack should be 'OK'
drop
# start-next-step test 1
1 3 start 'ok' next
-> stack size should be 3
-> stack should be 'ok', 'ok', 'ok'
drop drop2
# start-next-step test 2
3 1 start 'ok' next
-> stack size should be 1
-> stack should be 'ok'
drop
# start-next-step test 3
-1 0 start 'ok' next
-> stack size should be 2
-> stack should be 'ok', 'ok'
drop2
# start-next-step test 4
0 4 start 'ok' 2 step
-> stack size should be 3
-> stack should be 'ok', 'ok', 'ok'
drop2 drop
# start-next-step test 5
0 -2 start 'ok' -1 step
-> stack size should be 3
-> stack should be 'ok', 'ok', 'ok'
drop2 drop
# start-next-step test 6
0 0.2 start 'ok' 0.1 step
-> stack size should be 3
-> stack should be 'ok', 'ok', 'ok'
drop2 drop
# for-next-step test 1
1 3 for i i next
-> stack size should be 3
-> stack should be 3, 2, 1
drop drop2
# for-next-step test 2
3 1 for i i next
-> stack size should be 1
-> stack should be 3
drop
# for-next-step test 3
-1 0 for i i next
-> stack size should be 2
-> stack should be 0, -1
drop2
# for-next-step test 4
0 4 for i i 2 step
-> stack size should be 3
-> stack should be 4, 2, 0
drop2 drop
# for-next-step test 5
0 -2 for i i -1 step
-> stack size should be 3
-> stack should be -2, -1, 0
drop2 drop
# for-next-step test 6
0 0.2 for i i 0.1 step
-> stack size should be 3
-> stack should be 0.2, 0.1, 0
drop2 drop
# for-next-step test 7
1 2 for i 10 20 for j i j + 10 step next
-> stack size should be 4
-> stack should be 22, 12, 21, 11
drop2 drop2
## 4 ## STORE
# sto test 1
1 'a' sto
-> stack size should be 0
# rcl test 1
'a' rcl
# not (2)
0 not
-> stack size should be 1
-> stack should be 1
drop
# sto test 2
'toto' 'b' sto
-> stack size should be 0
# rcl test 2
'b' rcl
-> stack size should be 1
-> stack should be 'toto'
# >
0 0.1 >
-> stack should be 0
drop
0.1 0 >
-> stack should be 1
drop
1 1 >
-> stack should be 0
drop
# sto/rcl test 1
'b' rcl 'a' sto 'a' rcl
-> stack size should be 1
-> stack should be 'toto'
# >=
0 0.1 >=
-> stack should be 0
drop
0.1 0 >=
-> stack should be 1
drop
1 1 >=
-> stack should be 1
drop
# purge test 1
'a' purge 'b' purge
-> stack size should be 0
# auto-eval test 1
1 'a' sto 1 3 start 1 a + 'a' sto next a
-> stack size should be 1
-> stack should be 4
# <
0 0.1 <
-> stack should be 1
drop
0.1 0 <
-> stack should be 0
drop
1 1 <
-> stack should be 0
drop
# <=
0 0.1 <=
-> stack should be 1
drop
0.1 0 <=
-> stack should be 0
drop
1 1 <=
-> stack should be 1
drop
# !=
0 0.1 !=
-> stack should be 1
drop
1 1 !=
-> stack should be 0
drop
# ==
0 0.1 ==
-> stack should be 0
drop
1 1 ==
-> stack should be 1
drop
# same
0 0.1 same
-> stack should be 0
drop
1 1 same
-> stack should be 1
drop