Merge pull request #4612 from ridiculousfish/muparser-no-except

Muparser Exceptectomy

This removes large pieces of muParser that fish does not use, such as its optimizer. It also switches muParser from throwing exceptions to propagating errors explicitly.
This commit is contained in:
ridiculousfish 2017-12-19 09:34:32 -08:00 committed by GitHub
commit ec2b38053e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 4972 additions and 9011 deletions

1
.gitignore vendored
View file

@ -90,6 +90,7 @@ messages.pot
/muparser-*/bk-deps
/muparser-*/shared-ld-sh
/muparser-*/build/autoconf/muparser.pc
/muparser-2.2.5/samples/example1/example1
/pcre2-*/configure.lineno
# xcode

View file

@ -4,6 +4,9 @@ PROJECT(fish-shell CXX)
# We are C++11.
SET(CMAKE_CXX_STANDARD 11)
# Disable exception handling.
ADD_COMPILE_OPTIONS(-fno-exceptions)
# Hide the CMake Rules directories in Xcode projects.
SOURCE_GROUP("CMake Rules" REGULAR_EXPRESSION "^$")

View file

@ -29,7 +29,7 @@ if test $all = yes
echo
exit 1
end
set c_files src/*.h src/*.cpp
set c_files src/*.h src/*.cpp muparser-2.2.5/src/*.cpp muparser-2.2.5/include/*.h
# For now we don't restyle all fish scripts other than completion scripts. That's because people
# really like to vertically align the elements of the `complete` command and fish_indent
# currently does not honor that whitespace.

View file

@ -212,11 +212,8 @@ AS_IF([test "$use_doxygen" != "no"],
AC_SYS_LARGEFILE
# Fish does not use exceptions itself. However the MuParser library does so we
# need to enable support for them and pay the cost of larger code. Note:
# Enabling exceptions increases the compiled code size but to avoid that we
# would have to maintain our own patches to the MuParser code.
#CXXFLAGS="$CXXFLAGS -fno-exceptions"
# Fish does not use exceptions.
CXXFLAGS="$CXXFLAGS -fno-exceptions"
#
# Set some warning flags

View file

@ -376,10 +376,8 @@
D068222B1F5149B500040321 /* muParserBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D06822221F51498700040321 /* muParserBase.cpp */; };
D068222C1F5149B500040321 /* muParserBytecode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D06822231F51498700040321 /* muParserBytecode.cpp */; };
D068222D1F5149B500040321 /* muParserCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D06822241F51498700040321 /* muParserCallback.cpp */; };
D068222E1F5149B500040321 /* muParserDLL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D06822251F51498700040321 /* muParserDLL.cpp */; };
D068222F1F5149B500040321 /* muParserError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D06822261F51498700040321 /* muParserError.cpp */; };
D06822301F5149B500040321 /* muParserInt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D06822271F51498700040321 /* muParserInt.cpp */; };
D06822311F5149B500040321 /* muParserTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D06822281F51498700040321 /* muParserTest.cpp */; };
D06822321F5149B500040321 /* muParserTokenReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D06822291F51498700040321 /* muParserTokenReader.cpp */; };
D07B247315BCC15700D4ADB4 /* add-shell in Resources */ = {isa = PBXBuildFile; fileRef = D07B247215BCC15700D4ADB4 /* add-shell */; };
D07B247615BCC4BE00D4ADB4 /* install.sh in Resources */ = {isa = PBXBuildFile; fileRef = D07B247515BCC4BE00D4ADB4 /* install.sh */; };
@ -806,12 +804,7 @@
D06821FD1F51498700040321 /* muParserBytecode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserBytecode.h; sourceTree = "<group>"; };
D06821FE1F51498700040321 /* muParserCallback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserCallback.h; sourceTree = "<group>"; };
D06821FF1F51498700040321 /* muParserDef.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserDef.h; sourceTree = "<group>"; };
D06822001F51498700040321 /* muParserDLL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserDLL.h; sourceTree = "<group>"; };
D06822011F51498700040321 /* muParserError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserError.h; sourceTree = "<group>"; };
D06822021F51498700040321 /* muParserFixes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserFixes.h; sourceTree = "<group>"; };
D06822031F51498700040321 /* muParserInt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserInt.h; sourceTree = "<group>"; };
D06822041F51498700040321 /* muParserStack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserStack.h; sourceTree = "<group>"; };
D06822051F51498700040321 /* muParserTemplateMagic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserTemplateMagic.h; sourceTree = "<group>"; };
D06822061F51498700040321 /* muParserTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserTest.h; sourceTree = "<group>"; };
D06822071F51498700040321 /* muParserToken.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserToken.h; sourceTree = "<group>"; };
D06822081F51498700040321 /* muParserTokenReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = muParserTokenReader.h; sourceTree = "<group>"; };
@ -819,10 +812,8 @@
D06822221F51498700040321 /* muParserBase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = muParserBase.cpp; sourceTree = "<group>"; };
D06822231F51498700040321 /* muParserBytecode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = muParserBytecode.cpp; sourceTree = "<group>"; };
D06822241F51498700040321 /* muParserCallback.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = muParserCallback.cpp; sourceTree = "<group>"; };
D06822251F51498700040321 /* muParserDLL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = muParserDLL.cpp; sourceTree = "<group>"; };
D06822261F51498700040321 /* muParserError.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = muParserError.cpp; sourceTree = "<group>"; };
D06822271F51498700040321 /* muParserInt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = muParserInt.cpp; sourceTree = "<group>"; };
D06822281F51498700040321 /* muParserTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = muParserTest.cpp; sourceTree = "<group>"; };
D06822291F51498700040321 /* muParserTokenReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = muParserTokenReader.cpp; sourceTree = "<group>"; };
D07B247215BCC15700D4ADB4 /* add-shell */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = "add-shell"; path = "build_tools/osx_package_scripts/add-shell"; sourceTree = "<group>"; };
D07B247515BCC4BE00D4ADB4 /* install.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = install.sh; path = osx/install.sh; sourceTree = "<group>"; };
@ -1059,12 +1050,7 @@
D06821FD1F51498700040321 /* muParserBytecode.h */,
D06821FE1F51498700040321 /* muParserCallback.h */,
D06821FF1F51498700040321 /* muParserDef.h */,
D06822001F51498700040321 /* muParserDLL.h */,
D06822011F51498700040321 /* muParserError.h */,
D06822021F51498700040321 /* muParserFixes.h */,
D06822031F51498700040321 /* muParserInt.h */,
D06822041F51498700040321 /* muParserStack.h */,
D06822051F51498700040321 /* muParserTemplateMagic.h */,
D06822061F51498700040321 /* muParserTest.h */,
D06822071F51498700040321 /* muParserToken.h */,
D06822081F51498700040321 /* muParserTokenReader.h */,
@ -1079,10 +1065,8 @@
D06822221F51498700040321 /* muParserBase.cpp */,
D06822231F51498700040321 /* muParserBytecode.cpp */,
D06822241F51498700040321 /* muParserCallback.cpp */,
D06822251F51498700040321 /* muParserDLL.cpp */,
D06822261F51498700040321 /* muParserError.cpp */,
D06822271F51498700040321 /* muParserInt.cpp */,
D06822281F51498700040321 /* muParserTest.cpp */,
D06822291F51498700040321 /* muParserTokenReader.cpp */,
);
path = src;
@ -1927,10 +1911,8 @@
D068222B1F5149B500040321 /* muParserBase.cpp in Sources */,
D068222C1F5149B500040321 /* muParserBytecode.cpp in Sources */,
D068222D1F5149B500040321 /* muParserCallback.cpp in Sources */,
D068222E1F5149B500040321 /* muParserDLL.cpp in Sources */,
D068222F1F5149B500040321 /* muParserError.cpp in Sources */,
D06822301F5149B500040321 /* muParserInt.cpp in Sources */,
D06822311F5149B500040321 /* muParserTest.cpp in Sources */,
D06822321F5149B500040321 /* muParserTokenReader.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -2432,6 +2414,7 @@
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = YES;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_NO_COMMON_BLOCKS = YES;
@ -2485,6 +2468,7 @@
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = YES;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_NO_COMMON_BLOCKS = YES;

View file

@ -3,7 +3,6 @@ SET(MUPARSER_SRCS
${CMAKE_CURRENT_LIST_DIR}/src/muParserBase.cpp
${CMAKE_CURRENT_LIST_DIR}/src/muParserBytecode.cpp
${CMAKE_CURRENT_LIST_DIR}/src/muParserCallback.cpp
${CMAKE_CURRENT_LIST_DIR}/src/muParserDLL.cpp
${CMAKE_CURRENT_LIST_DIR}/src/muParserError.cpp
${CMAKE_CURRENT_LIST_DIR}/src/muParserInt.cpp
${CMAKE_CURRENT_LIST_DIR}/src/muParserTokenReader.cpp)

View file

@ -43,13 +43,12 @@ LDFLAGS = @LDFLAGS@
DESTDIR =
MUPARSER_LIB_CXXFLAGS = $(____DEBUG) $(____SHARED) $(____SHARED_0) \
-I$(srcdir)/include $(CPPFLAGS) $(CXXFLAGS)
-I$(srcdir)/include $(CPPFLAGS) $(CXXFLAGS) -std=c++11
MUPARSER_LIB_OBJECTS = \
muParser_lib_muParser.o \
muParser_lib_muParserBase.o \
muParser_lib_muParserBytecode.o \
muParser_lib_muParserCallback.o \
muParser_lib_muParserDLL.o \
muParser_lib_muParserError.o \
muParser_lib_muParserInt.o \
muParser_lib_muParserTest.o \
@ -59,44 +58,12 @@ MUPARSER_LIB_HEADERS = \
include/muParserBase.h \
include/muParserBytecode.h \
include/muParserCallback.h \
include/muParserDLL.h \
include/muParserDef.h \
include/muParserError.h \
include/muParserFixes.h \
include/muParserInt.h \
include/muParserStack.h \
include/muParserTemplateMagic.h \
include/muParserTest.h \
include/muParserToken.h \
include/muParserTokenReader.h
MUPARSER_DLL_CXXFLAGS = $(____DEBUG) $(____SHARED) $(____SHARED_0) \
-I$(srcdir)/include $(PIC_FLAG) $(CPPFLAGS) $(CXXFLAGS)
MUPARSER_DLL_OBJECTS = \
muParser_dll_muParser.o \
muParser_dll_muParserBase.o \
muParser_dll_muParserBytecode.o \
muParser_dll_muParserCallback.o \
muParser_dll_muParserDLL.o \
muParser_dll_muParserError.o \
muParser_dll_muParserInt.o \
muParser_dll_muParserTest.o \
muParser_dll_muParserTokenReader.o
MUPARSER_DLL_HEADERS = \
include/muParser.h \
include/muParserBase.h \
include/muParserBytecode.h \
include/muParserCallback.h \
include/muParserDLL.h \
include/muParserDef.h \
include/muParserError.h \
include/muParserFixes.h \
include/muParserInt.h \
include/muParserStack.h \
include/muParserTemplateMagic.h \
include/muParserTest.h \
include/muParserToken.h \
include/muParserTokenReader.h
EXAMPLE1_CXXFLAGS = $(____DEBUG) -I$(srcdir)/include $(CPPFLAGS) $(CXXFLAGS)
EXAMPLE1_CXXFLAGS = $(____DEBUG) -I$(srcdir)/include $(CPPFLAGS) $(CXXFLAGS) -std=c++11
EXAMPLE1_OBJECTS = \
example1_example1.o
@ -106,17 +73,13 @@ EXAMPLE1_OBJECTS = \
@COND_DEPS_TRACKING_1@CXXC = $(BK_DEPS) $(CXX)
@COND_DEBUG_0@DEBUG_BUILD_POSTFIX =
@COND_DEBUG_1@DEBUG_BUILD_POSTFIX = d
@COND_SHARED_0@__muParser_lib___depname = \
@COND_SHARED_0@ $(top_builddir)/lib/$(LIBPREFIX)muparser$(DEBUG_BUILD_POSTFIX)$(LIBEXT)
__muParser_lib___depname = $(top_builddir)/lib/$(LIBPREFIX)muparser$(DEBUG_BUILD_POSTFIX)$(LIBEXT)
@COND_SHARED_0@__install_muParser_lib___depname = install_muParser_lib
@COND_SHARED_0@__uninstall_muParser_lib___depname = uninstall_muParser_lib
@COND_SHARED_0@__install_muParser_lib_headers___depname = \
@COND_SHARED_0@ install_muParser_lib_headers
@COND_SHARED_0@__uninstall_muParser_lib_headers___depname = \
@COND_SHARED_0@ uninstall_muParser_lib_headers
COND_SHARED_1___muParser_dll___depname = \
$(top_builddir)/lib/$(DLLPREFIX)muparser$(DEBUG_BUILD_POSTFIX)$(__muParser_dll___targetsuf3)
@COND_SHARED_1@__muParser_dll___depname = $(COND_SHARED_1___muParser_dll___depname)
@COND_SHARED_1@__install_muParser_dll___depname = install_muParser_dll
@COND_SHARED_1@__uninstall_muParser_dll___depname = uninstall_muParser_dll
COND_PLATFORM_MACOSX_1___muParser_dll___macinstnamecmd = -install_name \
@ -194,8 +157,7 @@ COND_USE_SOTWOSYMLINKS_1___muParser_dll___so_symlinks_uninst_cmd = rm -f \
@COND_USE_SOVERSOLARIS_1@ $(LIBPREFIX)muparser$(DEBUG_BUILD_POSTFIX).$(DLLIMP_SUFFIX)
@COND_PLATFORM_MACOSX_1@__muParser_dll___macver = \
@COND_PLATFORM_MACOSX_1@ -compatibility_version 1 -current_version 1
@COND_SAMPLES_1@__example1___depname = \
@COND_SAMPLES_1@ $(top_builddir)/samples/example1/example1$(EXEEXT)
__example1___depname = $(top_builddir)/samples/example1/example1$(EXEEXT)
@COND_PLATFORM_MAC_0@__example1___mac_setfilecmd = @true
@COND_PLATFORM_MAC_1@__example1___mac_setfilecmd = \
@COND_PLATFORM_MAC_1@ $(SETFILE) -t APPL \
@ -204,12 +166,12 @@ COND_USE_SOTWOSYMLINKS_1___muParser_dll___so_symlinks_uninst_cmd = rm -f \
@COND_SHARED_1@____SHARED = -DMUPARSER_DLL
@COND_SHARED_0@____SHARED_0 =
@COND_SHARED_1@____SHARED_0 = -DMUPARSERLIB_EXPORTS
@COND_DEBUG_0@____DEBUG = -DNDEBUG
@COND_DEBUG_0@____DEBUG =
@COND_DEBUG_1@____DEBUG =
### Targets: ###
all: $(__muParser_lib___depname) $(__muParser_dll___depname) $(__example1___depname)
all: $(__muParser_lib___depname) $(__example1___depname)
install: $(__install_muParser_lib___depname) $(__install_muParser_lib_headers___depname) $(__install_muParser_dll___depname) $(__install_muParser_dll_headers___depname)
$(INSTALL_DIR) $(DESTDIR)$(libdir)/pkgconfig
@ -259,12 +221,9 @@ distclean: clean
@COND_SHARED_0@ rm -f $(DESTDIR)$(prefix)/$$f; \
@COND_SHARED_0@ done
@COND_SHARED_1@$(top_builddir)/lib/$(DLLPREFIX)muparser$(DEBUG_BUILD_POSTFIX)$(__muParser_dll___targetsuf3): $(MUPARSER_DLL_OBJECTS)
@COND_SHARED_1@ $(SHARED_LD_CXX) $@ $(MUPARSER_DLL_OBJECTS) $(__muParser_dll___macinstnamecmd) $(__muParser_dll___importlib) $(__muParser_dll___soname_flags) $(__muParser_dll___macver) $(LDFLAGS) $(LIBS)
@COND_SHARED_1@
@COND_SHARED_1@ $(__muParser_dll___so_symlinks_cmd)
@COND_SHARED_1@install_muParser_dll: $(__muParser_dll___depname)
@COND_SHARED_1@ $(INSTALL_DIR) $(DESTDIR)$(libdir)
@COND_SHARED_1@ $(INSTALL_DATA) $(top_builddir)/lib/$(LIBPREFIX)muparser$(DEBUG_BUILD_POSTFIX).$(DLLIMP_SUFFIX) $(DESTDIR)$(libdir)
@COND_SHARED_1@ $(INSTALL_PROGRAM) $(top_builddir)/lib/$(DLLPREFIX)muparser$(DEBUG_BUILD_POSTFIX)$(__muParser_dll___targetsuf3) $(DESTDIR)$(libdir)
@ -275,26 +234,12 @@ distclean: clean
@COND_SHARED_1@ rm -f $(DESTDIR)$(libdir)/$(DLLPREFIX)muparser$(DEBUG_BUILD_POSTFIX)$(__muParser_dll___targetsuf3)
@COND_SHARED_1@ (cd $(DESTDIR)$(libdir) ; $(__muParser_dll___so_symlinks_uninst_cmd))
@COND_SHARED_1@install_muParser_dll_headers:
@COND_SHARED_1@ $(INSTALL_DIR) $(DESTDIR)$(prefix)
@COND_SHARED_1@ for f in $(MUPARSER_DLL_HEADERS); do \
@COND_SHARED_1@ if test ! -d $(DESTDIR)$(prefix)/`dirname $$f` ; then \
@COND_SHARED_1@ $(INSTALL_DIR) $(DESTDIR)$(prefix)/`dirname $$f`; \
@COND_SHARED_1@ fi; \
@COND_SHARED_1@ $(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(prefix)/$$f; \
@COND_SHARED_1@ done
@COND_SHARED_1@uninstall_muParser_dll_headers:
@COND_SHARED_1@ for f in $(MUPARSER_DLL_HEADERS); do \
@COND_SHARED_1@ rm -f $(DESTDIR)$(prefix)/$$f; \
@COND_SHARED_1@ done
@COND_SAMPLES_1@$(top_builddir)/samples/example1/example1$(EXEEXT): $(EXAMPLE1_OBJECTS) $(__muParser_lib___depname)
@COND_SAMPLES_1@ $(CXX) -o $@ $(EXAMPLE1_OBJECTS) -L$(top_builddir)/lib -L$(srcdir)/lib $(LDFLAGS) -lmuparser$(DEBUG_BUILD_POSTFIX) $(LIBS)
@COND_SAMPLES_1@
@COND_SAMPLES_1@ $(__example1___mac_setfilecmd)
lib: $(__muParser_lib___depname) $(__muParser_dll___depname)
lib: $(__muParser_lib___depname)
samples: $(__example1___depname)
@ -328,33 +273,6 @@ muParser_lib_muParserTest.o: $(srcdir)/src/muParserTest.cpp
muParser_lib_muParserTokenReader.o: $(srcdir)/src/muParserTokenReader.cpp
$(CXXC) -c -o $@ $(MUPARSER_LIB_CXXFLAGS) $(srcdir)/src/muParserTokenReader.cpp
muParser_dll_muParser.o: $(srcdir)/src/muParser.cpp
$(CXXC) -c -o $@ $(MUPARSER_DLL_CXXFLAGS) $(srcdir)/src/muParser.cpp
muParser_dll_muParserBase.o: $(srcdir)/src/muParserBase.cpp
$(CXXC) -c -o $@ $(MUPARSER_DLL_CXXFLAGS) $(srcdir)/src/muParserBase.cpp
muParser_dll_muParserBytecode.o: $(srcdir)/src/muParserBytecode.cpp
$(CXXC) -c -o $@ $(MUPARSER_DLL_CXXFLAGS) $(srcdir)/src/muParserBytecode.cpp
muParser_dll_muParserCallback.o: $(srcdir)/src/muParserCallback.cpp
$(CXXC) -c -o $@ $(MUPARSER_DLL_CXXFLAGS) $(srcdir)/src/muParserCallback.cpp
muParser_dll_muParserDLL.o: $(srcdir)/src/muParserDLL.cpp
$(CXXC) -c -o $@ $(MUPARSER_DLL_CXXFLAGS) $(srcdir)/src/muParserDLL.cpp
muParser_dll_muParserError.o: $(srcdir)/src/muParserError.cpp
$(CXXC) -c -o $@ $(MUPARSER_DLL_CXXFLAGS) $(srcdir)/src/muParserError.cpp
muParser_dll_muParserInt.o: $(srcdir)/src/muParserInt.cpp
$(CXXC) -c -o $@ $(MUPARSER_DLL_CXXFLAGS) $(srcdir)/src/muParserInt.cpp
muParser_dll_muParserTest.o: $(srcdir)/src/muParserTest.cpp
$(CXXC) -c -o $@ $(MUPARSER_DLL_CXXFLAGS) $(srcdir)/src/muParserTest.cpp
muParser_dll_muParserTokenReader.o: $(srcdir)/src/muParserTokenReader.cpp
$(CXXC) -c -o $@ $(MUPARSER_DLL_CXXFLAGS) $(srcdir)/src/muParserTokenReader.cpp
example1_example1.o: $(srcdir)/samples/example1/example1.cpp
$(CXXC) -c -o $@ $(EXAMPLE1_CXXFLAGS) $(srcdir)/samples/example1/example1.cpp

View file

@ -3569,11 +3569,12 @@ $as_echo "no" >&6; }
fi
# Check whether --enable-shared was given.
if test "${enable_shared+set}" = set; then :
enableval=$enable_shared;
else
enableval="$default"
fi
# fish: disabled
# if test "${enable_shared+set}" = set; then :
# enableval=$enable_shared;
# else
# enableval="$default"
# fi

View file

@ -1,26 +1,26 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2013 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_H
#define MU_PARSER_H
@ -30,86 +30,75 @@
//--- Parser includes --------------------------------------------------------------------------
#include "muParserBase.h"
#include "muParserTemplateMagic.h"
/** \file
\brief Definition of the standard floating point parser.
*/
namespace mu
{
/** \brief Mathematical expressions parser.
Standard implementation of the mathematical expressions parser.
Can be used as a reference implementation for subclassing the parser.
namespace mu {
/** \brief Mathematical expressions parser.
<small>
(C) 2011 Ingo Berg<br>
muparser(at)beltoforion.de
</small>
*/
/* final */ class Parser : public ParserBase
{
public:
Standard implementation of the mathematical expressions parser.
Can be used as a reference implementation for subclassing the parser.
<small>
(C) 2011 Ingo Berg<br>
muparser(at)beltoforion.de
</small>
*/
/* final */ class Parser : public ParserBase {
public:
Parser();
virtual void InitCharSets();
virtual void InitFun();
virtual void InitConst();
virtual void InitOprt();
virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd);
value_type Diff(value_type *a_Var,
value_type a_fPos,
value_type a_fEpsilon = 0) const;
protected:
protected:
// Trigonometric functions
static value_type Sin(value_type);
static value_type Cos(value_type);
static value_type Tan(value_type);
static value_type Tan2(value_type, value_type);
static ValueOrError Sin(value_type);
static ValueOrError Cos(value_type);
static ValueOrError Tan(value_type);
static ValueOrError Tan2(value_type, value_type);
// arcus functions
static value_type ASin(value_type);
static value_type ACos(value_type);
static value_type ATan(value_type);
static value_type ATan2(value_type, value_type);
static ValueOrError ASin(value_type);
static ValueOrError ACos(value_type);
static ValueOrError ATan(value_type);
static ValueOrError ATan2(value_type, value_type);
// hyperbolic functions
static value_type Sinh(value_type);
static value_type Cosh(value_type);
static value_type Tanh(value_type);
static ValueOrError Sinh(value_type);
static ValueOrError Cosh(value_type);
static ValueOrError Tanh(value_type);
// arcus hyperbolic functions
static value_type ASinh(value_type);
static value_type ACosh(value_type);
static value_type ATanh(value_type);
static ValueOrError ASinh(value_type);
static ValueOrError ACosh(value_type);
static ValueOrError ATanh(value_type);
// Logarithm functions
static value_type Log2(value_type); // Logarithm Base 2
static value_type Log10(value_type); // Logarithm Base 10
static value_type Ln(value_type); // Logarithm Base e (natural logarithm)
static ValueOrError Log2(value_type); // Logarithm Base 2
static ValueOrError Log10(value_type); // Logarithm Base 10
static ValueOrError Ln(value_type); // Logarithm Base e (natural logarithm)
// misc
static value_type Exp(value_type);
static value_type Abs(value_type);
static value_type Sqrt(value_type);
static value_type Rint(value_type);
static value_type Sign(value_type);
static ValueOrError Exp(value_type);
static ValueOrError Abs(value_type);
static ValueOrError Sqrt(value_type);
static ValueOrError Rint(value_type);
static ValueOrError Sign(value_type);
// Prefix operators
// !!! Unary Minus is a MUST if you want to use negative signs !!!
static value_type UnaryMinus(value_type);
static value_type UnaryPlus(value_type);
static ValueOrError UnaryMinus(value_type);
static ValueOrError UnaryPlus(value_type);
// Functions with variable number of arguments
static value_type Sum(const value_type*, int); // sum
static value_type Avg(const value_type*, int); // mean value
static value_type Min(const value_type*, int); // minimum
static value_type Max(const value_type*, int); // maximum
static ValueOrError Sum(const value_type *, int); // sum
static ValueOrError Avg(const value_type *, int); // mean value
static ValueOrError Min(const value_type *, int); // minimum
static ValueOrError Max(const value_type *, int); // maximum
static int IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal);
};
} // namespace mu
static int IsVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal);
};
} // namespace mu
#endif

View file

@ -1,49 +1,45 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2013 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_BASE_H
#define MU_PARSER_BASE_H
//--- Standard includes ------------------------------------------------------------------------
#include <limits.h>
#include <cmath>
#include <string>
#include <iostream>
#include <locale>
#include <map>
#include <memory>
#include <locale>
#include <limits.h>
#include <string>
//--- Parser includes --------------------------------------------------------------------------
#include "muParserDef.h"
#include "muParserStack.h"
#include "muParserTokenReader.h"
#include "muParserBytecode.h"
#include "muParserError.h"
#include "muParserDef.h"
#include "muParserTokenReader.h"
namespace mu
{
namespace mu {
/** \file
\brief This file contains the class definition of the muparser engine.
*/
@ -52,266 +48,218 @@ namespace mu
/** \brief Mathematical expressions parser (base parser engine).
\author (C) 2013 Ingo Berg
This is the implementation of a bytecode based mathematical expressions parser.
The formula will be parsed from string and converted into a bytecode.
This is the implementation of a bytecode based mathematical expressions parser.
The formula will be parsed from string and converted into a bytecode.
Future calculations will be done with the bytecode instead the formula string
resulting in a significant performance increase.
Complementary to a set of internally implemented functions the parser is able to handle
user defined functions and variables.
resulting in a significant performance increase.
Complementary to a set of internally implemented functions the parser is able to handle
user defined functions and variables.
*/
class ParserBase
{
friend class ParserTokenReader;
class ParserBase {
friend class ParserTokenReader;
private:
private:
/** \brief Typedef for the parse functions.
/** \brief Typedef for the parse functions.
The parse function do the actual work. The parser exchanges
the function pointer to the parser function depending on
the function pointer to the parser function depending on
which state it is in. (i.e. bytecode parser vs. string parser)
*/
typedef value_type (ParserBase::*ParseFunction)() const;
/** \brief Type used for storing an array of values. */
typedef std::vector<value_type> valbuf_type;
typedef ValueOrError (ParserBase::*ParseFunction)() const;
/** \brief Type for a vector of strings. */
typedef std::vector<string_type> stringbuf_type;
/** \brief Typedef for the token reader. */
typedef ParserTokenReader token_reader_type;
/** \brief Type used for parser tokens. */
typedef ParserToken<value_type, string_type> token_type;
/** \brief Maximum number of threads spawned by OpenMP when using the bulk mode. */
static const int s_MaxNumOpenMPThreads = 16;
public:
/** \brief Type of the error class.
public:
/** \brief Type of the error class.
Included for backwards compatibility.
*/
typedef ParserError exception_type;
static void EnableDebugDump(bool bDumpCmd, bool bDumpStack);
ParserBase();
ParserBase(const ParserBase &a_Parser);
ParserBase& operator=(const ParserBase &a_Parser);
ParserBase();
ParserBase(const ParserBase &a_Parser) = delete;
ParserBase &operator=(const ParserBase &a_Parser) = delete;
virtual ~ParserBase();
value_type Eval() const;
value_type* Eval(int &nStackSize) const;
void Eval(value_type *results, int nBulkSize);
ValueOrError Eval() const;
void Eval(std::vector<ValueOrError> *results) const;
int GetNumResults() const;
void SetExpr(const string_type &a_sExpr);
OptionalError SetExpr(const string_type &a_sExpr);
void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL);
void SetDecSep(char_type cDecSep);
void SetThousandsSep(char_type cThousandsSep = 0);
void ResetLocale();
void EnableOptimizer(bool a_bIsOn=true);
void EnableBuiltInOprt(bool a_bIsOn=true);
void EnableBuiltInOprt(bool a_bIsOn = true);
bool HasBuiltInOprt() const;
void AddValIdent(identfun_type a_pCallback);
/** \fn void mu::ParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true)
/** \fn void mu::ParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun)
\brief Define a parser function without arguments.
\param a_strName Name of the function
\param a_pFun Pointer to the callback function
\param a_bAllowOpt A flag indicating this function may be optimized
*/
template<typename T>
void DefineFun(const string_type &a_strName, T a_pFun, bool a_bAllowOpt = true)
{
AddCallback( a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars() );
template <typename T>
OptionalError DefineFun(const string_type &a_strName, T a_pFun) {
return AddCallback(a_strName, ParserCallback(a_pFun), m_FunDef, ValidNameChars());
}
void DefineOprt(const string_type &a_strName,
fun_type2 a_pFun,
unsigned a_iPri=0,
EOprtAssociativity a_eAssociativity = oaLEFT,
bool a_bAllowOpt = false);
void DefineConst(const string_type &a_sName, value_type a_fVal);
void DefineStrConst(const string_type &a_sName, const string_type &a_strVal);
void DefineVar(const string_type &a_sName, value_type *a_fVar);
void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true);
void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true);
OptionalError DefineOprt(const string_type &a_strName, fun_type2 a_pFun, unsigned a_iPri = 0,
EOprtAssociativity a_eAssociativity = oaLEFT);
OptionalError DefineConst(const string_type &a_sName, value_type a_fVal);
OptionalError DefineStrConst(const string_type &a_sName, const string_type &a_strVal);
OptionalError DefineVar(const string_type &a_sName, value_type *a_fVar);
OptionalError DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt);
OptionalError DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt,
int a_iPrec = prINFIX);
// Clear user defined variables, constants or functions
void ClearVar();
void ClearFun();
// Clear user defined constants or operators.
void ClearConst();
void ClearInfixOprt();
void ClearPostfixOprt();
void ClearOprt();
void RemoveVar(const string_type &a_strVarName);
const varmap_type& GetUsedVar() const;
const varmap_type& GetVar() const;
const valmap_type& GetConst() const;
const string_type& GetExpr() const;
const funmap_type& GetFunDef() const;
string_type GetVersion(EParserVersionInfo eInfo = pviFULL) const;
const char_type ** GetOprtDef() const;
void RemoveVar(const string_type &a_strVarName);
const varmap_type &GetVar() const;
const string_type &GetExpr() const;
const char_type **GetOprtDef() const;
void DefineNameChars(const char_type *a_szCharset);
void DefineOprtChars(const char_type *a_szCharset);
void DefineInfixOprtChars(const char_type *a_szCharset);
const char_type* ValidNameChars() const;
const char_type* ValidOprtChars() const;
const char_type* ValidInfixOprtChars() const;
const char_type *ValidNameChars() const;
const char_type *ValidOprtChars() const;
const char_type *ValidInfixOprtChars() const;
void SetArgSep(char_type cArgSep);
char_type GetArgSep() const;
void Error(EErrorCodes a_iErrc,
int a_iPos = (int)mu::string_type::npos,
const string_type &a_strTok = string_type() ) const;
protected:
ParserError Error(EErrorCodes a_iErrc, int a_iPos = (int)mu::string_type::npos,
const string_type &a_strTok = string_type()) const;
protected:
void Init();
virtual void InitCharSets() = 0;
virtual void InitFun() = 0;
virtual void InitConst() = 0;
virtual void InitOprt() = 0;
virtual void InitOprt() = 0;
virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd);
static const char_type *c_DefaultOprt[];
static const char_type *c_DefaultOprt[];
static std::locale s_locale; ///< The locale used by the parser
static bool g_DbgDumpCmdCode;
static bool g_DbgDumpStack;
/** \brief A facet class used to change decimal and thousands separator. */
template<class TChar>
class change_dec_sep : public std::numpunct<TChar>
{
public:
explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3)
:std::numpunct<TChar>()
,m_nGroup(nGroup)
,m_cDecPoint(cDecSep)
,m_cThousandsSep(cThousandsSep)
{}
protected:
virtual char_type do_decimal_point() const
{
return m_cDecPoint;
}
template <class TChar>
class change_dec_sep : public std::numpunct<TChar> {
public:
explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3)
: std::numpunct<TChar>(),
m_nGroup(nGroup),
m_cDecPoint(cDecSep),
m_cThousandsSep(cThousandsSep) {}
virtual char_type do_thousands_sep() const
{
return m_cThousandsSep;
}
protected:
virtual char_type do_decimal_point() const { return m_cDecPoint; }
virtual std::string do_grouping() const
{
// fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4
// courtesy of Jens Bartsch
// original code:
// return std::string(1, (char)m_nGroup);
// new code:
return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX));
}
virtual char_type do_thousands_sep() const { return m_cThousandsSep; }
private:
virtual std::string do_grouping() const {
// fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4
// courtesy of Jens Bartsch
// original code:
// return std::string(1, (char)m_nGroup);
// new code:
return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX));
}
int m_nGroup;
char_type m_cDecPoint;
char_type m_cThousandsSep;
private:
int m_nGroup;
char_type m_cDecPoint;
char_type m_cThousandsSep;
};
private:
void Assign(const ParserBase &a_Parser);
void InitTokenReader();
private:
void ReInit() const;
void AddCallback( const string_type &a_strName,
const ParserCallback &a_Callback,
funmap_type &a_Storage,
const char_type *a_szCharSet );
OptionalError AddCallback(const string_type &a_strName, const ParserCallback &a_Callback,
funmap_type &a_Storage, const char_type *a_szCharSet);
void ApplyRemainingOprt(ParserStack<token_type> &a_stOpt,
ParserStack<token_type> &a_stVal) const;
void ApplyBinOprt(ParserStack<token_type> &a_stOpt,
ParserStack<token_type> &a_stVal) const;
OptionalError ApplyRemainingOprt(ParserStack<token_type> &a_stOpt,
ParserStack<token_type> &a_stVal) const;
OptionalError ApplyBinOprt(ParserStack<token_type> &a_stOpt,
ParserStack<token_type> &a_stVal) const;
void ApplyIfElse(ParserStack<token_type> &a_stOpt,
ParserStack<token_type> &a_stVal) const;
OptionalError ApplyIfElse(ParserStack<token_type> &a_stOpt,
ParserStack<token_type> &a_stVal) const;
void ApplyFunc(ParserStack<token_type> &a_stOpt,
ParserStack<token_type> &a_stVal,
int iArgCount) const;
OptionalError ApplyFunc(ParserStack<token_type> &a_stOpt, ParserStack<token_type> &a_stVal,
int iArgCount) const;
token_type ApplyStrFunc(const token_type &a_FunTok,
const std::vector<token_type> &a_vArg) const;
OptionalError ApplyStrFunc(const token_type &a_FunTok,
const std::vector<token_type> &a_vArg) const;
int GetOprtPrecedence(const token_type &a_Tok) const;
EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const;
void CreateRPN() const;
OptionalError CreateRPN() const;
value_type ParseString() const;
value_type ParseCmdCode() const;
value_type ParseCmdCodeBulk(int nOffset, int nThreadID) const;
ValueOrError ExecuteRPN() const;
ValueOrError InvokeFunction(generic_fun_type func, const value_type *args, int argCount) const;
void CheckName(const string_type &a_strName, const string_type &a_CharSet) const;
void CheckOprt(const string_type &a_sName,
const ParserCallback &a_Callback,
const string_type &a_szCharSet) const;
/// Build the RPN if necessary, and then execute it.
/// \return the result, or an error.
ValueOrError BuildAndExecuteRPN() const;
void StackDump(const ParserStack<token_type > &a_stVal,
const ParserStack<token_type > &a_stOprt) const;
OptionalError CheckName(const string_type &a_strName, const string_type &a_CharSet) const;
OptionalError CheckOprt(const string_type &a_sName, const ParserCallback &a_Callback,
const string_type &a_szCharSet) const;
void StackDump(const ParserStack<token_type> &a_stVal,
const ParserStack<token_type> &a_stOprt) const;
/** \brief Pointer to the parser function.
/** \brief Pointer to the parser function.
Eval() calls the function whose address is stored there.
*/
mutable ParseFunction m_pParseFormula;
mutable ParserByteCode m_vRPN; ///< The Bytecode class.
mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments
stringbuf_type m_vStringVarBuf;
mutable ParserByteCode m_vRPN; ///< The Bytecode class.
mutable stringbuf_type
m_vStringBuf; ///< String buffer, used for storing string function arguments
stringbuf_type m_vStringVarBuf;
std::auto_ptr<token_reader_type> m_pTokenReader; ///< Managed pointer to the token reader object.
std::unique_ptr<ParserTokenReader> m_pTokenReader;
funmap_type m_FunDef; ///< Map of function names and pointers.
funmap_type m_PostOprtDef; ///< Postfix operator callbacks
funmap_type m_InfixOprtDef; ///< unary infix operator.
funmap_type m_OprtDef; ///< Binary operator callbacks
valmap_type m_ConstDef; ///< user constants.
strmap_type m_StrVarDef; ///< user defined string constants
varmap_type m_VarDef; ///< user defind variables.
funmap_type m_FunDef; ///< Map of function names and pointers.
funmap_type m_PostOprtDef; ///< Postfix operator callbacks
funmap_type m_InfixOprtDef; ///< unary infix operator.
funmap_type m_OprtDef; ///< Binary operator callbacks
valmap_type m_ConstDef; ///< user constants.
strmap_type m_StrVarDef; ///< user defined string constants
varmap_type m_VarDef; ///< user defind variables.
bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off
bool m_bBuiltInOp =
true; ///< Flag that can be used for switching built in operators on and off
string_type m_sNameChars; ///< Charset for names
string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens
string_type m_sInfixOprtChars; ///< Charset for infix operator tokens
mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses
string_type m_sNameChars; ///< Charset for names
string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens
string_type m_sInfixOprtChars; ///< Charset for infix operator tokens
// items merely used for caching state information
mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine
mutable int m_nFinalResultIdx;
/// This is merely a buffer used for the stack in the cmd parsing routine
mutable std::vector<value_type> m_vStackBuffer;
mutable int m_nFinalResultIdx = 0;
};
} // namespace mu
} // namespace mu
#endif

View file

@ -1,118 +1,99 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2004-2013 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_BYTECODE_H
#define MU_PARSER_BYTECODE_H
#include <cassert>
#include <string>
#include <stack>
#include <string>
#include <vector>
#include "muParserDef.h"
#include "muParserError.h"
#include "muParserToken.h"
/** \file
\brief Definition of the parser bytecode class.
*/
namespace mu
{
struct SToken
{
namespace mu {
struct SToken {
ECmdCode Cmd;
int StackPos;
union
{
struct //SValData
{
value_type *ptr;
value_type data;
value_type data2;
} Val;
union {
struct // SValData
{
value_type *ptr;
value_type data;
} Val;
struct //SFunData
{
// Note: generic_fun_type is merely a placeholder. The real type could be
// anything between gun_type1 and fun_type9. I can't use a void
// pointer due to constraints in the ANSI standard which allows
// data pointers and function pointers to differ in size.
generic_fun_type ptr;
int argc;
int idx;
} Fun;
struct // SFunData
{
// Note: generic_fun_type is merely a placeholder. The real type could be
// anything between gun_type1 and fun_type9. I can't use a void
// pointer due to constraints in the ANSI standard which allows
// data pointers and function pointers to differ in size.
generic_fun_type ptr;
int argc;
int idx;
} Fun;
struct //SOprtData
{
value_type *ptr;
int offset;
} Oprt;
struct // SOprtData
{
value_type *ptr;
int offset;
} Oprt;
};
};
/** \brief Bytecode implementation of the Math Parser.
};
The bytecode contains the formula converted to revers polish notation stored in a continious
memory area. Associated with this data are operator codes, variable pointers, constant
values and function pointers. Those are necessary in order to calculate the result.
All those data items will be casted to the underlying datatype of the bytecode.
/** \brief Bytecode implementation of the Math Parser.
\author (C) 2004-2013 Ingo Berg
The bytecode contains the formula converted to revers polish notation stored in a continious
memory area. Associated with this data are operator codes, variable pointers, constant
values and function pointers. Those are necessary in order to calculate the result.
All those data items will be casted to the underlying datatype of the bytecode.
\author (C) 2004-2013 Ingo Berg
*/
class ParserByteCode
{
private:
class ParserByteCode {
private:
/** \brief Token type for internal use only. */
typedef ParserToken<value_type, string_type> token_type;
/** \brief Token vector for storing the RPN. */
typedef std::vector<SToken> rpn_type;
/** \brief Position in the Calculation array. */
unsigned m_iStackPos;
/** \brief Maximum size needed for the stack. */
std::size_t m_iMaxStackSize;
/** \brief The actual rpn storage. */
rpn_type m_vRPN;
bool m_bEnableOptimizer;
void ConstantFolding(ECmdCode a_Oprt);
public:
std::vector<SToken> m_vRPN;
public:
ParserByteCode();
ParserByteCode(const ParserByteCode &a_ByteCode);
ParserByteCode& operator=(const ParserByteCode &a_ByteCode);
void Assign(const ParserByteCode &a_ByteCode);
ParserByteCode(const ParserByteCode &a_ByteCode) = delete;
ParserByteCode &operator=(const ParserByteCode &a_ByteCode) = delete;
void AddVar(value_type *a_pVar);
void AddVal(value_type a_fVal);
@ -120,22 +101,18 @@ public:
void AddIfElse(ECmdCode a_Oprt);
void AddAssignOp(value_type *a_pVar);
void AddFun(generic_fun_type a_pFun, int a_iArgc);
void AddBulkFun(generic_fun_type a_pFun, int a_iArgc);
void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx);
void EnableOptimizer(bool bStat);
void Finalize();
void clear();
std::size_t GetMaxStackSize() const;
std::size_t GetSize() const;
bool empty() const { return GetSize() == 0; }
const SToken* GetBase() const;
const SToken *GetBase() const;
void AsciiDump();
};
} // namespace mu
} // namespace mu
#endif

View file

@ -1,26 +1,26 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2004-2011 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_CALLBACK_H
@ -32,87 +32,61 @@
\brief Definition of the parser callback class.
*/
namespace mu
{
namespace mu {
/** \brief Encapsulation of prototypes for a numerical parser function.
Encapsulates the prototyp for numerical parser functions. The class
stores the number of arguments for parser functions as well
as additional flags indication the function is non optimizeable.
The pointer to the callback function pointer is stored as void*
The pointer to the callback function pointer is stored as void*
and needs to be casted according to the argument count.
Negative argument counts indicate a parser function with a variable number
of arguments.
of arguments.
\author (C) 2004-2011 Ingo Berg
*/
class ParserCallback
{
public:
ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti);
ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC);
ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity);
ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti);
ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti);
ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti);
ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti);
ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti);
ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti);
ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti);
ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti);
ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti);
class ParserCallback final {
public:
explicit ParserCallback(fun_type0 a_pFun);
ParserCallback(fun_type1 a_pFun, int a_iPrec = -1, ECmdCode a_iCode = cmFUNC);
ParserCallback(fun_type2 a_pFun, int a_iPrec, EOprtAssociativity a_eAssociativity);
explicit ParserCallback(fun_type2 a_pFun);
explicit ParserCallback(fun_type3 a_pFun);
ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti);
ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti);
ParserCallback(multfun_type a_pFun, bool a_bAllowOpti);
ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti);
ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti);
ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti);
explicit ParserCallback(multfun_type a_pFun);
explicit ParserCallback(strfun_type1 a_pFun);
explicit ParserCallback(strfun_type2 a_pFun);
explicit ParserCallback(strfun_type3 a_pFun);
ParserCallback();
ParserCallback(const ParserCallback &a_Fun);
ParserCallback* Clone() const;
ParserCallback(const ParserCallback& a_Fun);
bool IsOptimizable() const;
void* GetAddr() const;
ECmdCode GetCode() const;
ECmdCode GetCode() const;
ETypeCode GetType() const;
int GetPri() const;
int GetPri() const;
EOprtAssociativity GetAssociativity() const;
int GetArgc() const;
private:
void *m_pFun; ///< Pointer to the callback function, casted to void
private:
void* m_pFun; ///< Pointer to the callback function, casted to void
/** \brief Number of numeric function arguments
This number is negative for functions with variable number of arguments. in this cases
they represent the actual number of arguments found.
*/
int m_iArgc;
int m_iPri; ///< Valid only for binary and infix operators; Operator precedence.
EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators
ECmdCode m_iCode;
int m_iArgc;
int m_iPri; ///< Valid only for binary and infix operators; Operator precedence.
EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators
ECmdCode m_iCode;
ETypeCode m_iType;
bool m_bAllowOpti; ///< Flag indication optimizeability
};
//------------------------------------------------------------------------------
/** \brief Container for Callback objects. */
typedef std::map<string_type, ParserCallback> funmap_type;
typedef std::map<string_type, ParserCallback> funmap_type;
} // namespace mu
} // namespace mu
#endif

View file

@ -1,241 +0,0 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2011 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_DLL_H
#define MU_PARSER_DLL_H
#if defined(WIN32) || defined(_WIN32)
#ifdef MUPARSERLIB_EXPORTS
#define API_EXPORT(TYPE) __declspec(dllexport) TYPE __cdecl
#else
#define API_EXPORT(TYPE) __declspec(dllimport) TYPE __cdecl
#endif
#else
#define API_EXPORT(TYPE) TYPE
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/** \file
\brief This file contains the DLL interface of muparser.
*/
// Basic types
typedef void* muParserHandle_t; // parser handle
#ifndef _UNICODE
typedef char muChar_t; // character type
#else
typedef wchar_t muChar_t; // character type
#endif
typedef int muBool_t; // boolean type
typedef int muInt_t; // integer type
typedef double muFloat_t; // floating point type
// function types for calculation
typedef muFloat_t (*muFun0_t )();
typedef muFloat_t (*muFun1_t )(muFloat_t);
typedef muFloat_t (*muFun2_t )(muFloat_t, muFloat_t);
typedef muFloat_t (*muFun3_t )(muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun4_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun5_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun6_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun7_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun8_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun9_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun10_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
// Function prototypes for bulkmode functions
typedef muFloat_t (*muBulkFun0_t )(int, int);
typedef muFloat_t (*muBulkFun1_t )(int, int, muFloat_t);
typedef muFloat_t (*muBulkFun2_t )(int, int, muFloat_t, muFloat_t);
typedef muFloat_t (*muBulkFun3_t )(int, int, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muBulkFun4_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muBulkFun5_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muBulkFun6_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muBulkFun7_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muBulkFun8_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muBulkFun9_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muBulkFun10_t)(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muMultFun_t)(const muFloat_t*, muInt_t);
typedef muFloat_t (*muStrFun1_t)(const muChar_t*);
typedef muFloat_t (*muStrFun2_t)(const muChar_t*, muFloat_t);
typedef muFloat_t (*muStrFun3_t)(const muChar_t*, muFloat_t, muFloat_t);
// Functions for parser management
typedef void (*muErrorHandler_t)(muParserHandle_t a_hParser); // [optional] callback to an error handler
typedef muFloat_t* (*muFacFun_t)(const muChar_t*, void*); // [optional] callback for creating new variables
typedef muInt_t (*muIdentFun_t)(const muChar_t*, muInt_t*, muFloat_t*); // [optional] value identification callbacks
//-----------------------------------------------------------------------------------------------------
// Constants
static const int muOPRT_ASCT_LEFT = 0;
static const int muOPRT_ASCT_RIGHT = 1;
static const int muBASETYPE_FLOAT = 0;
static const int muBASETYPE_INT = 1;
//-----------------------------------------------------------------------------------------------------
//
//
// muParser C compatible bindings
//
//
//-----------------------------------------------------------------------------------------------------
// Basic operations / initialization
API_EXPORT(muParserHandle_t) mupCreate(int nBaseType);
API_EXPORT(void) mupRelease(muParserHandle_t a_hParser);
API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser);
API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t *a_szExpr);
API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void* pUserData);
API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser);
API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser);
API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int *nNum);
API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t *a_fResult, int nSize);
// Defining callbacks / variables / constants
API_EXPORT(void) mupDefineFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun0_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun1_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun2_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun3_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun4_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun5_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun6_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun7_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun8_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun9_t a_pFun, muBool_t a_bOptimize);
API_EXPORT(void) mupDefineFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun10_t a_pFun, muBool_t a_bOptimize);
// Defining bulkmode functions
API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun0_t a_pFun);
API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun1_t a_pFun);
API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun2_t a_pFun);
API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun3_t a_pFun);
API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun4_t a_pFun);
API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun5_t a_pFun);
API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun6_t a_pFun);
API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun7_t a_pFun);
API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun8_t a_pFun);
API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun9_t a_pFun);
API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun10_t a_pFun);
// string functions
API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun1_t a_pFun);
API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun2_t a_pFun);
API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun3_t a_pFun);
API_EXPORT(void) mupDefineMultFun( muParserHandle_t a_hParser,
const muChar_t* a_szName,
muMultFun_t a_pFun,
muBool_t a_bOptimize);
API_EXPORT(void) mupDefineOprt( muParserHandle_t a_hParser,
const muChar_t* a_szName,
muFun2_t a_pFun,
muInt_t a_nPrec,
muInt_t a_nOprtAsct,
muBool_t a_bOptimize);
API_EXPORT(void) mupDefineConst( muParserHandle_t a_hParser,
const muChar_t* a_szName,
muFloat_t a_fVal );
API_EXPORT(void) mupDefineStrConst( muParserHandle_t a_hParser,
const muChar_t* a_szName,
const muChar_t *a_sVal );
API_EXPORT(void) mupDefineVar( muParserHandle_t a_hParser,
const muChar_t* a_szName,
muFloat_t *a_fVar);
API_EXPORT(void) mupDefineBulkVar( muParserHandle_t a_hParser,
const muChar_t* a_szName,
muFloat_t *a_fVar);
API_EXPORT(void) mupDefinePostfixOprt( muParserHandle_t a_hParser,
const muChar_t* a_szName,
muFun1_t a_pOprt,
muBool_t a_bOptimize);
API_EXPORT(void) mupDefineInfixOprt( muParserHandle_t a_hParser,
const muChar_t* a_szName,
muFun1_t a_pOprt,
muBool_t a_bOptimize);
// Define character sets for identifiers
API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset);
API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset);
API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset);
// Remove all / single variables
API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName);
API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser);
API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser);
API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser);
API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser);
// Querying variables / expression variables / constants
API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser);
API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser);
API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser);
API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar);
API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar);
API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t* a_pVar);
API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep);
API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cArgSep);
API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cArgSep);
API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser);
// Add value recognition callbacks
API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, muIdentFun_t);
// Error handling
API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser);
API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser);
API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t a_pErrHandler);
API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser);
API_EXPORT(muInt_t) mupGetErrorCode(muParserHandle_t a_hParser);
API_EXPORT(muInt_t) mupGetErrorPos(muParserHandle_t a_hParser);
API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser);
//API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser);
// This is used for .NET only. It creates a new variable allowing the dll to
// manage the variable rather than the .NET garbage collector.
API_EXPORT(muFloat_t*) mupCreateVar();
API_EXPORT(void) mupReleaseVar(muFloat_t*);
#ifdef __cplusplus
}
#endif
#endif // include guard

View file

@ -1,36 +1,37 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2014 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MUP_DEF_H
#define MUP_DEF_H
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include "muParserFixes.h"
#include <memory>
#include <sstream>
#include <string>
#include <vector>
/** \file
\brief This file contains standard definitions used by the parser.
@ -41,7 +42,8 @@
#define MUP_CHARS _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
/** \brief If this macro is defined mathematical exceptions (div by zero) will be thrown as exceptions. */
/** \brief If this macro is defined mathematical exceptions (div by zero) will be thrown as
* exceptions. */
//#define MUP_MATH_EXCEPTIONS
/** \brief Define the base datatype for values.
@ -51,318 +53,374 @@
*/
#define MUP_BASETYPE double
/** \brief Activate this option in order to compile with OpenMP support.
#if defined(_UNICODE)
/** \brief Definition of the basic parser string type. */
#define MUP_STRING_TYPE std::wstring
OpenMP is used only in the bulk mode it may increase the performance a bit.
#if !defined(_T)
#define _T(x) L##x
#endif // not defined _T
#else
#ifndef _T
#define _T(x) x
#endif
/** \brief Definition of the basic parser string type. */
#define MUP_STRING_TYPE std::string
#endif
namespace mu {
#if defined(_UNICODE)
//------------------------------------------------------------------------------
/** \brief Encapsulate wcout. */
inline std::wostream &console() { return std::wcout; }
/** \brief Encapsulate cin. */
inline std::wistream &console_in() { return std::wcin; }
#else
/** \brief Encapsulate cout.
Used for supporting UNICODE more easily.
*/
//#define MUP_USE_OPENMP
inline std::ostream &console() { return std::cout; }
#if defined(_UNICODE)
/** \brief Definition of the basic parser string type. */
#define MUP_STRING_TYPE std::wstring
/** \brief Encapsulate cin.
#if !defined(_T)
#define _T(x) L##x
#endif // not defined _T
#else
#ifndef _T
#define _T(x) x
#endif
/** \brief Definition of the basic parser string type. */
#define MUP_STRING_TYPE std::string
#endif
#if defined(_DEBUG)
/** \brief Debug macro to force an abortion of the programm with a certain message.
*/
#define MUP_FAIL(MSG) \
{ \
bool MSG=false; \
assert(MSG); \
}
/** \brief An assertion that does not kill the program.
This macro is neutralised in UNICODE builds. It's
too difficult to translate.
*/
#define MUP_ASSERT(COND) \
if (!(COND)) \
{ \
stringstream_type ss; \
ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") \
<< __FILE__ << _T(" line ") \
<< __LINE__ << _T("."); \
throw ParserError( ss.str() ); \
}
#else
#define MUP_FAIL(MSG)
#define MUP_ASSERT(COND)
#endif
namespace mu
{
#if defined(_UNICODE)
//------------------------------------------------------------------------------
/** \brief Encapsulate wcout. */
inline std::wostream& console()
{
return std::wcout;
}
/** \brief Encapsulate cin. */
inline std::wistream& console_in()
{
return std::wcin;
}
#else
/** \brief Encapsulate cout.
Used for supporting UNICODE more easily.
*/
inline std::ostream& console()
{
return std::cout;
}
/** \brief Encapsulate cin.
Used for supporting UNICODE more easily.
*/
inline std::istream& console_in()
{
return std::cin;
}
Used for supporting UNICODE more easily.
*/
inline std::istream &console_in() { return std::cin; }
#endif
//------------------------------------------------------------------------------
/** \brief Bytecode values.
/// Our stack type.
template <typename T>
class ParserStack : public std::vector<T> {
public:
// Convenience to get the top value and pop it.
T pop() {
T val = std::move(this->back());
this->pop_back();
return val;
}
\attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt!
*/
enum ECmdCode
{
T &top() { return this->back(); }
void push(T val) { this->push_back(std::move(val)); }
};
//------------------------------------------------------------------------------
/** \brief Bytecode values.
\attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt!
*/
enum ECmdCode {
// The following are codes for built in binary operators
// apart from built in operators the user has the opportunity to
// add user defined operators.
cmLE = 0, ///< Operator item: less or equal
cmGE = 1, ///< Operator item: greater or equal
cmNEQ = 2, ///< Operator item: not equal
cmEQ = 3, ///< Operator item: equals
cmLT = 4, ///< Operator item: less than
cmGT = 5, ///< Operator item: greater than
cmADD = 6, ///< Operator item: add
cmSUB = 7, ///< Operator item: subtract
cmMUL = 8, ///< Operator item: multiply
cmDIV = 9, ///< Operator item: division
cmPOW = 10, ///< Operator item: y to the power of ...
cmLAND = 11,
cmLOR = 12,
cmASSIGN = 13, ///< Operator item: Assignment operator
cmBO = 14, ///< Operator item: opening bracket
cmBC = 15, ///< Operator item: closing bracket
cmIF = 16, ///< For use in the ternary if-then-else operator
cmELSE = 17, ///< For use in the ternary if-then-else operator
cmENDIF = 18, ///< For use in the ternary if-then-else operator
cmARG_SEP = 19, ///< function argument separator
cmVAR = 20, ///< variable item
cmVAL = 21, ///< value item
// For optimization purposes
cmVARPOW2,
cmVARPOW3,
cmVARPOW4,
cmVARMUL,
cmPOW2,
cmLE = 0, ///< Operator item: less or equal
cmGE = 1, ///< Operator item: greater or equal
cmNEQ = 2, ///< Operator item: not equal
cmEQ = 3, ///< Operator item: equals
cmLT = 4, ///< Operator item: less than
cmGT = 5, ///< Operator item: greater than
cmADD = 6, ///< Operator item: add
cmSUB = 7, ///< Operator item: subtract
cmMUL = 8, ///< Operator item: multiply
cmDIV = 9, ///< Operator item: division
cmPOW = 10, ///< Operator item: y to the power of ...
cmLAND = 11,
cmLOR = 12,
cmASSIGN = 13, ///< Operator item: Assignment operator
cmBO = 14, ///< Operator item: opening bracket
cmBC = 15, ///< Operator item: closing bracket
cmIF = 16, ///< For use in the ternary if-then-else operator
cmELSE = 17, ///< For use in the ternary if-then-else operator
cmENDIF = 18, ///< For use in the ternary if-then-else operator
cmARG_SEP = 19, ///< function argument separator
cmVAR = 20, ///< variable item
cmVAL = 21, ///< value item
// operators and functions
cmFUNC, ///< Code for a generic function item
cmFUNC_STR, ///< Code for a function with a string parameter
cmFUNC_BULK, ///< Special callbacks for Bulk mode with an additional parameter for the bulk index
cmSTRING, ///< Code for a string token
cmOPRT_BIN, ///< user defined binary operator
cmOPRT_POSTFIX, ///< code for postfix operators
cmOPRT_INFIX, ///< code for infix operators
cmEND, ///< end of formula
cmUNKNOWN ///< uninitialized item
};
cmFUNC, ///< Code for a generic function item
cmFUNC_STR, ///< Code for a function with a string parameter
cmSTRING, ///< Code for a string token
cmOPRT_BIN, ///< user defined binary operator
cmOPRT_POSTFIX, ///< code for postfix operators
cmOPRT_INFIX, ///< code for infix operators
cmEND, ///< end of formula
cmUNKNOWN ///< uninitialized item
};
//------------------------------------------------------------------------------
/** \brief Types internally used by the parser.
*/
enum ETypeCode
{
tpSTR = 0, ///< String type (Function arguments and constants only, no string variables)
tpDBL = 1, ///< Floating point variables
tpVOID = 2 ///< Undefined type.
};
//------------------------------------------------------------------------------
/** \brief Types internally used by the parser.
*/
enum ETypeCode {
tpSTR = 0, ///< String type (Function arguments and constants only, no string variables)
tpDBL = 1, ///< Floating point variables
tpVOID = 2 ///< Undefined type.
};
//------------------------------------------------------------------------------
enum EParserVersionInfo
{
pviBRIEF,
pviFULL
};
//------------------------------------------------------------------------------
/** \brief Parser operator precedence values. */
enum EOprtAssociativity { oaLEFT = 0, oaRIGHT = 1, oaNONE = 2 };
//------------------------------------------------------------------------------
/** \brief Parser operator precedence values. */
enum EOprtAssociativity
{
oaLEFT = 0,
oaRIGHT = 1,
oaNONE = 2
};
//------------------------------------------------------------------------------
/** \brief Parser operator precedence values. */
enum EOprtPrecedence
{
//------------------------------------------------------------------------------
/** \brief Parser operator precedence values. */
enum EOprtPrecedence {
// binary operators
prLOR = 1,
prLAND = 2,
prLOGIC = 3, ///< logic operators
prCMP = 4, ///< comparsion operators
prLOR = 1,
prLAND = 2,
prLOGIC = 3, ///< logic operators
prCMP = 4, ///< comparsion operators
prADD_SUB = 5, ///< addition
prMUL_DIV = 6, ///< multiplication/division
prPOW = 7, ///< power operator priority (highest)
prPOW = 7, ///< power operator priority (highest)
// infix operators
prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator
prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator
prPOSTFIX = 6 ///< Postfix operator priority (currently unused)
};
};
//------------------------------------------------------------------------------
// basic types
//------------------------------------------------------------------------------
// basic types
/** \brief The numeric datatype used by the parser.
Normally this is a floating point type either single or double precision.
*/
typedef MUP_BASETYPE value_type;
/** \brief The numeric datatype used by the parser.
/** \brief The stringtype used by the parser.
Normally this is a floating point type either single or double precision.
*/
typedef MUP_BASETYPE value_type;
Depends on wether UNICODE is used or not.
*/
typedef MUP_STRING_TYPE string_type;
/** \brief The stringtype used by the parser.
/** \brief The character type used by the parser.
Depends on wether UNICODE is used or not.
*/
typedef string_type::value_type char_type;
Depends on wether UNICODE is used or not.
*/
typedef MUP_STRING_TYPE string_type;
/** \brief Typedef for easily using stringstream that respect the parser stringtype. */
typedef std::basic_stringstream<char_type,
std::char_traits<char_type>,
std::allocator<char_type> > stringstream_type;
/** \brief The character type used by the parser.
// Data container types
Depends on wether UNICODE is used or not.
*/
typedef string_type::value_type char_type;
/** \brief Type used for storing variables. */
typedef std::map<string_type, value_type*> varmap_type;
/** \brief Type used for storing constants. */
typedef std::map<string_type, value_type> valmap_type;
/** \brief Type for assigning a string name to an index in the internal string table. */
typedef std::map<string_type, std::size_t> strmap_type;
/** \brief Typedef for easily using stringstream that respect the parser stringtype. */
typedef std::basic_stringstream<char_type, std::char_traits<char_type>, std::allocator<char_type> >
stringstream_type;
// Parser callbacks
/** \brief Callback type used for functions without arguments. */
typedef value_type (*generic_fun_type)();
// Data container types
/** \brief Callback type used for functions without arguments. */
typedef value_type (*fun_type0)();
/** \brief Type used for storing variables. */
typedef std::map<string_type, value_type *> varmap_type;
/** \brief Callback type used for functions with a single arguments. */
typedef value_type (*fun_type1)(value_type);
/** \brief Type used for storing constants. */
typedef std::map<string_type, value_type> valmap_type;
/** \brief Callback type used for functions with two arguments. */
typedef value_type (*fun_type2)(value_type, value_type);
/** \brief Type for assigning a string name to an index in the internal string table. */
typedef std::map<string_type, std::size_t> strmap_type;
/** \brief Callback type used for functions with three arguments. */
typedef value_type (*fun_type3)(value_type, value_type, value_type);
/** \brief Error codes. */
enum EErrorCodes {
// Formula syntax errors
ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found
ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified.
ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(")
ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23")
ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found
ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found
ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found
ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing
ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position
ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument
ecVAL_EXPECTED =
10, ///< A numerical function has been called with a non value type of argument
ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3")
ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)")
ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)")
ecTOO_MANY_PARAMS = 14, ///< Too many function parameters
ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)")
ecOPRT_TYPE_CONFLICT =
16, ///< binary operators may only be applied to value items of the same type
ecSTR_RESULT = 17, ///< result is a string
/** \brief Callback type used for functions with four arguments. */
typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type);
// Invalid Parser input Parameters
ecINVALID_NAME = 18, ///< Invalid function, variable or constant name.
ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier
ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name.
ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name.
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type);
ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator
ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer
ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer
ecEMPTY_EXPRESSION = 25, ///< The Expression is empty
ecNAME_CONFLICT = 26, ///< Name conflict
ecOPT_PRI = 27, ///< Invalid operator priority
//
ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused)
ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused)
ecGENERIC = 30, ///< Generic error
ecLOCALE = 31, ///< Conflict with current locale
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type6)(value_type, value_type, value_type, value_type, value_type, value_type);
ecUNEXPECTED_CONDITIONAL = 32,
ecMISSING_ELSE_CLAUSE = 33,
ecMISPLACED_COLON = 34,
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type7)(value_type, value_type, value_type, value_type, value_type, value_type, value_type);
ecUNREASONABLE_NUMBER_OF_COMPUTATIONS = 35,
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type8)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
// The last two are special entries
ecCOUNT, ///< This is no error code, It just stores just the total number of error codes
ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages
};
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type9)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type10)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions without arguments. */
typedef value_type (*bulkfun_type0)(int, int);
/** \brief Callback type used for functions with a single arguments. */
typedef value_type (*bulkfun_type1)(int, int, value_type);
/** \brief Callback type used for functions with two arguments. */
typedef value_type (*bulkfun_type2)(int, int, value_type, value_type);
/** \brief Callback type used for functions with three arguments. */
typedef value_type (*bulkfun_type3)(int, int, value_type, value_type, value_type);
/** \brief Callback type used for functions with four arguments. */
typedef value_type (*bulkfun_type4)(int, int, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*bulkfun_type5)(int, int, value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*bulkfun_type6)(int, int, value_type, value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*bulkfun_type7)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*bulkfun_type8)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*bulkfun_type9)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*bulkfun_type10)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with a variable argument list. */
typedef value_type (*multfun_type)(const value_type*, int);
/** \brief Callback type used for functions taking a string as an argument. */
typedef value_type (*strfun_type1)(const char_type*);
/** \brief Callback type used for functions taking a string and a value as arguments. */
typedef value_type (*strfun_type2)(const char_type*, value_type);
/** \brief Callback type used for functions taking a string and two values as arguments. */
typedef value_type (*strfun_type3)(const char_type*, value_type, value_type);
/** \brief Callback used for functions that identify values in a string. */
typedef int (*identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal);
/** \brief Callback used for variable creation factory functions. */
typedef value_type* (*facfun_type)(const char_type*, void*);
} // end of namespace
/// \return an error message for the given code.
string_type parser_error_for_code(EErrorCodes code);
// Compatibility with non-clang compilers.
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
// Define a type-level attribute declaring that this type, when used as the return value
// of a function, should produce warnings.
#if __has_attribute(warn_unused_result)
#define MUPARSER_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define MUPARSER_ATTR_WARN_UNUSED_RESULT
#endif
//---------------------------------------------------------------------------
/** \brief Error class of the parser.
\author Ingo Berg
Part of the math parser package.
*/
class ParserError {
private:
/** \brief Replace all ocuurences of a substring with another string. */
void ReplaceSubString(string_type &strSource, const string_type &strFind,
const string_type &strReplaceWith);
void Reset();
public:
ParserError();
explicit ParserError(EErrorCodes a_iErrc);
explicit ParserError(const string_type &sMsg);
ParserError(EErrorCodes a_iErrc, const string_type &sTok, int a_iPos = -1);
ParserError(EErrorCodes a_iErrc, int a_iPos, const string_type &sTok);
ParserError(const char_type *a_szMsg, int a_iPos = -1, const string_type &sTok = string_type());
ParserError(ParserError &&) = default;
ParserError &operator=(ParserError &&) = default;
ParserError(const ParserError &a_Obj) = default;
ParserError &operator=(const ParserError &a_Obj) = default;
~ParserError();
void SetFormula(const string_type &a_strFormula);
const string_type &GetExpr() const;
const string_type &GetMsg() const;
int GetPos() const;
const string_type &GetToken() const;
EErrorCodes GetCode() const;
private:
string_type m_strMsg; ///< The message string
string_type m_strTok; ///< Token related with the error
int m_iPos = -1; ///< Formula position related to the error
EErrorCodes m_iErrc = ecUNDEFINED; ///< Error code
} MUPARSER_ATTR_WARN_UNUSED_RESULT;
// OptionalError is used to optionally encapsulate an error.
class OptionalError {
std::unique_ptr<ParserError> error_{};
public:
/// Create an OptionalError that represents no error.
OptionalError() {}
/// Create an OptionalError for the given error.
/* implicit */ OptionalError(ParserError err) : error_(new ParserError(std::move(err))) {}
/// \return whether an error is present.
bool has_error() const { return bool(error_); }
/// \return the error. asserts if this is not an error.
const ParserError &error() const {
assert(error_ && "Value did not error");
return *error_;
}
} MUPARSER_ATTR_WARN_UNUSED_RESULT;
// ValueOrError is used to propagate failures to callers.
class ValueOrError {
value_type value_{0};
OptionalError error_{};
public:
/// \return true if this has a value, false if it is an error.
bool has_value() const { return !error_.has_error(); }
/// \return false if this has a value,true if it is an error.
bool has_error() const { return error_.has_error(); }
/// Construct from a value.
/* implicit */ ValueOrError(value_type value) : value_(value) {}
/// Construct from an error.
/* implicit */ ValueOrError(ParserError err) : error_(std::move(err)) {}
/// \return the error. asserts if this is not an error.
const ParserError &error() const { return error_.error(); }
/// \return the value. asserts if this is an error.
value_type value() const {
assert(has_value() && "Value is an error");
return value_;
}
/// \return whether this has a value.
explicit operator bool() const { return has_value(); }
value_type operator*() const {
assert(has_value() && "Cannot access value with error");
return value_;
}
} MUPARSER_ATTR_WARN_UNUSED_RESULT;
// Parser callbacks
/** \brief Callback type used for functions without arguments. */
typedef ValueOrError (*generic_fun_type)();
/** \brief Callback type used for functions without arguments. */
typedef ValueOrError (*fun_type0)();
/** \brief Callback type used for functions with a single arguments. */
typedef ValueOrError (*fun_type1)(value_type);
/** \brief Callback type used for functions with two arguments. */
typedef ValueOrError (*fun_type2)(value_type, value_type);
/** \brief Callback type used for functions with three arguments. */
typedef ValueOrError (*fun_type3)(value_type, value_type, value_type);
/** \brief Callback type used for functions with a variable argument list. */
typedef ValueOrError (*multfun_type)(const value_type *, int);
/** \brief Callback type used for functions taking a string as an argument. */
typedef ValueOrError (*strfun_type1)(const char_type *);
/** \brief Callback type used for functions taking a string and a value as arguments. */
typedef ValueOrError (*strfun_type2)(const char_type *, value_type);
/** \brief Callback type used for functions taking a string and two values as arguments. */
typedef ValueOrError (*strfun_type3)(const char_type *, value_type, value_type);
/** \brief Callback used for functions that identify values in a string. */
typedef int (*identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal);
/** \brief Callback used for variable creation factory functions. */
typedef value_type *(*facfun_type)(const char_type *, void *);
} // end of namespace
#endif

View file

@ -1,176 +0,0 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2004-2011 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_ERROR_H
#define MU_PARSER_ERROR_H
#include <cassert>
#include <stdexcept>
#include <string>
#include <sstream>
#include <vector>
#include <memory>
#include "muParserDef.h"
/** \file
\brief This file defines the error class used by the parser.
*/
namespace mu
{
/** \brief Error codes. */
enum EErrorCodes
{
// Formula syntax errors
ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found
ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified.
ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(")
ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23")
ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found
ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found
ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found
ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing
ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position
ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument
ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument
ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3")
ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)")
ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)")
ecTOO_MANY_PARAMS = 14, ///< Too many function parameters
ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)")
ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type
ecSTR_RESULT = 17, ///< result is a string
// Invalid Parser input Parameters
ecINVALID_NAME = 18, ///< Invalid function, variable or constant name.
ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier
ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name.
ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name.
ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator
ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer
ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer
ecEMPTY_EXPRESSION = 25, ///< The Expression is empty
ecNAME_CONFLICT = 26, ///< Name conflict
ecOPT_PRI = 27, ///< Invalid operator priority
//
ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused)
ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused)
ecGENERIC = 30, ///< Generic error
ecLOCALE = 31, ///< Conflict with current locale
ecUNEXPECTED_CONDITIONAL = 32,
ecMISSING_ELSE_CLAUSE = 33,
ecMISPLACED_COLON = 34,
ecUNREASONABLE_NUMBER_OF_COMPUTATIONS = 35,
// internal errors
ecINTERNAL_ERROR = 36, ///< Internal error of any kind.
// The last two are special entries
ecCOUNT, ///< This is no error code, It just stores just the total number of error codes
ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages
};
//---------------------------------------------------------------------------
/** \brief A class that handles the error messages.
*/
class ParserErrorMsg
{
public:
typedef ParserErrorMsg self_type;
ParserErrorMsg& operator=(const ParserErrorMsg &);
ParserErrorMsg(const ParserErrorMsg&);
ParserErrorMsg();
~ParserErrorMsg();
static const ParserErrorMsg& Instance();
string_type operator[](unsigned a_iIdx) const;
private:
std::vector<string_type> m_vErrMsg; ///< A vector with the predefined error messages
static const self_type m_Instance; ///< The instance pointer
};
//---------------------------------------------------------------------------
/** \brief Error class of the parser.
\author Ingo Berg
Part of the math parser package.
*/
class ParserError
{
private:
/** \brief Replace all ocuurences of a substring with another string. */
void ReplaceSubString( string_type &strSource,
const string_type &strFind,
const string_type &strReplaceWith);
void Reset();
public:
ParserError();
explicit ParserError(EErrorCodes a_iErrc);
explicit ParserError(const string_type &sMsg);
ParserError( EErrorCodes a_iErrc,
const string_type &sTok,
const string_type &sFormula = string_type(),
int a_iPos = -1);
ParserError( EErrorCodes a_iErrc,
int a_iPos,
const string_type &sTok);
ParserError( const char_type *a_szMsg,
int a_iPos = -1,
const string_type &sTok = string_type());
ParserError(const ParserError &a_Obj);
ParserError& operator=(const ParserError &a_Obj);
~ParserError();
void SetFormula(const string_type &a_strFormula);
const string_type& GetExpr() const;
const string_type& GetMsg() const;
int GetPos() const;
const string_type& GetToken() const;
EErrorCodes GetCode() const;
private:
string_type m_strMsg; ///< The message string
string_type m_strFormula; ///< Formula string
string_type m_strTok; ///< Token related with the error
int m_iPos; ///< Formula position related to the error
EErrorCodes m_iErrc; ///< Error code
const ParserErrorMsg &m_ErrMsg;
};
} // namespace mu
#endif

View file

@ -1,62 +0,0 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2013 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_FIXES_H
#define MU_PARSER_FIXES_H
/** \file
\brief This file contains compatibility fixes for some platforms.
*/
//
// Compatibility fixes
//
//---------------------------------------------------------------------------
//
// Intel Compiler
//
//---------------------------------------------------------------------------
#ifdef __INTEL_COMPILER
// remark #981: operands are evaluated in unspecified order
// disabled -> completely pointless if the functions do not have side effects
//
#pragma warning(disable:981)
// remark #383: value copied to temporary, reference to temporary used
#pragma warning(disable:383)
// remark #1572: floating-point equality and inequality comparisons are unreliable
// disabled -> everyone knows it, the parser passes this problem
// deliberately to the user
#pragma warning(disable:1572)
#endif
#endif // include guard

View file

@ -1,131 +1,116 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2004-2013 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_INT_H
#define MU_PARSER_INT_H
#include "muParserBase.h"
#include <vector>
#include "muParserBase.h"
/** \file
\brief Definition of a parser using integer value.
*/
namespace mu
{
namespace mu {
/** \brief Mathematical expressions parser.
This version of the parser handles only integer numbers. It disables the built in operators thus it is
This version of the parser handles only integer numbers. It disables the built in operators thus
it is
slower than muParser. Integer values are stored in the double value_type and converted if needed.
*/
class ParserInt : public ParserBase
{
private:
static int Round(value_type v) { return (int)(v + ((v>=0) ? 0.5 : -0.5) ); };
static value_type Abs(value_type);
static value_type Sign(value_type);
static value_type Ite(value_type, value_type, value_type);
// !! The unary Minus is a MUST, otherwise you cant use negative signs !!
static value_type UnaryMinus(value_type);
// Functions with variable number of arguments
static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum
static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum
static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum
// binary operator callbacks
static value_type Add(value_type v1, value_type v2);
static value_type Sub(value_type v1, value_type v2);
static value_type Mul(value_type v1, value_type v2);
static value_type Div(value_type v1, value_type v2);
static value_type Mod(value_type v1, value_type v2);
static value_type Pow(value_type v1, value_type v2);
static value_type Shr(value_type v1, value_type v2);
static value_type Shl(value_type v1, value_type v2);
static value_type LogAnd(value_type v1, value_type v2);
static value_type LogOr(value_type v1, value_type v2);
static value_type And(value_type v1, value_type v2);
static value_type Or(value_type v1, value_type v2);
static value_type Xor(value_type v1, value_type v2);
static value_type Less(value_type v1, value_type v2);
static value_type Greater(value_type v1, value_type v2);
static value_type LessEq(value_type v1, value_type v2);
static value_type GreaterEq(value_type v1, value_type v2);
static value_type Equal(value_type v1, value_type v2);
static value_type NotEqual(value_type v1, value_type v2);
static value_type Not(value_type v1);
class ParserInt : public ParserBase {
private:
static int Round(value_type v) { return (int)(v + ((v >= 0) ? 0.5 : -0.5)); };
static int IsHexVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal);
static int IsBinVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal);
static int IsVal (const char_type* a_szExpr, int *a_iPos, value_type *a_iVal);
static ValueOrError Abs(value_type);
static ValueOrError Sign(value_type);
static ValueOrError Ite(value_type, value_type, value_type);
// !! The unary Minus is a MUST, otherwise you cant use negative signs !!
static ValueOrError UnaryMinus(value_type);
// Functions with variable number of arguments
static ValueOrError Sum(const value_type* a_afArg, int a_iArgc); // sum
static ValueOrError Min(const value_type* a_afArg, int a_iArgc); // minimum
static ValueOrError Max(const value_type* a_afArg, int a_iArgc); // maximum
// binary operator callbacks
static ValueOrError Add(value_type v1, value_type v2);
static ValueOrError Sub(value_type v1, value_type v2);
static ValueOrError Mul(value_type v1, value_type v2);
static ValueOrError Div(value_type v1, value_type v2);
static ValueOrError Mod(value_type v1, value_type v2);
static ValueOrError Pow(value_type v1, value_type v2);
static ValueOrError Shr(value_type v1, value_type v2);
static ValueOrError Shl(value_type v1, value_type v2);
static ValueOrError LogAnd(value_type v1, value_type v2);
static ValueOrError LogOr(value_type v1, value_type v2);
static ValueOrError And(value_type v1, value_type v2);
static ValueOrError Or(value_type v1, value_type v2);
static ValueOrError Xor(value_type v1, value_type v2);
static ValueOrError Less(value_type v1, value_type v2);
static ValueOrError Greater(value_type v1, value_type v2);
static ValueOrError LessEq(value_type v1, value_type v2);
static ValueOrError GreaterEq(value_type v1, value_type v2);
static ValueOrError Equal(value_type v1, value_type v2);
static ValueOrError NotEqual(value_type v1, value_type v2);
static ValueOrError Not(value_type v1);
static int IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_iVal);
static int IsBinVal(const char_type* a_szExpr, int* a_iPos, value_type* a_iVal);
static int IsVal(const char_type* a_szExpr, int* a_iPos, value_type* a_iVal);
/** \brief A facet class used to change decimal and thousands separator. */
template<class TChar>
class change_dec_sep : public std::numpunct<TChar>
{
public:
explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3)
:std::numpunct<TChar>()
,m_cDecPoint(cDecSep)
,m_cThousandsSep(cThousandsSep)
,m_nGroup(nGroup)
{}
protected:
virtual char_type do_decimal_point() const
{
return m_cDecPoint;
}
template <class TChar>
class change_dec_sep : public std::numpunct<TChar> {
public:
explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3)
: std::numpunct<TChar>(),
m_cDecPoint(cDecSep),
m_cThousandsSep(cThousandsSep),
m_nGroup(nGroup) {}
virtual char_type do_thousands_sep() const
{
return m_cThousandsSep;
}
protected:
virtual char_type do_decimal_point() const { return m_cDecPoint; }
virtual std::string do_grouping() const
{
// fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4
// courtesy of Jens Bartsch
// original code:
// return std::string(1, (char)m_nGroup);
// new code:
return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX));
}
virtual char_type do_thousands_sep() const { return m_cThousandsSep; }
private:
virtual std::string do_grouping() const {
// fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4
// courtesy of Jens Bartsch
// original code:
// return std::string(1, (char)m_nGroup);
// new code:
return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX));
}
int m_nGroup;
char_type m_cDecPoint;
char_type m_cThousandsSep;
private:
int m_nGroup;
char_type m_cDecPoint;
char_type m_cThousandsSep;
};
public:
public:
ParserInt();
virtual void InitFun();
@ -134,7 +119,6 @@ public:
virtual void InitCharSets();
};
} // namespace mu
} // namespace mu
#endif

View file

@ -1,125 +0,0 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2004-2011 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_STACK_H
#define MU_PARSER_STACK_H
#include <cassert>
#include <string>
#include <stack>
#include <vector>
#include "muParserError.h"
#include "muParserToken.h"
/** \file
\brief This file defines the stack used by muparser.
*/
namespace mu
{
/** \brief Parser stack implementation.
Stack implementation based on a std::stack. The behaviour of pop() had been
slightly changed in order to get an error code if the stack is empty.
The stack is used within the Parser both as a value stack and as an operator stack.
\author (C) 2004-2011 Ingo Berg
*/
template <typename TValueType>
class ParserStack
{
private:
/** \brief Type of the underlying stack implementation. */
typedef std::stack<TValueType, std::vector<TValueType> > impl_type;
impl_type m_Stack; ///< This is the actual stack.
public:
//---------------------------------------------------------------------------
ParserStack()
:m_Stack()
{}
//---------------------------------------------------------------------------
virtual ~ParserStack()
{}
//---------------------------------------------------------------------------
/** \brief Pop a value from the stack.
Unlike the standard implementation this function will return the value that
is going to be taken from the stack.
\throw ParserException in case the stack is empty.
\sa pop(int &a_iErrc)
*/
TValueType pop()
{
if (empty())
throw ParserError( _T("stack is empty.") );
TValueType el = top();
m_Stack.pop();
return el;
}
/** \brief Push an object into the stack.
\param a_Val object to push into the stack.
\throw nothrow
*/
void push(const TValueType& a_Val)
{
m_Stack.push(a_Val);
}
/** \brief Return the number of stored elements. */
unsigned size() const
{
return (unsigned)m_Stack.size();
}
/** \brief Returns true if stack is empty false otherwise. */
bool empty() const
{
return m_Stack.empty();
}
/** \brief Return reference to the top object in the stack.
The top object is the one pushed most recently.
*/
TValueType& top()
{
return m_Stack.top();
}
};
} // namespace MathUtils
#endif

View file

@ -1,113 +0,0 @@
#ifndef MU_PARSER_TEMPLATE_MAGIC_H
#define MU_PARSER_TEMPLATE_MAGIC_H
#include <cmath>
#include "muParserError.h"
namespace mu
{
//-----------------------------------------------------------------------------------------------
//
// Compile time type detection
//
//-----------------------------------------------------------------------------------------------
/** \brief A class singling out integer types at compile time using
template meta programming.
*/
template<typename T>
struct TypeInfo
{
static bool IsInteger() { return false; }
};
template<>
struct TypeInfo<char>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<short>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<int>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<long>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<unsigned char>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<unsigned short>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<unsigned int>
{
static bool IsInteger() { return true; }
};
template<>
struct TypeInfo<unsigned long>
{
static bool IsInteger() { return true; }
};
//-----------------------------------------------------------------------------------------------
//
// Standard math functions with dummy overload for integer types
//
//-----------------------------------------------------------------------------------------------
/** \brief A template class for providing wrappers for essential math functions.
This template is spezialized for several types in order to provide a unified interface
for parser internal math function calls regardless of the data type.
*/
template<typename T>
struct MathImpl
{
static T Sin(T v) { return sin(v); }
static T Cos(T v) { return cos(v); }
static T Tan(T v) { return tan(v); }
static T ASin(T v) { return asin(v); }
static T ACos(T v) { return acos(v); }
static T ATan(T v) { return atan(v); }
static T ATan2(T v1, T v2) { return atan2(v1, v2); }
static T Sinh(T v) { return sinh(v); }
static T Cosh(T v) { return cosh(v); }
static T Tanh(T v) { return tanh(v); }
static T ASinh(T v) { return log(v + sqrt(v * v + 1)); }
static T ACosh(T v) { return log(v + sqrt(v * v - 1)); }
static T ATanh(T v) { return ((T)0.5 * log((1 + v) / (1 - v))); }
static T Log(T v) { return log(v); }
static T Log2(T v) { return log(v)/log((T)2); } // Logarithm base 2
static T Log10(T v) { return log10(v); } // Logarithm base 10
static T Exp(T v) { return exp(v); }
static T Abs(T v) { return (v>=0) ? v : -v; }
static T Sqrt(T v) { return sqrt(v); }
static T Rint(T v) { return floor(v + (T)0.5); }
static T Sign(T v) { return (T)((v<0) ? -1 : (v>0) ? 1 : 0); }
static T Pow(T v1, T v2) { return std::pow(v1, v2); }
};
}
#endif

View file

@ -1,34 +1,34 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2013 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_TEST_H
#define MU_PARSER_TEST_H
#include <string>
#include <cstdlib>
#include <numeric> // for accumulate
#include <numeric> // for accumulate
#include <string>
#include "muParser.h"
#include "muParserInt.h"
@ -36,179 +36,140 @@
\brief This file contains the parser test class.
*/
namespace mu
namespace mu {
/** \brief Namespace for test cases. */
namespace Test {
//------------------------------------------------------------------------------
/** \brief Test cases for unit testing.
(C) 2004-2011 Ingo Berg
*/
class ParserTester // final
{
/** \brief Namespace for test cases. */
namespace Test
{
//------------------------------------------------------------------------------
/** \brief Test cases for unit testing.
private:
static int c_iCount;
(C) 2004-2011 Ingo Berg
*/
class ParserTester // final
{
private:
static int c_iCount;
// Multiarg callbacks
static ValueOrError f1of1(value_type v) { return v; };
// Multiarg callbacks
static value_type f1of1(value_type v) { return v;};
static value_type f1of2(value_type v, value_type ) {return v;};
static value_type f2of2(value_type , value_type v) {return v;};
static ValueOrError f1of2(value_type v, value_type) { return v; };
static ValueOrError f2of2(value_type, value_type v) { return v; };
static value_type f1of3(value_type v, value_type , value_type ) {return v;};
static value_type f2of3(value_type , value_type v, value_type ) {return v;};
static value_type f3of3(value_type , value_type , value_type v) {return v;};
static value_type f1of4(value_type v, value_type, value_type , value_type ) {return v;}
static value_type f2of4(value_type , value_type v, value_type , value_type ) {return v;}
static value_type f3of4(value_type , value_type, value_type v, value_type ) {return v;}
static value_type f4of4(value_type , value_type, value_type , value_type v) {return v;}
static ValueOrError f1of3(value_type v, value_type, value_type) { return v; };
static ValueOrError f2of3(value_type, value_type v, value_type) { return v; };
static ValueOrError f3of3(value_type, value_type, value_type v) { return v; };
static value_type f1of5(value_type v, value_type, value_type , value_type , value_type ) { return v; }
static value_type f2of5(value_type , value_type v, value_type , value_type , value_type ) { return v; }
static value_type f3of5(value_type , value_type, value_type v, value_type , value_type ) { return v; }
static value_type f4of5(value_type , value_type, value_type , value_type v, value_type ) { return v; }
static value_type f5of5(value_type , value_type, value_type , value_type , value_type v) { return v; }
static ValueOrError Min(value_type a_fVal1, value_type a_fVal2) {
return (a_fVal1 < a_fVal2) ? a_fVal1 : a_fVal2;
}
static ValueOrError Max(value_type a_fVal1, value_type a_fVal2) {
return (a_fVal1 > a_fVal2) ? a_fVal1 : a_fVal2;
}
static value_type Min(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1<a_fVal2) ? a_fVal1 : a_fVal2; }
static value_type Max(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1>a_fVal2) ? a_fVal1 : a_fVal2; }
static ValueOrError plus2(value_type v1) { return v1 + 2; }
static ValueOrError times3(value_type v1) { return v1 * 3; }
static ValueOrError sqr(value_type v1) { return v1 * v1; }
static ValueOrError sign(value_type v) { return -v; }
static ValueOrError add(value_type v1, value_type v2) { return v1 + v2; }
static ValueOrError land(value_type v1, value_type v2) { return (int)v1 & (int)v2; }
static value_type plus2(value_type v1) { return v1+2; }
static value_type times3(value_type v1) { return v1*3; }
static value_type sqr(value_type v1) { return v1*v1; }
static value_type sign(value_type v) { return -v; }
static value_type add(value_type v1, value_type v2) { return v1+v2; }
static value_type land(value_type v1, value_type v2) { return (int)v1 & (int)v2; }
static ValueOrError FirstArg(const value_type* a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function FirstArg."));
return a_afArg[0];
}
static value_type FirstArg(const value_type* a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw mu::Parser::exception_type( _T("too few arguments for function FirstArg.") );
static ValueOrError LastArg(const value_type* a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function LastArg."));
return a_afArg[0];
}
return a_afArg[a_iArgc - 1];
}
static value_type LastArg(const value_type* a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw mu::Parser::exception_type( _T("too few arguments for function LastArg.") );
static ValueOrError Sum(const value_type* a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function sum."));
return a_afArg[a_iArgc-1];
}
value_type fRes = 0;
for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i];
return fRes;
}
static value_type Sum(const value_type* a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw mu::Parser::exception_type( _T("too few arguments for function sum.") );
static ValueOrError Rnd(value_type v) {
return (value_type)(1 + (v * std::rand() / (RAND_MAX + 1.0)));
}
value_type fRes=0;
for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];
return fRes;
}
static ValueOrError RndWithString(const char_type*) {
return (value_type)(1 + (1000.0f * std::rand() / (RAND_MAX + 1.0)));
}
static value_type Rnd(value_type v)
{
return (value_type)(1+(v*std::rand()/(RAND_MAX+1.0)));
}
static ValueOrError Ping() { return 10; }
static value_type RndWithString(const char_type*)
{
return (value_type)( 1 + (1000.0f * std::rand() / (RAND_MAX + 1.0) ) );
}
static ValueOrError ValueOf(const char_type*) { return 123; }
static value_type Ping()
{
return 10;
}
static ValueOrError StrFun1(const char_type* v1) {
int val(0);
stringstream_type(v1) >> val;
return (value_type)val;
}
static value_type ValueOf(const char_type*)
{
return 123;
}
static ValueOrError StrFun2(const char_type* v1, value_type v2) {
int val(0);
stringstream_type(v1) >> val;
return (value_type)(val + v2);
}
static value_type StrFun1(const char_type* v1)
{
int val(0);
stringstream_type(v1) >> val;
return (value_type)val;
}
static ValueOrError StrFun3(const char_type* v1, value_type v2, value_type v3) {
int val(0);
stringstream_type(v1) >> val;
return val + v2 + v3;
}
static value_type StrFun2(const char_type* v1, value_type v2)
{
int val(0);
stringstream_type(v1) >> val;
return (value_type)(val + v2);
}
static value_type StrFun3(const char_type* v1, value_type v2, value_type v3)
{
int val(0);
stringstream_type(v1) >> val;
return val + v2 + v3;
}
static ValueOrError StrToFloat(const char_type* a_szMsg) {
value_type val(0);
stringstream_type(a_szMsg) >> val;
return val;
}
static value_type StrToFloat(const char_type* a_szMsg)
{
value_type val(0);
stringstream_type(a_szMsg) >> val;
return val;
}
// postfix operator callback
static ValueOrError Mega(value_type a_fVal) { return a_fVal * (value_type)1e6; }
static ValueOrError Micro(value_type a_fVal) { return a_fVal * (value_type)1e-6; }
static ValueOrError Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
// postfix operator callback
static value_type Mega(value_type a_fVal) { return a_fVal * (value_type)1e6; }
static value_type Micro(value_type a_fVal) { return a_fVal * (value_type)1e-6; }
static value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
// Custom value recognition
static int IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal);
// Custom value recognition
static int IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal);
int TestNames();
int TestSyntax();
int TestMultiArg();
int TestPostFix();
int TestExpression();
int TestInfixOprt();
int TestBinOprt();
int TestInterface();
int TestException();
int TestStrArg();
int TestIfThenElse();
int TestNames();
int TestSyntax();
int TestMultiArg();
int TestPostFix();
int TestExpression();
int TestInfixOprt();
int TestBinOprt();
int TestVarConst();
int TestInterface();
int TestException();
int TestStrArg();
int TestIfThenElse();
int TestBulkMode();
void Abort() const;
void Abort() const;
public:
typedef int (ParserTester::*testfun_type)();
public:
typedef int (ParserTester::*testfun_type)();
ParserTester();
void Run();
ParserTester();
void Run();
private:
std::vector<testfun_type> m_vTestFun;
void AddTest(testfun_type a_pFun);
private:
std::vector<testfun_type> m_vTestFun;
void AddTest(testfun_type a_pFun);
// Test Double Parser
int EqnTest(const string_type& a_str, double a_fRes, bool a_fPass);
int EqnTestWithVarChange(const string_type& a_str, double a_fRes1, double a_fVar1,
double a_fRes2, double a_fVar2);
int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true);
// Test Double Parser
int EqnTest(const string_type& a_str, double a_fRes, bool a_fPass);
int EqnTestWithVarChange(const string_type& a_str,
double a_fRes1,
double a_fVar1,
double a_fRes2,
double a_fVar2);
int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true);
// Test Int Parser
int EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass);
// Test Bulkmode
int EqnTestBulk(const string_type& a_str, double a_fRes[4], bool a_fPass);
};
} // namespace Test
} // namespace mu
// Test Int Parser
int EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass);
};
} // namespace Test
} // namespace mu
#endif

View file

@ -1,129 +1,113 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2004-2013 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_TOKEN_H
#define MU_PARSER_TOKEN_H
#include <cassert>
#include <string>
#include <stack>
#include <vector>
#include <memory>
#include <stack>
#include <string>
#include <vector>
#include "muParserError.h"
#include "muParserCallback.h"
/** \file
\brief This file contains the parser token definition.
*/
namespace mu
{
/** \brief Encapsulation of the data for a single formula token.
namespace mu {
/** \brief Encapsulation of the data for a single formula token.
Formula token implementation. Part of the Math Parser Package.
Formula tokens can be either one of the following:
<ul>
<li>value</li>
<li>variable</li>
<li>function with numerical arguments</li>
<li>functions with a string as argument</li>
<li>prefix operators</li>
<li>infix operators</li>
<li>binary operator</li>
</ul>
Formula token implementation. Part of the Math Parser Package.
Formula tokens can be either one of the following:
<ul>
<li>value</li>
<li>variable</li>
<li>function with numerical arguments</li>
<li>functions with a string as argument</li>
<li>prefix operators</li>
<li>infix operators</li>
<li>binary operator</li>
</ul>
\author (C) 2004-2013 Ingo Berg
*/
template<typename TBase, typename TString>
class ParserToken
{
private:
\author (C) 2004-2013 Ingo Berg
*/
template <typename TBase, typename TString>
class ParserToken {
private:
ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode.
ETypeCode m_iType;
void *m_pTok; ///< Stores Token pointer; not applicable for all tokens
int m_iIdx; ///< An otional index to an external buffer storing the token data
TString m_strTok; ///< Token string
TString m_strVal; ///< Value for string variables
value_type m_fVal; ///< the value
std::unique_ptr<ParserCallback> m_pCallback;
ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode.
ETypeCode m_iType;
void *m_pTok; ///< Stores Token pointer; not applicable for all tokens
int m_iIdx; ///< An otional index to an external buffer storing the token data
TString m_strTok; ///< Token string
TString m_strVal; ///< Value for string variables
value_type m_fVal; ///< the value
std::auto_ptr<ParserCallback> m_pCallback;
public:
//---------------------------------------------------------------------------
/** \brief Constructor (default).
public:
Sets token to an neutral state of type cmUNKNOWN.
\sa ECmdCode
*/
ParserToken()
: m_iCode(cmUNKNOWN),
m_iType(tpVOID),
m_pTok(0),
m_iIdx(-1),
m_strTok(),
m_strVal(),
m_fVal(0),
m_pCallback() {}
//---------------------------------------------------------------------------
/** \brief Constructor (default).
Sets token to an neutral state of type cmUNKNOWN.
\throw nothrow
\sa ECmdCode
*/
ParserToken()
:m_iCode(cmUNKNOWN)
,m_iType(tpVOID)
,m_pTok(0)
,m_iIdx(-1)
,m_strTok()
,m_strVal()
,m_fVal(0)
,m_pCallback()
{}
//------------------------------------------------------------------------------
/** \brief Create token from another one.
//------------------------------------------------------------------------------
/** \brief Create token from another one.
Implemented by calling Assign(...)
\throw nothrow
\post m_iType==cmUNKNOWN
\sa #Assign
*/
ParserToken(const ParserToken &a_Tok)
{
Assign(a_Tok);
}
//------------------------------------------------------------------------------
/** \brief Assignement operator.
Copy token state from another token and return this.
Implemented by calling Assign(...).
\throw nothrow
*/
ParserToken& operator=(const ParserToken &a_Tok)
{
Implemented by calling Assign(...)
\post m_iType==cmUNKNOWN
\sa #Assign
*/
ParserToken(const ParserToken &a_Tok) { Assign(a_Tok); }
//------------------------------------------------------------------------------
/** \brief Assignement operator.
Copy token state from another token and return this.
Implemented by calling Assign(...).
*/
ParserToken &operator=(const ParserToken &a_Tok) {
Assign(a_Tok);
return *this;
}
}
//------------------------------------------------------------------------------
/** \brief Copy token information from argument.
\throw nothrow
*/
void Assign(const ParserToken &a_Tok)
{
//------------------------------------------------------------------------------
/** \brief Copy token information from argument.
*/
void Assign(const ParserToken &a_Tok) {
m_iCode = a_Tok.m_iCode;
m_pTok = a_Tok.m_pTok;
m_strTok = a_Tok.m_strTok;
@ -131,27 +115,26 @@ namespace mu
m_strVal = a_Tok.m_strVal;
m_iType = a_Tok.m_iType;
m_fVal = a_Tok.m_fVal;
// create new callback object if a_Tok has one
m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0);
}
// create new callback object if a_Tok has one
m_pCallback.reset(a_Tok.m_pCallback ? new ParserCallback(*a_Tok.m_pCallback) : nullptr);
}
//------------------------------------------------------------------------------
/** \brief Assign a token type.
//------------------------------------------------------------------------------
/** \brief Assign a token type.
Token may not be of type value, variable or function. Those have seperate set functions.
Token may not be of type value, variable or function. Those have seperate set functions.
\pre [assert] a_iType!=cmVAR
\pre [assert] a_iType!=cmVAL
\pre [assert] a_iType!=cmFUNC
\post m_fVal = 0
\post m_pTok = 0
*/
ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString())
{
\pre [assert] a_iType!=cmVAR
\pre [assert] a_iType!=cmVAL
\pre [assert] a_iType!=cmFUNC
\post m_fVal = 0
\post m_pTok = 0
*/
ParserToken &Set(ECmdCode a_iType, const TString &a_strTok = TString()) {
// The following types cant be set this way, they have special Set functions
assert(a_iType!=cmVAR);
assert(a_iType!=cmVAL);
assert(a_iType!=cmFUNC);
assert(a_iType != cmVAR);
assert(a_iType != cmVAL);
assert(a_iType != cmFUNC);
m_iCode = a_iType;
m_iType = tpVOID;
@ -160,12 +143,11 @@ namespace mu
m_iIdx = -1;
return *this;
}
}
//------------------------------------------------------------------------------
/** \brief Set Callback type. */
ParserToken& Set(const ParserCallback &a_pCallback, const TString &a_sTok)
{
//------------------------------------------------------------------------------
/** \brief Set Callback type. */
ParserToken &Set(const ParserCallback &a_pCallback, const TString &a_sTok) {
assert(a_pCallback.GetAddr());
m_iCode = a_pCallback.GetCode();
@ -175,55 +157,49 @@ namespace mu
m_pTok = 0;
m_iIdx = -1;
return *this;
}
//------------------------------------------------------------------------------
/** \brief Make this token a value token.
Member variables not necessary for value tokens will be invalidated.
\throw nothrow
*/
ParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString())
{
return *this;
}
//------------------------------------------------------------------------------
/** \brief Make this token a value token.
Member variables not necessary for value tokens will be invalidated.
*/
ParserToken &SetVal(TBase a_fVal, const TString &a_strTok = TString()) {
m_iCode = cmVAL;
m_iType = tpDBL;
m_fVal = a_fVal;
m_strTok = a_strTok;
m_iIdx = -1;
m_pTok = 0;
m_pCallback.reset(0);
return *this;
}
}
//------------------------------------------------------------------------------
/** \brief make this token a variable token.
Member variables not necessary for variable tokens will be invalidated.
\throw nothrow
*/
ParserToken& SetVar(TBase *a_pVar, const TString &a_strTok)
{
//------------------------------------------------------------------------------
/** \brief make this token a variable token.
Member variables not necessary for variable tokens will be invalidated.
*/
ParserToken &SetVar(TBase *a_pVar, const TString &a_strTok) {
m_iCode = cmVAR;
m_iType = tpDBL;
m_strTok = a_strTok;
m_iIdx = -1;
m_pTok = (void*)a_pVar;
m_pTok = (void *)a_pVar;
m_pCallback.reset(0);
return *this;
}
}
//------------------------------------------------------------------------------
/** \brief Make this token a variable token.
Member variables not necessary for variable tokens will be invalidated.
\throw nothrow
*/
ParserToken& SetString(const TString &a_strTok, std::size_t a_iSize)
{
//------------------------------------------------------------------------------
/** \brief Make this token a variable token.
Member variables not necessary for variable tokens will be invalidated.
*/
ParserToken &SetString(const TString &a_strTok, std::size_t a_iSize) {
m_iCode = cmSTRING;
m_iType = tpSTR;
m_strTok = a_strTok;
@ -232,170 +208,136 @@ namespace mu
m_pTok = 0;
m_pCallback.reset(0);
return *this;
}
}
//------------------------------------------------------------------------------
/** \brief Set an index associated with the token related data.
In cmSTRFUNC - This is the index to a string table in the main parser.
\param a_iIdx The index the string function result will take in the bytecode parser.
\throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING
*/
void SetIdx(int a_iIdx) {
if (m_iCode != cmSTRING || a_iIdx < 0) assert(0 && "muParser internal error");
//------------------------------------------------------------------------------
/** \brief Set an index associated with the token related data.
In cmSTRFUNC - This is the index to a string table in the main parser.
\param a_iIdx The index the string function result will take in the bytecode parser.
\throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING
*/
void SetIdx(int a_iIdx)
{
if (m_iCode!=cmSTRING || a_iIdx<0)
throw ParserError(ecINTERNAL_ERROR);
m_iIdx = a_iIdx;
}
}
//------------------------------------------------------------------------------
/** \brief Return Index associated with the token related data.
In cmSTRFUNC - This is the index to a string table in the main parser.
//------------------------------------------------------------------------------
/** \brief Return Index associated with the token related data.
\throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING
\return The index the result will take in the Bytecode calculatin array (#m_iIdx).
*/
int GetIdx() const
{
if (m_iIdx<0 || m_iCode!=cmSTRING )
throw ParserError(ecINTERNAL_ERROR);
In cmSTRFUNC - This is the index to a string table in the main parser.
\throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING
\return The index the result will take in the Bytecode calculatin array (#m_iIdx).
*/
int GetIdx() const {
if (m_iIdx < 0 || m_iCode != cmSTRING) assert(0 && "muParser internal error");
return m_iIdx;
}
}
//------------------------------------------------------------------------------
/** \brief Return the token type.
\return #m_iType
\throw nothrow
*/
ECmdCode GetCode() const
{
if (m_pCallback.get())
{
return m_pCallback->GetCode();
}
else
{
return m_iCode;
}
}
//------------------------------------------------------------------------------
/** \brief Return the token type.
//------------------------------------------------------------------------------
ETypeCode GetType() const
{
if (m_pCallback.get())
{
return m_pCallback->GetType();
\return #m_iType
*/
ECmdCode GetCode() const {
if (m_pCallback.get()) {
return m_pCallback->GetCode();
} else {
return m_iCode;
}
else
{
return m_iType;
}
//------------------------------------------------------------------------------
ETypeCode GetType() const {
if (m_pCallback.get()) {
return m_pCallback->GetType();
} else {
return m_iType;
}
}
//------------------------------------------------------------------------------
int GetPri() const
{
if ( !m_pCallback.get())
throw ParserError(ecINTERNAL_ERROR);
if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX)
throw ParserError(ecINTERNAL_ERROR);
}
//------------------------------------------------------------------------------
int GetPri() const {
if (!m_pCallback.get()) assert(0 && "muParser internal error");
if (m_pCallback->GetCode() != cmOPRT_BIN && m_pCallback->GetCode() != cmOPRT_INFIX)
assert(0 && "muParser internal error");
return m_pCallback->GetPri();
}
}
//------------------------------------------------------------------------------
EOprtAssociativity GetAssociativity() const
{
if (m_pCallback.get()==NULL || m_pCallback->GetCode()!=cmOPRT_BIN)
throw ParserError(ecINTERNAL_ERROR);
//------------------------------------------------------------------------------
EOprtAssociativity GetAssociativity() const {
if (m_pCallback.get() == NULL || m_pCallback->GetCode() != cmOPRT_BIN)
assert(0 && "muParser internal error");
return m_pCallback->GetAssociativity();
}
}
//------------------------------------------------------------------------------
/** \brief Return the address of the callback function assoziated with
function and operator tokens.
//------------------------------------------------------------------------------
/** \brief Return the address of the callback function assoziated with
function and operator tokens.
\return The pointer stored in #m_pTok.
\throw exception_type if token type is non of:
<ul>
<li>cmFUNC</li>
<li>cmSTRFUNC</li>
<li>cmPOSTOP</li>
<li>cmINFIXOP</li>
<li>cmOPRT_BIN</li>
</ul>
\sa ECmdCode
*/
generic_fun_type GetFuncAddr() const
{
return (m_pCallback.get()) ? (generic_fun_type)m_pCallback->GetAddr() : 0;
}
\return The pointer stored in #m_pTok.
*/
generic_fun_type GetFuncAddr() const {
return m_pCallback ? (generic_fun_type)m_pCallback->GetAddr() : nullptr;
}
//------------------------------------------------------------------------------
/** \biref Get value of the token.
Only applicable to variable and value tokens.
\throw exception_type if token is no value/variable token.
*/
TBase GetVal() const
{
switch (m_iCode)
{
case cmVAL: return m_fVal;
case cmVAR: return *((TBase*)m_pTok);
default: throw ParserError(ecVAL_EXPECTED);
//------------------------------------------------------------------------------
/** \brifef Get value of the token.
Only applicable to variable and value tokens.
*/
ValueOrError GetVal() const {
switch (m_iCode) {
case cmVAL:
return m_fVal;
case cmVAR:
return *((TBase *)m_pTok);
default:
return ParserError(ecVAL_EXPECTED);
}
}
}
//------------------------------------------------------------------------------
/** \brief Get address of a variable token.
//------------------------------------------------------------------------------
/** \brief Get address of a variable token.
Valid only if m_iType==CmdVar.
\throw exception_type if token is no variable token.
*/
TBase* GetVar() const
{
if (m_iCode!=cmVAR)
throw ParserError(ecINTERNAL_ERROR);
Valid only if m_iType==CmdVar.
\throw exception_type if token is no variable token.
*/
TBase *GetVar() const {
if (m_iCode != cmVAR) assert(0 && "muParser internal error");
return (TBase*)m_pTok;
}
return (TBase *)m_pTok;
}
//------------------------------------------------------------------------------
/** \brief Return the number of function arguments.
//------------------------------------------------------------------------------
/** \brief Return the number of function arguments.
Valid only if m_iType==CmdFUNC.
*/
int GetArgCount() const
{
Valid only if m_iType==CmdFUNC.
*/
int GetArgCount() const {
assert(m_pCallback.get());
if (!m_pCallback->GetAddr())
throw ParserError(ecINTERNAL_ERROR);
if (!m_pCallback->GetAddr()) assert(0 && "muParser internal error");
return m_pCallback->GetArgc();
}
}
//------------------------------------------------------------------------------
/** \brief Return the token identifier.
If #m_iType is cmSTRING the token identifier is the value of the string argument
for a string function.
\return #m_strTok
\throw nothrow
\sa m_strTok
*/
const TString& GetAsString() const
{
return m_strTok;
}
};
} // namespace mu
//------------------------------------------------------------------------------
/** \brief Return the token identifier.
If #m_iType is cmSTRING the token identifier is the value of the string argument
for a string function.
\return #m_strTok
\sa m_strTok
*/
const TString &GetAsString() const { return m_strTok; }
};
} // namespace mu
#endif

View file

@ -1,26 +1,26 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2004-2013 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MU_PARSER_TOKEN_READER_H
@ -42,120 +42,111 @@
\brief This file contains the parser token reader definition.
*/
namespace mu {
// Forward declaration
class ParserBase;
namespace mu
{
// Forward declaration
class ParserBase;
/** \brief Token reader for the ParserBase class.
*/
class ParserTokenReader final {
private:
typedef ParserToken<value_type, string_type> token_type;
/** \brief Token reader for the ParserBase class.
public:
ParserTokenReader(ParserBase *a_pParent);
*/
class ParserTokenReader
{
private:
void AddValIdent(identfun_type a_pCallback);
void SetVarCreator(facfun_type a_pFactory, void *pUserData);
void SetFormula(const string_type &a_strFormula);
void SetArgSep(char_type cArgSep);
typedef ParserToken<value_type, string_type> token_type;
int GetPos() const;
const string_type &GetExpr() const;
char_type GetArgSep() const;
public:
void IgnoreUndefVar(bool bIgnore);
void ReInit();
token_type ReadNextToken();
ParserTokenReader(ParserBase *a_pParent);
ParserTokenReader* Clone(ParserBase *a_pParent) const;
/// \return the first error (if any), clearing it.
OptionalError acquireFirstError() {
OptionalError ret = std::move(firstError_);
firstError_ = OptionalError{};
return ret;
}
void AddValIdent(identfun_type a_pCallback);
void SetVarCreator(facfun_type a_pFactory, void *pUserData);
void SetFormula(const string_type &a_strFormula);
void SetArgSep(char_type cArgSep);
private:
/** \brief Syntax codes.
int GetPos() const;
const string_type& GetExpr() const;
varmap_type& GetUsedVar();
char_type GetArgSep() const;
void IgnoreUndefVar(bool bIgnore);
void ReInit();
token_type ReadNextToken();
private:
/** \brief Syntax codes.
The syntax codes control the syntax check done during the first time parsing of
the expression string. They are flags that indicate which tokens are allowed next
if certain tokens are identified.
*/
enum ESynCodes
{
noBO = 1 << 0, ///< to avoid i.e. "cos(7)("
noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()"
noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14"
noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a"
The syntax codes control the syntax check done during the first time parsing of
the expression string. They are flags that indicate which tokens are allowed next
if certain tokens are identified.
*/
enum ESynCodes {
noBO = 1 << 0, ///< to avoid i.e. "cos(7)("
noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()"
noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14"
noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a"
noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ...
noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin"
noOPT = 1 << 6, ///< to avoid i.e. "(+)"
noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!"
noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4"
noEND = 1 << 9, ///< to avoid unexpected end of formula
noSTR = 1 << 10, ///< to block numeric arguments on string functions
noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7"
noIF = 1 << 12,
noELSE = 1 << 13,
noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin"
noOPT = 1 << 6, ///< to avoid i.e. "(+)"
noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!"
noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4"
noEND = 1 << 9, ///< to avoid unexpected end of formula
noSTR = 1 << 10, ///< to block numeric arguments on string functions
noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7"
noIF = 1 << 12,
noELSE = 1 << 13,
sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP,
noANY = ~0 ///< All of he above flags set
};
noANY = ~0 ///< All of he above flags set
};
ParserTokenReader(const ParserTokenReader &a_Reader);
ParserTokenReader& operator=(const ParserTokenReader &a_Reader);
void Assign(const ParserTokenReader &a_Reader);
ParserTokenReader(const ParserTokenReader &a_Reader) = delete;
ParserTokenReader &operator=(const ParserTokenReader &a_Reader) = delete;
void SetParent(ParserBase *a_pParent);
int ExtractToken(const char_type *a_szCharSet,
string_type &a_strTok,
int a_iPos) const;
int ExtractOperatorToken(string_type &a_sTok, int a_iPos) const;
void SetParent(ParserBase *a_pParent);
int ExtractToken(const char_type *a_szCharSet, string_type &a_strTok, int a_iPos) const;
int ExtractOperatorToken(string_type &a_sTok, int a_iPos) const;
bool IsBuiltIn(token_type &a_Tok);
bool IsArgSep(token_type &a_Tok);
bool IsEOF(token_type &a_Tok);
bool IsInfixOpTok(token_type &a_Tok);
bool IsFunTok(token_type &a_Tok);
bool IsPostOpTok(token_type &a_Tok);
bool IsOprt(token_type &a_Tok);
bool IsValTok(token_type &a_Tok);
bool IsVarTok(token_type &a_Tok);
bool IsStrVarTok(token_type &a_Tok);
bool IsUndefVarTok(token_type &a_Tok);
bool IsString(token_type &a_Tok);
void Error(EErrorCodes a_iErrc,
int a_iPos = -1,
const string_type &a_sTok = string_type() ) const;
bool IsBuiltIn(token_type &a_Tok);
bool IsArgSep(token_type &a_Tok);
bool IsEOF(token_type &a_Tok);
bool IsInfixOpTok(token_type &a_Tok);
bool IsFunTok(token_type &a_Tok);
bool IsPostOpTok(token_type &a_Tok);
bool IsOprt(token_type &a_Tok);
bool IsValTok(token_type &a_Tok);
bool IsVarTok(token_type &a_Tok);
bool IsStrVarTok(token_type &a_Tok);
bool IsUndefVarTok(token_type &a_Tok);
bool IsString(token_type &a_Tok);
bool Error(EErrorCodes a_iErrc, int a_iPos = -1, const string_type &a_sTok = string_type());
token_type& SaveBeforeReturn(const token_type &tok);
token_type &SaveBeforeReturn(const token_type &tok);
ParserBase *m_pParser;
string_type m_strFormula;
int m_iPos;
int m_iSynFlags;
bool m_bIgnoreUndefVar;
ParserBase *m_pParser;
string_type m_strFormula;
int m_iPos = 0;
int m_iSynFlags = 0;
bool m_bIgnoreUndefVar = false;
const funmap_type *m_pFunDef;
const funmap_type *m_pPostOprtDef;
const funmap_type *m_pInfixOprtDef;
const funmap_type *m_pOprtDef;
const valmap_type *m_pConstDef;
const strmap_type *m_pStrVarDef;
varmap_type *m_pVarDef; ///< The only non const pointer to parser internals
facfun_type m_pFactory;
void *m_pFactoryData;
std::list<identfun_type> m_vIdentFun; ///< Value token identification function
varmap_type m_UsedVar;
value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables
int m_iBrackets;
token_type m_lastTok;
char_type m_cArgSep; ///< The character used for separating function arguments
};
} // namespace mu
OptionalError firstError_; /// The first error reported during parsing.
const funmap_type *m_pFunDef = nullptr;
const funmap_type *m_pPostOprtDef = nullptr;
const funmap_type *m_pInfixOprtDef = nullptr;
const funmap_type *m_pOprtDef = nullptr;
const valmap_type *m_pConstDef = nullptr;
const strmap_type *m_pStrVarDef = nullptr;
varmap_type *m_pVarDef = nullptr; ///< The only non const pointer to parser internals
facfun_type m_pFactory = nullptr;
void *m_pFactoryData = nullptr;
std::list<identfun_type> m_vIdentFun; ///< Value token identification function
varmap_type m_UsedVar;
value_type m_fZero = 0; ///< Dummy value of zero, referenced by undefined variables
int m_iBrackets = 0;
token_type m_lastTok;
char_type m_cArgSep = ','; ///< The character used for separating function arguments
};
} // namespace mu
#endif

View file

@ -1,11 +1,11 @@
//---------------------------------------------------------------------------
//
// __________
// _____ __ __\______ \_____ _______ ______ ____ _______
// / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
// __________
// _____ __ __\______ \_____ _______ ______ ____ _______
// / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ |
// | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
// |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
// \/ \/ \/ \/
// |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
// \/ \/ \/ \/
// (C) 2015 Ingo Berg
//
// example1.cpp - using the parser as a static library
@ -15,578 +15,339 @@
#include "muParserTest.h"
#if defined(_WIN32) && defined(_DEBUG)
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#define CREATE_LEAKAGE_REPORT
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <stdlib.h>
#define CREATE_LEAKAGE_REPORT
#endif
#if defined( USINGDLL ) && defined( _WIN32 )
#if defined(USINGDLL) && defined(_WIN32)
#error This sample can be used only with STATIC builds of muParser (on win32)
#endif
/** \brief This macro will enable mathematical constants like M_PI. */
#define _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <locale>
#include <limits>
#include <ios>
#include <iomanip>
#include <ios>
#include <iostream>
#include <limits>
#include <locale>
#include <numeric>
#include <string>
#include "muParser.h"
using namespace std;
using namespace mu;
#if defined(CREATE_LEAKAGE_REPORT)
// Dumping memory leaks in the destructor of the static guard
// guarantees i won't get false positives from the ParserErrorMsg
// guarantees i won't get false positives from the ParserErrorMsg
// class wich is a singleton with a static instance.
struct DumpLeaks
{
~DumpLeaks()
{
_CrtDumpMemoryLeaks();
}
struct DumpLeaks {
~DumpLeaks() { _CrtDumpMemoryLeaks(); }
} static LeakDumper;
#endif
// Forward declarations
void CalcBulk();
// Operator callback functions
value_type Mega(value_type a_fVal) { return a_fVal * 1e6; }
value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
value_type Rnd(value_type v) { return v*std::rand()/(value_type)(RAND_MAX+1.0); }
value_type Not(value_type v) { return v==0; }
value_type Add(value_type v1, value_type v2) { return v1+v2; }
value_type Mul(value_type v1, value_type v2) { return v1*v2; }
ValueOrError Mega(value_type a_fVal) { return a_fVal * 1e6; }
ValueOrError Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
ValueOrError Rnd(value_type v) { return v * std::rand() / (value_type)(RAND_MAX + 1.0); }
ValueOrError Not(value_type v) { return v == 0; }
ValueOrError Add(value_type v1, value_type v2) { return v1 + v2; }
ValueOrError Mul(value_type v1, value_type v2) { return v1 * v2; }
//---------------------------------------------------------------------------
value_type ThrowAnException(value_type)
{
throw std::runtime_error("This function does throw an exception.");
ValueOrError ThrowAnException(value_type) {
throw std::runtime_error("This function does throw an exception.");
}
//---------------------------------------------------------------------------
value_type BulkFun1(int nBulkIdx, int nThreadIdx, value_type v1)
{
// Note: I'm just doing something with all three parameters to shut
// compiler warnings up!
return nBulkIdx + nThreadIdx + v1;
//---------------------------------------------------------------------------
ValueOrError Ping() {
mu::console() << "ping\n";
return 0;
}
//---------------------------------------------------------------------------
value_type Ping()
{
mu::console() << "ping\n";
return 0;
ValueOrError StrFun0(const char_type *szMsg) {
if (szMsg) mu::console() << szMsg << std::endl;
return 999;
}
//---------------------------------------------------------------------------
value_type StrFun0(const char_type *szMsg)
{
if (szMsg)
mu::console() << szMsg << std::endl;
return 999;
ValueOrError StrFun2(const char_type *v1, value_type v2, value_type v3) {
mu::console() << v1 << std::endl;
return v2 + v3;
}
//---------------------------------------------------------------------------
value_type StrFun2(const char_type *v1, value_type v2,value_type v3)
{
mu::console() << v1 << std::endl;
return v2+v3;
}
//---------------------------------------------------------------------------
value_type Debug(mu::value_type v1, mu::value_type v2)
{
ParserBase::EnableDebugDump(v1!=0, v2!=0);
mu::console() << _T("Bytecode dumping ") << ((v1!=0) ? _T("active") : _T("inactive")) << _T("\n");
return 1;
ValueOrError Debug(mu::value_type v1, mu::value_type v2) {
ParserBase::EnableDebugDump(v1 != 0, v2 != 0);
mu::console() << _T("Bytecode dumping ") << ((v1 != 0) ? _T("active") : _T("inactive"))
<< _T("\n");
return 1;
}
//---------------------------------------------------------------------------
// Factory function for creating new parser variables
// This could as well be a function performing database queries.
value_type* AddVariable(const char_type *a_szName, void *a_pUserData)
{
// I don't want dynamic allocation here, so i used this static buffer
// If you want dynamic allocation you must allocate all variables dynamically
// in order to delete them later on. Or you find other ways to keep track of
// variables that have been created implicitely.
static value_type afValBuf[100];
static int iVal = -1;
value_type *AddVariable(const char_type *a_szName, void *a_pUserData) {
// I don't want dynamic allocation here, so i used this static buffer
// If you want dynamic allocation you must allocate all variables dynamically
// in order to delete them later on. Or you find other ways to keep track of
// variables that have been created implicitely.
static value_type afValBuf[100];
static int iVal = -1;
++iVal;
++iVal;
mu::console() << _T("Generating new variable \"")
<< a_szName << std::dec << _T("\" (slots left: ")
<< 99-iVal << _T(")")
<< _T(" User data pointer is:")
<< std::hex << a_pUserData <<endl;
afValBuf[iVal] = 0;
mu::console() << _T("Generating new variable \"") << a_szName << std::dec
<< _T("\" (slots left: ") << 99 - iVal << _T(")")
<< _T(" User data pointer is:") << std::hex << a_pUserData << endl;
afValBuf[iVal] = 0;
if (iVal>=99)
throw mu::ParserError( _T("Variable buffer overflow.") );
else
return &afValBuf[iVal];
if (iVal >= 99)
throw mu::ParserError(_T("Variable buffer overflow."));
else
return &afValBuf[iVal];
}
int IsHexValue(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)
{
if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') )
return 0;
int IsHexValue(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) {
if (a_szExpr[1] == 0 || (a_szExpr[0] != '0' || a_szExpr[1] != 'x')) return 0;
unsigned iVal(0);
unsigned iVal(0);
// New code based on streams for UNICODE compliance:
stringstream_type::pos_type nPos(0);
stringstream_type ss(a_szExpr + 2);
ss >> std::hex >> iVal;
nPos = ss.tellg();
// New code based on streams for UNICODE compliance:
stringstream_type::pos_type nPos(0);
stringstream_type ss(a_szExpr + 2);
ss >> std::hex >> iVal;
nPos = ss.tellg();
if (nPos == (stringstream_type::pos_type)0) return 1;
*a_iPos += (int)(2 + nPos);
*a_fVal = (value_type)iVal;
if (nPos==(stringstream_type::pos_type)0)
return 1;
*a_iPos += (int)(2 + nPos);
*a_fVal = (value_type)iVal;
return 1;
}
//---------------------------------------------------------------------------
void Splash()
{
mu::console() << _T(" __________ \n");
mu::console() << _T(" _____ __ __\\______ \\_____ _______ ______ ____ _______\n");
mu::console() << _T(" / \\ | | \\| ___/\\__ \\ \\_ __ \\/ ___/_/ __ \\\\_ __ \\ \n");
mu::console() << _T(" | Y Y \\| | /| | / __ \\_| | \\/\\___ \\ \\ ___/ | | \\/ \n");
mu::console() << _T(" |__|_| /|____/ |____| (____ /|__| /____ > \\___ >|__| \n");
mu::console() << _T(" \\/ \\/ \\/ \\/ \n");
mu::console() << _T(" Version ") << Parser().GetVersion(pviFULL) << _T("\n");
mu::console() << _T(" (C) 2015 Ingo Berg\n");
void Splash() {
mu::console() << _T(" __________ \n");
mu::console() << _T(" _____ __ __\\______ \\_____ _______ ______ ____ _______\n");
mu::console()
<< _T(" / \\ | | \\| ___/\\__ \\ \\_ __ \\/ ___/_/ __ \\\\_ __ \\ \n");
mu::console()
<< _T(" | Y Y \\| | /| | / __ \\_| | \\/\\___ \\ \\ ___/ | | \\/ \n");
mu::console() << _T(" |__|_| /|____/ |____| (____ /|__| /____ > \\___ >|__| \n");
mu::console() << _T(" \\/ \\/ \\/ \\/ \n");
mu::console() << _T(" (C) 2015 Ingo Berg\n");
}
//---------------------------------------------------------------------------
value_type SelfTest()
{
mu::console() << _T( "-----------------------------------------------------------\n");
mu::console() << _T( "Running test suite:\n\n");
ValueOrError SelfTest() {
mu::console() << _T( "-----------------------------------------------------------\n");
mu::console() << _T( "Running test suite:\n\n");
// Skip the self test if the value type is set to an integer type.
if (mu::TypeInfo<mu::value_type>::IsInteger())
{
mu::console() << _T( " Test skipped: integer data type are not compatible with the unit test!\n\n");
}
else
{
mu::Test::ParserTester pt;
pt.Run();
}
// Skip the self test if the value type is set to an integer type.
if (std::numeric_limits<mu::value_type>::is_integer) {
mu::console()
<< _T( " Test skipped: integer data type are not compatible with the unit test!\n\n");
} else {
mu::Test::ParserTester pt;
pt.Run();
}
return 0;
return 0;
}
//---------------------------------------------------------------------------
value_type Help()
{
mu::console() << _T( "-----------------------------------------------------------\n");
mu::console() << _T( "Commands:\n\n");
mu::console() << _T( " list var - list parser variables\n");
mu::console() << _T( " list exprvar - list expression variables\n");
mu::console() << _T( " list const - list all numeric parser constants\n");
mu::console() << _T( " opt on - enable optimizer (default)\n");
mu::console() << _T( " opt off - disable optimizer\n");
mu::console() << _T( " locale de - switch to german locale\n");
mu::console() << _T( " locale en - switch to english locale\n");
mu::console() << _T( " locale reset - reset locale\n");
mu::console() << _T( " test bulk - test bulk mode\n");
mu::console() << _T( " quit - exits the parser\n");
mu::console() << _T( "\nConstants:\n\n");
mu::console() << _T( " \"_e\" 2.718281828459045235360287\n");
mu::console() << _T( " \"_pi\" 3.141592653589793238462643\n");
mu::console() << _T( "-----------------------------------------------------------\n");
return 0;
}
//---------------------------------------------------------------------------
/*
void CheckLocale()
{
// Local names:
// "C" - the classic C locale
// "de_DE" - not for Windows?
// "en_US" - not for Windows?
// "German_germany" - For MSVC8
try
{
std::locale loc("German_germany");
console() << _T("Locale settings:\n");
console() << _T(" Decimal point: '") << std::use_facet<numpunct<char_type> >(loc).decimal_point() << _T("'\n");
console() << _T(" Thousands sep: '") << std::use_facet<numpunct<char_type> >(loc).thousands_sep() << _T("'\n");
console() << _T(" Grouping: '") << std::use_facet<numpunct<char_type> >(loc).grouping() << _T("'\n");
console() << _T(" True is named: '") << std::use_facet<numpunct<char_type> >(loc).truename() << _T("'\n");
console() << _T(" False is named: '") << std::use_facet<numpunct<char_type> >(loc).falsename() << _T("'\n");
console() << _T("-----------------------------------------------------------\n");
}
catch(...)
{
console() << _T("Locale settings:\n");
console() << _T(" invalid locale name\n");
console() << _T("-----------------------------------------------------------\n");
}
}
//---------------------------------------------------------------------------
void CheckDiff()
{
mu::Parser parser;
value_type x = 1,
v1,
v2,
v3,
eps(pow(std::numeric_limits<value_type>::epsilon(), 0.2));
parser.DefineVar(_T("x"), &x);
parser.SetExpr(_T("_e^-x*sin(x)"));
v1 = parser.Diff(&x, 1),
v2 = parser.Diff(&x, 1, eps);
v3 = cos((value_type)1.0)/exp((value_type)1) - sin((value_type)1.0)/exp((value_type)1); //-0.110793765307;
mu::console() << parser.GetExpr() << _T("\n");
mu::console() << _T("v1 = ") << v1 << _T("; v1-v3 = ") << v1-v3 << _T("\n");
mu::console() << _T("v2 = ") << v2 << _T("; v2-v3 = ") << v2-v3 << _T("\n");
}
*/
//---------------------------------------------------------------------------
void ListVar(const mu::ParserBase &parser)
{
// Query the used variables (must be done after calc)
mu::varmap_type variables = parser.GetVar();
if (!variables.size())
return;
cout << "\nParser variables:\n";
cout << "-----------------\n";
cout << "Number: " << (int)variables.size() << "\n";
varmap_type::const_iterator item = variables.begin();
for (; item!=variables.end(); ++item)
mu::console() << _T("Name: ") << item->first << _T(" Address: [0x") << item->second << _T("]\n");
}
//---------------------------------------------------------------------------
void ListConst(const mu::ParserBase &parser)
{
mu::console() << _T("\nParser constants:\n");
mu::console() << _T("-----------------\n");
mu::valmap_type cmap = parser.GetConst();
if (!cmap.size())
{
mu::console() << _T("Expression does not contain constants\n");
}
else
{
valmap_type::const_iterator item = cmap.begin();
for (; item!=cmap.end(); ++item)
mu::console() << _T(" ") << item->first << _T(" = ") << item->second << _T("\n");
}
}
//---------------------------------------------------------------------------
void ListExprVar(const mu::ParserBase &parser)
{
string_type sExpr = parser.GetExpr();
if (sExpr.length()==0)
{
cout << _T("Expression string is empty\n");
return;
}
// Query the used variables (must be done after calc)
mu::console() << _T("\nExpression variables:\n");
mu::console() << _T("---------------------\n");
mu::console() << _T("Expression: ") << parser.GetExpr() << _T("\n");
varmap_type variables = parser.GetUsedVar();
if (!variables.size())
{
mu::console() << _T("Expression does not contain variables\n");
}
else
{
mu::console() << _T("Number: ") << (int)variables.size() << _T("\n");
mu::varmap_type::const_iterator item = variables.begin();
for (; item!=variables.end(); ++item)
mu::console() << _T("Name: ") << item->first << _T(" Address: [0x") << item->second << _T("]\n");
}
ValueOrError Help() {
mu::console() << _T( "-----------------------------------------------------------\n");
mu::console() << _T( "Commands:\n\n");
mu::console() << _T( " list var - list parser variables\n");
mu::console() << _T( " list exprvar - list expression variables\n");
mu::console() << _T( " list const - list all numeric parser constants\n");
mu::console() << _T( " locale de - switch to german locale\n");
mu::console() << _T( " locale en - switch to english locale\n");
mu::console() << _T( " locale reset - reset locale\n");
mu::console() << _T( " quit - exits the parser\n");
mu::console() << _T( "\nConstants:\n\n");
mu::console() << _T( " \"_e\" 2.718281828459045235360287\n");
mu::console() << _T( " \"_pi\" 3.141592653589793238462643\n");
mu::console() << _T( "-----------------------------------------------------------\n");
return 0;
}
//---------------------------------------------------------------------------
/** \brief Check for external keywords.
*/
int CheckKeywords(const mu::char_type *a_szLine, mu::Parser &a_Parser)
{
string_type sLine(a_szLine);
int CheckKeywords(const mu::char_type *a_szLine, mu::Parser &a_Parser) {
string_type sLine(a_szLine);
if ( sLine == _T("quit") )
{
return -1;
}
else if ( sLine == _T("list var") )
{
ListVar(a_Parser);
return 1;
}
else if ( sLine == _T("opt on") )
{
a_Parser.EnableOptimizer(true);
mu::console() << _T("Optimizer enabled\n");
return 1;
}
else if ( sLine == _T("opt off") )
{
a_Parser.EnableOptimizer(false);
mu::console() << _T("Optimizer disabled\n");
return 1;
}
else if ( sLine == _T("list const") )
{
ListConst(a_Parser);
return 1;
}
else if ( sLine == _T("list exprvar") )
{
ListExprVar(a_Parser);
return 1;
}
else if ( sLine == _T("locale de") )
{
mu::console() << _T("Setting german locale: ArgSep=';' DecSep=',' ThousandsSep='.'\n");
a_Parser.SetArgSep(';');
a_Parser.SetDecSep(',');
a_Parser.SetThousandsSep('.');
return 1;
}
else if ( sLine == _T("locale en") )
{
mu::console() << _T("Setting english locale: ArgSep=',' DecSep='.' ThousandsSep=''\n");
a_Parser.SetArgSep(',');
a_Parser.SetDecSep('.');
a_Parser.SetThousandsSep();
return 1;
}
else if ( sLine == _T("locale reset") )
{
mu::console() << _T("Resetting locale\n");
a_Parser.ResetLocale();
return 1;
}
else if ( sLine == _T("test bulk") )
{
mu::console() << _T("Testing bulk mode\n");
CalcBulk();
return 1;
}
if (sLine == _T("quit")) {
return -1;
} else if (sLine == _T("locale de")) {
mu::console() << _T("Setting german locale: ArgSep=';' DecSep=',' ThousandsSep='.'\n");
a_Parser.SetArgSep(';');
a_Parser.SetDecSep(',');
a_Parser.SetThousandsSep('.');
return 1;
} else if (sLine == _T("locale en")) {
mu::console() << _T("Setting english locale: ArgSep=',' DecSep='.' ThousandsSep=''\n");
a_Parser.SetArgSep(',');
a_Parser.SetDecSep('.');
a_Parser.SetThousandsSep();
return 1;
} else if (sLine == _T("locale reset")) {
mu::console() << _T("Resetting locale\n");
a_Parser.ResetLocale();
return 1;
}
return 0;
return 0;
}
//---------------------------------------------------------------------------
void CalcBulk()
{
const int nBulkSize = 200;
value_type *x = new value_type[nBulkSize];
value_type *y = new value_type[nBulkSize];
value_type *result = new value_type[nBulkSize];
void Calc() {
mu::Parser parser;
try
{
for (int i=0; i<nBulkSize; ++i)
{
x[i] = i;
y[i] = (value_type)i/10;
}
mu::Parser parser;
parser.DefineVar(_T("x"), x);
parser.DefineVar(_T("y"), y);
parser.DefineFun(_T("fun1"), BulkFun1);
parser.SetExpr(_T("fun1(0)+x+y"));
parser.Eval(result, nBulkSize);
for (int i=0; i<nBulkSize; ++i)
{
mu::console() << _T("Eqn. ") << i << _T(": x=") << x[i] << _T("; y=") << y[i] << _T("; result=") << result[i] << _T("\n");
}
}
catch(...)
{
delete [] x;
delete [] y;
delete [] result;
throw;
}
delete [] x;
delete [] y;
delete [] result;
}
//---------------------------------------------------------------------------
void Calc()
{
mu::Parser parser;
// Change locale settings if necessary
// function argument separator: sum(2;3;4) vs. sum(2,3,4)
// decimal separator: 3,14 vs. 3.14
// thousands separator: 1000000 vs 1.000.000
// Change locale settings if necessary
// function argument separator: sum(2;3;4) vs. sum(2,3,4)
// decimal separator: 3,14 vs. 3.14
// thousands separator: 1000000 vs 1.000.000
//#define USE_GERMAN_LOCALE
#ifdef USE_GERMAN_LOCALE
parser.SetArgSep(';');
parser.SetDecSep(',');
parser.SetThousandsSep('.');
#ifdef USE_GERMAN_LOCALE
parser.SetArgSep(';');
parser.SetDecSep(',');
parser.SetThousandsSep('.');
#else
// this is the default, so i it's commented:
//parser.SetArgSep(',');
//parser.SetDecSep('.');
//parser.SetThousandsSep('');
// this is the default, so i it's commented:
// parser.SetArgSep(',');
// parser.SetDecSep('.');
// parser.SetThousandsSep('');
#endif
// Add some variables
value_type vVarVal[] = { 1, 2 }; // Values of the parser variables
parser.DefineVar(_T("a"), &vVarVal[0]); // Assign Variable names and bind them to the C++ variables
parser.DefineVar(_T("b"), &vVarVal[1]);
parser.DefineVar(_T("ft"), &vVarVal[1]);
parser.DefineStrConst(_T("sVar1"), _T("Sample string 1") );
parser.DefineStrConst(_T("sVar2"), _T("Sample string 2") );
parser.AddValIdent(IsHexValue);
// Add some variables
value_type vVarVal[] = {1, 2}; // Values of the parser variables
parser.DefineVar(_T("a"),
&vVarVal[0]); // Assign Variable names and bind them to the C++ variables
parser.DefineVar(_T("b"), &vVarVal[1]);
parser.DefineVar(_T("ft"), &vVarVal[1]);
parser.DefineStrConst(_T("sVar1"), _T("Sample string 1"));
parser.DefineStrConst(_T("sVar2"), _T("Sample string 2"));
parser.AddValIdent(IsHexValue);
// Add user defined unary operators
parser.DefinePostfixOprt(_T("M"), Mega);
parser.DefinePostfixOprt(_T("m"), Milli);
parser.DefineInfixOprt(_T("!"), Not);
parser.DefineFun(_T("strfun0"), StrFun0);
parser.DefineFun(_T("strfun2"), StrFun2);
parser.DefineFun(_T("ping"), Ping);
parser.DefineFun(_T("rnd"), Rnd); // Add an unoptimizeable function
parser.DefineFun(_T("throw"), ThrowAnException);
// Add user defined unary operators
parser.DefinePostfixOprt(_T("M"), Mega);
parser.DefinePostfixOprt(_T("m"), Milli);
parser.DefineInfixOprt(_T("!"), Not);
parser.DefineFun(_T("strfun0"), StrFun0);
parser.DefineFun(_T("strfun2"), StrFun2);
parser.DefineFun(_T("ping"), Ping);
parser.DefineFun(_T("rnd"), Rnd);
parser.DefineFun(_T("throw"), ThrowAnException);
parser.DefineOprt(_T("add"), Add, 0);
parser.DefineOprt(_T("mul"), Mul, 1);
parser.DefineOprt(_T("add"), Add, 0);
parser.DefineOprt(_T("mul"), Mul, 1);
// These are service and debug functions
parser.DefineFun(_T("debug"), Debug);
parser.DefineFun(_T("selftest"), SelfTest);
parser.DefineFun(_T("help"), Help);
// These are service and debug functions
parser.DefineFun(_T("debug"), Debug);
parser.DefineFun(_T("selftest"), SelfTest);
parser.DefineFun(_T("help"), Help);
parser.DefinePostfixOprt(_T("{ft}"), Milli);
parser.DefinePostfixOprt(_T("ft"), Milli);
parser.DefinePostfixOprt(_T("{ft}"), Milli);
parser.DefinePostfixOprt(_T("ft"), Milli);
#ifdef _DEBUG
// parser.EnableDebugDump(1, 0);
#endif
// Define the variable factory
parser.SetVarFactory(AddVariable, &parser);
// Define the variable factory
parser.SetVarFactory(AddVariable, &parser);
for(;;)
{
try
{
string_type sLine;
std::getline(mu::console_in(), sLine);
for (;;) {
try {
string_type sLine;
std::getline(mu::console_in(), sLine);
switch (CheckKeywords(sLine.c_str(), parser))
{
case 0: break;
case 1: continue;
case -1: return;
}
switch (CheckKeywords(sLine.c_str(), parser)) {
case 0:
break;
case 1:
continue;
case -1:
return;
}
if (!sLine.length())
continue;
if (!sLine.length()) continue;
parser.SetExpr(sLine);
mu::console() << std::setprecision(12);
parser.SetExpr(sLine);
mu::console() << std::setprecision(12);
// There are multiple ways to retrieve the result...
// 1.) If you know there is only a single return value or in case you only need the last
// result of an expression consisting of comma separated subexpressions you can
// simply use:
mu::console() << _T("ans=") << parser.Eval() << _T("\n");
// There are multiple ways to retrieve the result...
// 1.) If you know there is only a single return value or in case you only need the last
// result of an expression consisting of comma separated subexpressions you can
// simply use:
mu::console() << _T("ans=") << *parser.Eval() << _T("\n");
// 2.) As an alternative you can also retrieve multiple return values using this API:
int nNum = parser.GetNumResults();
if (nNum>1)
{
mu::console() << _T("Multiple return values detected! Complete list:\n");
// 2.) As an alternative you can also retrieve multiple return values using this API:
int nNum = parser.GetNumResults();
if (nNum > 1) {
mu::console() << _T("Multiple return values detected! Complete list:\n");
// this is the hard way if you need to retrieve multiple subexpression
// results
value_type *v = parser.Eval(nNum);
mu::console() << std::setprecision(12);
for (int i=0; i<nNum; ++i)
{
mu::console() << v[i] << _T("\n");
// this is the hard way if you need to retrieve multiple subexpression
// results
std::vector<ValueOrError> vs;
parser.Eval(&vs);
mu::console() << std::setprecision(12);
for (const ValueOrError &v : vs) {
mu::console() << *v << _T("\n");
}
}
} catch (mu::Parser::exception_type &e) {
mu::console() << _T("\nError:\n");
mu::console() << _T("------\n");
mu::console() << _T("Message: ") << e.GetMsg() << _T("\n");
mu::console() << _T("Token: \"") << e.GetToken() << _T("\"\n");
mu::console() << _T("Position: ") << (int)e.GetPos() << _T("\n");
mu::console() << _T("Errc: ") << std::dec << e.GetCode() << _T("\n");
}
}
}
catch(mu::Parser::exception_type &e)
{
mu::console() << _T("\nError:\n");
mu::console() << _T("------\n");
mu::console() << _T("Message: ") << e.GetMsg() << _T("\n");
mu::console() << _T("Expression: \"") << e.GetExpr() << _T("\"\n");
mu::console() << _T("Token: \"") << e.GetToken() << _T("\"\n");
mu::console() << _T("Position: ") << (int)e.GetPos() << _T("\n");
mu::console() << _T("Errc: ") << std::dec << e.GetCode() << _T("\n");
}
} // while running
} // while running
}
//---------------------------------------------------------------------------
int main(int, char**)
{
Splash();
SelfTest();
Help();
int main(int, char **) {
Splash();
(void)SelfTest();
(void)Help();
// CheckLocale();
// CheckDiff();
// CheckLocale();
// CheckDiff();
mu::console() << _T("Enter an expression or a command:\n");
mu::console() << _T("Enter an expression or a command:\n");
try
{
Calc();
}
catch(Parser::exception_type &e)
{
// Only erros raised during the initialization will end up here
// formula related errors are treated in Calc()
console() << _T("Initialization error: ") << e.GetMsg() << endl;
console() << _T("aborting...") << endl;
string_type sBuf;
console_in() >> sBuf;
}
catch(std::exception & /*exc*/)
{
// there is no unicode compliant way to query exc.what()
// so i'll leave it for this example.
console() << _T("aborting...\n");
}
try {
Calc();
} catch (Parser::exception_type &e) {
// Only erros raised during the initialization will end up here
// formula related errors are treated in Calc()
console() << _T("Initialization error: ") << e.GetMsg() << endl;
console() << _T("aborting...") << endl;
string_type sBuf;
console_in() >> sBuf;
} catch (std::exception & /*exc*/) {
// there is no unicode compliant way to query exc.what()
// so i'll leave it for this example.
console() << _T("aborting...\n");
}
return 0;
return 0;
}

View file

@ -1,41 +1,41 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2013 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "muParser.h"
#include "muParserTemplateMagic.h"
//--- Standard includes ------------------------------------------------------------------------
#include <cmath>
#include <algorithm>
#include <cmath>
#include <limits>
#include <numeric>
/** \brief Pi (what else?). */
#define PARSER_CONST_PI 3.141592653589793238462643
#define PARSER_CONST_PI 3.141592653589793238462643
/** \brief The Eulerian number. */
#define PARSER_CONST_E 2.718281828459045235360287
#define PARSER_CONST_E 2.718281828459045235360287
using namespace std;
@ -43,355 +43,263 @@ using namespace std;
\brief Implementation of the standard floating point parser.
*/
/** \brief Namespace for mathematical applications. */
namespace mu
{
namespace mu {
//---------------------------------------------------------------------------
// Trigonometric function
ValueOrError Parser::Sin(value_type v) { return std::sin(v); }
ValueOrError Parser::Cos(value_type v) { return std::cos(v); }
ValueOrError Parser::Tan(value_type v) { return std::tan(v); }
ValueOrError Parser::ASin(value_type v) { return std::asin(v); }
ValueOrError Parser::ACos(value_type v) { return std::acos(v); }
ValueOrError Parser::ATan(value_type v) { return std::atan(v); }
ValueOrError Parser::ATan2(value_type v1, value_type v2) { return std::atan2(v1, v2); }
ValueOrError Parser::Sinh(value_type v) { return std::sinh(v); }
ValueOrError Parser::Cosh(value_type v) { return std::cosh(v); }
ValueOrError Parser::Tanh(value_type v) { return std::tanh(v); }
ValueOrError Parser::ASinh(value_type v) { return std::asinh(v); }
ValueOrError Parser::ACosh(value_type v) { return std::acosh(v); }
ValueOrError Parser::ATanh(value_type v) { return std::atanh(v); }
//---------------------------------------------------------------------------
// Trigonometric function
value_type Parser::Sin(value_type v) { return MathImpl<value_type>::Sin(v); }
value_type Parser::Cos(value_type v) { return MathImpl<value_type>::Cos(v); }
value_type Parser::Tan(value_type v) { return MathImpl<value_type>::Tan(v); }
value_type Parser::ASin(value_type v) { return MathImpl<value_type>::ASin(v); }
value_type Parser::ACos(value_type v) { return MathImpl<value_type>::ACos(v); }
value_type Parser::ATan(value_type v) { return MathImpl<value_type>::ATan(v); }
value_type Parser::ATan2(value_type v1, value_type v2) { return MathImpl<value_type>::ATan2(v1, v2); }
value_type Parser::Sinh(value_type v) { return MathImpl<value_type>::Sinh(v); }
value_type Parser::Cosh(value_type v) { return MathImpl<value_type>::Cosh(v); }
value_type Parser::Tanh(value_type v) { return MathImpl<value_type>::Tanh(v); }
value_type Parser::ASinh(value_type v) { return MathImpl<value_type>::ASinh(v); }
value_type Parser::ACosh(value_type v) { return MathImpl<value_type>::ACosh(v); }
value_type Parser::ATanh(value_type v) { return MathImpl<value_type>::ATanh(v); }
//---------------------------------------------------------------------------
// Logarithm functions
//---------------------------------------------------------------------------
// Logarithm functions
// Logarithm base 2
ValueOrError Parser::Log2(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v <= 0) return ParserError(ecDOMAIN_ERROR, _T("Log2"));
#endif
// Logarithm base 2
value_type Parser::Log2(value_type v)
{
#ifdef MUP_MATH_EXCEPTIONS
if (v<=0)
throw ParserError(ecDOMAIN_ERROR, _T("Log2"));
#endif
return std::log2(v);
}
return MathImpl<value_type>::Log2(v);
}
// Logarithm base 10
ValueOrError Parser::Log10(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v <= 0) return ParserError(ecDOMAIN_ERROR, _T("Log10"));
#endif
// Logarithm base 10
value_type Parser::Log10(value_type v)
{
#ifdef MUP_MATH_EXCEPTIONS
if (v<=0)
throw ParserError(ecDOMAIN_ERROR, _T("Log10"));
#endif
return MathImpl<value_type>::Log10(v);
}
return std::log10(v);
}
// Logarithm base e (natural logarithm)
value_type Parser::Ln(value_type v)
{
#ifdef MUP_MATH_EXCEPTIONS
if (v<=0)
throw ParserError(ecDOMAIN_ERROR, _T("Ln"));
#endif
ValueOrError Parser::Ln(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v <= 0) return ParserError(ecDOMAIN_ERROR, _T("Ln"));
#endif
return MathImpl<value_type>::Log(v);
}
return std::log(v);
}
//---------------------------------------------------------------------------
// misc
value_type Parser::Exp(value_type v) { return MathImpl<value_type>::Exp(v); }
value_type Parser::Abs(value_type v) { return MathImpl<value_type>::Abs(v); }
value_type Parser::Sqrt(value_type v)
{
#ifdef MUP_MATH_EXCEPTIONS
if (v<0)
throw ParserError(ecDOMAIN_ERROR, _T("sqrt"));
#endif
//---------------------------------------------------------------------------
// misc
ValueOrError Parser::Exp(value_type v) { return std::exp(v); }
ValueOrError Parser::Abs(value_type v) { return std::abs(v); }
ValueOrError Parser::Sqrt(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v < 0) return ParserError(ecDOMAIN_ERROR, _T("sqrt"));
#endif
return MathImpl<value_type>::Sqrt(v);
}
value_type Parser::Rint(value_type v) { return MathImpl<value_type>::Rint(v); }
value_type Parser::Sign(value_type v) { return MathImpl<value_type>::Sign(v); }
return std::sqrt(v);
}
ValueOrError Parser::Rint(value_type v) { return std::floor(v + 0.5); }
ValueOrError Parser::Sign(value_type v) {
// return 1, 0, -1 according to whether v is positive, zero, negative.
return (v > 0) - (v < 0);
}
//---------------------------------------------------------------------------
/** \brief Callback for the unary minus operator.
\param v The value to negate
\return -v
*/
value_type Parser::UnaryMinus(value_type v)
{
return -v;
}
//---------------------------------------------------------------------------
/** \brief Callback for the unary minus operator.
\param v The value to negate
\return -v
*/
ValueOrError Parser::UnaryMinus(value_type v) { return -v; }
//---------------------------------------------------------------------------
/** \brief Callback for the unary minus operator.
\param v The value to negate
\return -v
*/
value_type Parser::UnaryPlus(value_type v)
{
return v;
}
//---------------------------------------------------------------------------
/** \brief Callback for the unary minus operator.
\param v The value to negate
\return -v
*/
ValueOrError Parser::UnaryPlus(value_type v) { return v; }
//---------------------------------------------------------------------------
/** \brief Callback for adding multiple values.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
value_type Parser::Sum(const value_type *a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw exception_type(_T("too few arguments for function sum."));
//---------------------------------------------------------------------------
/** \brief Callback for adding multiple values.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
ValueOrError Parser::Sum(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function sum."));
value_type fRes=0;
for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];
value_type fRes = 0;
for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i];
return fRes;
}
}
//---------------------------------------------------------------------------
/** \brief Callback for averaging multiple values.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
value_type Parser::Avg(const value_type *a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw exception_type(_T("too few arguments for function sum."));
//---------------------------------------------------------------------------
/** \brief Callback for averaging multiple values.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
ValueOrError Parser::Avg(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function sum."));
value_type fRes=0;
for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];
return fRes/(value_type)a_iArgc;
}
value_type fRes = 0;
for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i];
return fRes / (value_type)a_iArgc;
}
//---------------------------------------------------------------------------
/** \brief Callback for determining the minimum value out of a vector.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
ValueOrError Parser::Min(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function min."));
//---------------------------------------------------------------------------
/** \brief Callback for determining the minimum value out of a vector.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
value_type Parser::Min(const value_type *a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw exception_type(_T("too few arguments for function min."));
value_type fRes=a_afArg[0];
for (int i=0; i<a_iArgc; ++i)
fRes = std::min(fRes, a_afArg[i]);
value_type fRes = a_afArg[0];
for (int i = 0; i < a_iArgc; ++i) fRes = std::min(fRes, a_afArg[i]);
return fRes;
}
}
//---------------------------------------------------------------------------
/** \brief Callback for determining the maximum value out of a vector.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
ValueOrError Parser::Max(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function max."));
//---------------------------------------------------------------------------
/** \brief Callback for determining the maximum value out of a vector.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
value_type Parser::Max(const value_type *a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw exception_type(_T("too few arguments for function min."));
value_type fRes=a_afArg[0];
for (int i=0; i<a_iArgc; ++i) fRes = std::max(fRes, a_afArg[i]);
value_type fRes = a_afArg[0];
for (int i = 0; i < a_iArgc; ++i) fRes = std::max(fRes, a_afArg[i]);
return fRes;
}
}
//---------------------------------------------------------------------------
/** \brief Default value recognition callback.
\param [in] a_szExpr Pointer to the expression
\param [in, out] a_iPos Pointer to an index storing the current position within the expression
\param [out] a_fVal Pointer where the value should be stored in case one is found.
\return 1 if a value was found 0 otherwise.
*/
int Parser::IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal)
{
//---------------------------------------------------------------------------
/** \brief Default value recognition callback.
\param [in] a_szExpr Pointer to the expression
\param [in, out] a_iPos Pointer to an index storing the current position within the expression
\param [out] a_fVal Pointer where the value should be stored in case one is found.
\return 1 if a value was found 0 otherwise.
*/
int Parser::IsVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) {
value_type fVal(0);
stringstream_type stream(a_szExpr);
stream.seekg(0); // todo: check if this really is necessary
stream.seekg(0); // todo: check if this really is necessary
stream.imbue(Parser::s_locale);
stream >> fVal;
stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading
stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading
if (iEnd==(stringstream_type::pos_type)-1)
return 0;
if (iEnd == (stringstream_type::pos_type)-1) return 0;
*a_iPos += (int)iEnd;
*a_fVal = fVal;
return 1;
}
}
//---------------------------------------------------------------------------
/** \brief Constructor.
//---------------------------------------------------------------------------
/** \brief Constructor.
Call ParserBase class constructor and trigger Function, Operator and Constant initialization.
*/
Parser::Parser()
:ParserBase()
{
Call ParserBase class constructor and trigger Function, Operator and Constant initialization.
*/
Parser::Parser() : ParserBase() {
AddValIdent(IsVal);
InitCharSets();
InitFun();
InitConst();
InitOprt();
}
}
//---------------------------------------------------------------------------
/** \brief Define the character sets.
\sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars
This function is used for initializing the default character sets that define
the characters to be useable in function and variable names and operators.
*/
void Parser::InitCharSets()
{
DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") );
DefineOprtChars( _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}") );
DefineInfixOprtChars( _T("/+-*^?<>=#!$%&|~'_") );
}
//---------------------------------------------------------------------------
/** \brief Define the character sets.
\sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars
//---------------------------------------------------------------------------
/** \brief Initialize the default functions. */
void Parser::InitFun()
{
if (mu::TypeInfo<mu::value_type>::IsInteger())
{
// When setting MUP_BASETYPE to an integer type
// Place functions for dealing with integer values here
// ...
// ...
// ...
This function is used for initializing the default character sets that define
the characters to be useable in function and variable names and operators.
*/
void Parser::InitCharSets() {
DefineNameChars(_T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"));
DefineOprtChars(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}"));
DefineInfixOprtChars(_T("/+-*^?<>=#!$%&|~'_"));
}
/// assert that the given optional error \p oerr is not an error.
/// This is used only during initialization, when it ought to be impossible
/// to generate an error.
static void assertNoError(OptionalError oerr) {
assert(!oerr.has_error() && "Unexpected error during initialization");
(void)oerr;
}
//---------------------------------------------------------------------------
/** \brief Initialize the default functions. */
void Parser::InitFun() {
if (std::numeric_limits<mu::value_type>::is_integer) {
// When setting MUP_BASETYPE to an integer type
// Place functions for dealing with integer values here
// ...
// ...
// ...
} else {
// trigonometric functions
assertNoError(DefineFun(_T("sin"), Sin));
assertNoError(DefineFun(_T("cos"), Cos));
assertNoError(DefineFun(_T("tan"), Tan));
// arcus functions
assertNoError(DefineFun(_T("asin"), ASin));
assertNoError(DefineFun(_T("acos"), ACos));
assertNoError(DefineFun(_T("atan"), ATan));
assertNoError(DefineFun(_T("atan2"), ATan2));
// hyperbolic functions
assertNoError(DefineFun(_T("sinh"), Sinh));
assertNoError(DefineFun(_T("cosh"), Cosh));
assertNoError(DefineFun(_T("tanh"), Tanh));
// arcus hyperbolic functions
assertNoError(DefineFun(_T("asinh"), ASinh));
assertNoError(DefineFun(_T("acosh"), ACosh));
assertNoError(DefineFun(_T("atanh"), ATanh));
// Logarithm functions
assertNoError(DefineFun(_T("log2"), Log2));
assertNoError(DefineFun(_T("log10"), Log10));
assertNoError(DefineFun(_T("log"), Ln));
assertNoError(DefineFun(_T("ln"), Ln));
// misc
assertNoError(DefineFun(_T("exp"), Exp));
assertNoError(DefineFun(_T("sqrt"), Sqrt));
assertNoError(DefineFun(_T("sign"), Sign));
assertNoError(DefineFun(_T("rint"), Rint));
assertNoError(DefineFun(_T("abs"), Abs));
// Functions with variable number of arguments
assertNoError(DefineFun(_T("sum"), Sum));
assertNoError(DefineFun(_T("avg"), Avg));
assertNoError(DefineFun(_T("min"), Min));
assertNoError(DefineFun(_T("max"), Max));
}
else
{
// trigonometric functions
DefineFun(_T("sin"), Sin);
DefineFun(_T("cos"), Cos);
DefineFun(_T("tan"), Tan);
// arcus functions
DefineFun(_T("asin"), ASin);
DefineFun(_T("acos"), ACos);
DefineFun(_T("atan"), ATan);
DefineFun(_T("atan2"), ATan2);
// hyperbolic functions
DefineFun(_T("sinh"), Sinh);
DefineFun(_T("cosh"), Cosh);
DefineFun(_T("tanh"), Tanh);
// arcus hyperbolic functions
DefineFun(_T("asinh"), ASinh);
DefineFun(_T("acosh"), ACosh);
DefineFun(_T("atanh"), ATanh);
// Logarithm functions
DefineFun(_T("log2"), Log2);
DefineFun(_T("log10"), Log10);
DefineFun(_T("log"), Ln);
DefineFun(_T("ln"), Ln);
// misc
DefineFun(_T("exp"), Exp);
DefineFun(_T("sqrt"), Sqrt);
DefineFun(_T("sign"), Sign);
DefineFun(_T("rint"), Rint);
DefineFun(_T("abs"), Abs);
// Functions with variable number of arguments
DefineFun(_T("sum"), Sum);
DefineFun(_T("avg"), Avg);
DefineFun(_T("min"), Min);
DefineFun(_T("max"), Max);
}
}
}
//---------------------------------------------------------------------------
/** \brief Initialize constants.
By default the parser recognizes two constants. Pi ("pi") and the Eulerian
number ("_e").
*/
void Parser::InitConst()
{
DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI);
DefineConst(_T("_e"), (value_type)PARSER_CONST_E);
}
//---------------------------------------------------------------------------
/** \brief Initialize constants.
//---------------------------------------------------------------------------
/** \brief Initialize operators.
By default only the unary minus operator is added.
*/
void Parser::InitOprt()
{
DefineInfixOprt(_T("-"), UnaryMinus);
DefineInfixOprt(_T("+"), UnaryPlus);
}
By default the parser recognizes two constants. Pi ("pi") and the Eulerian
number ("_e").
*/
void Parser::InitConst() {
assertNoError(DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI));
assertNoError(DefineConst(_T("_e"), (value_type)PARSER_CONST_E));
}
//---------------------------------------------------------------------------
void Parser::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/)
{
// this is just sample code to illustrate modifying variable names on the fly.
// I'm not sure anyone really needs such a feature...
/*
//---------------------------------------------------------------------------
/** \brief Initialize operators.
By default only the unary minus operator is added.
*/
void Parser::InitOprt() {
assertNoError(DefineInfixOprt(_T("-"), UnaryMinus));
assertNoError(DefineInfixOprt(_T("+"), UnaryPlus));
}
string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd);
string sRepl = std::string("_") + sVar + "_";
int nOrigVarEnd = nEnd;
cout << "variable detected!\n";
cout << " Expr: " << *pExpr << "\n";
cout << " Start: " << nStart << "\n";
cout << " End: " << nEnd << "\n";
cout << " Var: \"" << sVar << "\"\n";
cout << " Repl: \"" << sRepl << "\"\n";
nEnd = nStart + sRepl.length();
cout << " End: " << nEnd << "\n";
pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl);
cout << " New expr: " << *pExpr << "\n";
*/
}
//---------------------------------------------------------------------------
/** \brief Numerically differentiate with regard to a variable.
\param [in] a_Var Pointer to the differentiation variable.
\param [in] a_fPos Position at which the differentiation should take place.
\param [in] a_fEpsilon Epsilon used for the numerical differentiation.
Numerical differentiation uses a 5 point operator yielding a 4th order
formula. The default value for epsilon is 0.00074 which is
numeric_limits<double>::epsilon() ^ (1/5) as suggested in the muparser
forum:
http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843
*/
value_type Parser::Diff(value_type *a_Var,
value_type a_fPos,
value_type a_fEpsilon) const
{
value_type fRes(0),
fBuf(*a_Var),
f[4] = {0,0,0,0},
fEpsilon(a_fEpsilon);
// Backwards compatible calculation of epsilon inc case the user doesn't provide
// his own epsilon
if (fEpsilon==0)
fEpsilon = (a_fPos==0) ? (value_type)1e-10 : (value_type)1e-7 * a_fPos;
*a_Var = a_fPos+2 * fEpsilon; f[0] = Eval();
*a_Var = a_fPos+1 * fEpsilon; f[1] = Eval();
*a_Var = a_fPos-1 * fEpsilon; f[2] = Eval();
*a_Var = a_fPos-2 * fEpsilon; f[3] = Eval();
*a_Var = fBuf; // restore variable
fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon);
return fRes;
}
} // namespace mu
} // namespace mu

File diff suppressed because it is too large Load diff

View file

@ -1,371 +1,143 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2011 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "muParserBytecode.h"
#include <algorithm>
#include <cassert>
#include <string>
#include <stack>
#include <vector>
#include <iostream>
#include <stack>
#include <string>
#include <vector>
#include "muParserDef.h"
#include "muParserError.h"
#include "muParserToken.h"
#include "muParserStack.h"
#include "muParserTemplateMagic.h"
namespace mu
{
//---------------------------------------------------------------------------
/** \brief Bytecode default constructor. */
ParserByteCode::ParserByteCode()
:m_iStackPos(0)
,m_iMaxStackSize(0)
,m_vRPN()
,m_bEnableOptimizer(true)
{
namespace mu {
//---------------------------------------------------------------------------
/** \brief Bytecode default constructor. */
ParserByteCode::ParserByteCode() : m_iStackPos(0), m_iMaxStackSize(0), m_vRPN() {
m_vRPN.reserve(50);
}
}
//---------------------------------------------------------------------------
/** \brief Copy constructor.
Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)
*/
ParserByteCode::ParserByteCode(const ParserByteCode &a_ByteCode)
{
Assign(a_ByteCode);
}
//---------------------------------------------------------------------------
/** \brief Assignment operator.
Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)
*/
ParserByteCode& ParserByteCode::operator=(const ParserByteCode &a_ByteCode)
{
Assign(a_ByteCode);
return *this;
}
//---------------------------------------------------------------------------
void ParserByteCode::EnableOptimizer(bool bStat)
{
m_bEnableOptimizer = bStat;
}
//---------------------------------------------------------------------------
/** \brief Copy state of another object to this.
\throw nowthrow
*/
void ParserByteCode::Assign(const ParserByteCode &a_ByteCode)
{
if (this==&a_ByteCode)
return;
m_iStackPos = a_ByteCode.m_iStackPos;
m_vRPN = a_ByteCode.m_vRPN;
m_iMaxStackSize = a_ByteCode.m_iMaxStackSize;
m_bEnableOptimizer = a_ByteCode.m_bEnableOptimizer;
}
//---------------------------------------------------------------------------
/** \brief Add a Variable pointer to bytecode.
\param a_pVar Pointer to be added.
\throw nothrow
*/
void ParserByteCode::AddVar(value_type *a_pVar)
{
//---------------------------------------------------------------------------
/** \brief Add a Variable pointer to bytecode.
\param a_pVar Pointer to be added.
*/
void ParserByteCode::AddVar(value_type *a_pVar) {
++m_iStackPos;
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
// optimization does not apply
SToken tok;
tok.Cmd = cmVAR;
tok.Val.ptr = a_pVar;
tok.Val.data = 1;
tok.Val.data2 = 0;
tok.Cmd = cmVAR;
tok.Val.ptr = a_pVar;
tok.Val.data = 0;
m_vRPN.push_back(tok);
}
}
//---------------------------------------------------------------------------
/** \brief Add a Variable pointer to bytecode.
//---------------------------------------------------------------------------
/** \brief Add a Variable pointer to bytecode.
Value entries in byte code consist of:
<ul>
<li>value array position of the value</li>
<li>the operator code according to ParserToken::cmVAL</li>
<li>the value stored in #mc_iSizeVal number of bytecode entries.</li>
</ul>
Value entries in byte code consist of:
<ul>
<li>value array position of the value</li>
<li>the operator code according to ParserToken::cmVAL</li>
<li>the value stored in #mc_iSizeVal number of bytecode entries.</li>
</ul>
\param a_pVal Value to be added.
\throw nothrow
*/
void ParserByteCode::AddVal(value_type a_fVal)
{
\param a_pVal Value to be added.
*/
void ParserByteCode::AddVal(value_type a_fVal) {
++m_iStackPos;
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
// If optimization does not apply
SToken tok;
tok.Cmd = cmVAL;
tok.Val.ptr = NULL;
tok.Val.data = 0;
tok.Val.data2 = a_fVal;
tok.Val.ptr = NULL;
tok.Val.data = a_fVal;
m_vRPN.push_back(tok);
}
}
//---------------------------------------------------------------------------
void ParserByteCode::ConstantFolding(ECmdCode a_Oprt)
{
std::size_t sz = m_vRPN.size();
value_type &x = m_vRPN[sz-2].Val.data2,
&y = m_vRPN[sz-1].Val.data2;
switch (a_Oprt)
{
case cmLAND: x = (int)x && (int)y; m_vRPN.pop_back(); break;
case cmLOR: x = (int)x || (int)y; m_vRPN.pop_back(); break;
case cmLT: x = x < y; m_vRPN.pop_back(); break;
case cmGT: x = x > y; m_vRPN.pop_back(); break;
case cmLE: x = x <= y; m_vRPN.pop_back(); break;
case cmGE: x = x >= y; m_vRPN.pop_back(); break;
case cmNEQ: x = x != y; m_vRPN.pop_back(); break;
case cmEQ: x = x == y; m_vRPN.pop_back(); break;
case cmADD: x = x + y; m_vRPN.pop_back(); break;
case cmSUB: x = x - y; m_vRPN.pop_back(); break;
case cmMUL: x = x * y; m_vRPN.pop_back(); break;
case cmDIV:
//---------------------------------------------------------------------------
/** \brief Add an operator identifier to bytecode.
#if defined(MUP_MATH_EXCEPTIONS)
if (y==0)
throw ParserError(ecDIV_BY_ZERO, _T("0"));
#endif
Operator entries in byte code consist of:
<ul>
<li>value array position of the result</li>
<li>the operator code according to ParserToken::ECmdCode</li>
</ul>
x = x / y;
m_vRPN.pop_back();
break;
case cmPOW: x = MathImpl<value_type>::Pow(x, y);
m_vRPN.pop_back();
break;
default:
break;
} // switch opcode
}
//---------------------------------------------------------------------------
/** \brief Add an operator identifier to bytecode.
Operator entries in byte code consist of:
<ul>
<li>value array position of the result</li>
<li>the operator code according to ParserToken::ECmdCode</li>
</ul>
\sa ParserToken::ECmdCode
*/
void ParserByteCode::AddOp(ECmdCode a_Oprt)
{
bool bOptimized = false;
if (m_bEnableOptimizer)
{
std::size_t sz = m_vRPN.size();
// Check for foldable constants like:
// cmVAL cmVAL cmADD
// where cmADD can stand fopr any binary operator applied to
// two constant values.
if (sz>=2 && m_vRPN[sz-2].Cmd == cmVAL && m_vRPN[sz-1].Cmd == cmVAL)
{
ConstantFolding(a_Oprt);
bOptimized = true;
}
else
{
switch(a_Oprt)
{
case cmPOW:
// Optimization for polynomials of low order
if (m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-1].Cmd == cmVAL)
{
if (m_vRPN[sz-1].Val.data2==2)
m_vRPN[sz-2].Cmd = cmVARPOW2;
else if (m_vRPN[sz-1].Val.data2==3)
m_vRPN[sz-2].Cmd = cmVARPOW3;
else if (m_vRPN[sz-1].Val.data2==4)
m_vRPN[sz-2].Cmd = cmVARPOW4;
else
break;
m_vRPN.pop_back();
bOptimized = true;
}
break;
case cmSUB:
case cmADD:
// Simple optimization based on pattern recognition for a shitload of different
// bytecode combinations of addition/subtraction
if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) ||
(m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ||
(m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) ||
(m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ||
(m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||
(m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||
(m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||
(m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) )
{
assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) ||
(m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) ||
(m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) );
m_vRPN[sz-2].Cmd = cmVARMUL;
m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); // variable
m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset
m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplicand
m_vRPN.pop_back();
bOptimized = true;
}
break;
case cmMUL:
if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) ||
(m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) )
{
m_vRPN[sz-2].Cmd = cmVARMUL;
m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr));
m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2;
m_vRPN[sz-2].Val.data2 = 0;
m_vRPN.pop_back();
bOptimized = true;
}
else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) ||
(m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) )
{
// Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2
m_vRPN[sz-2].Cmd = cmVARMUL;
m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr));
if (m_vRPN[sz-1].Cmd == cmVAL)
{
m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2;
m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2;
}
else
{
m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2;
m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2;
}
m_vRPN.pop_back();
bOptimized = true;
}
else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR &&
m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr)
{
// Optimization: a*a -> a^2
m_vRPN[sz-2].Cmd = cmVARPOW2;
m_vRPN.pop_back();
bOptimized = true;
}
break;
case cmDIV:
if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-1].Val.data2!=0)
{
// Optimization: 4*a/2 -> 2*a
m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2;
m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2;
m_vRPN.pop_back();
bOptimized = true;
}
break;
} // switch a_Oprt
}
}
// If optimization can't be applied just write the value
if (!bOptimized)
{
--m_iStackPos;
SToken tok;
tok.Cmd = a_Oprt;
m_vRPN.push_back(tok);
}
}
//---------------------------------------------------------------------------
void ParserByteCode::AddIfElse(ECmdCode a_Oprt)
{
\sa ParserToken::ECmdCode
*/
void ParserByteCode::AddOp(ECmdCode a_Oprt) {
--m_iStackPos;
SToken tok;
tok.Cmd = a_Oprt;
m_vRPN.push_back(tok);
}
}
//---------------------------------------------------------------------------
/** \brief Add an assignment operator
Operator entries in byte code consist of:
<ul>
<li>cmASSIGN code</li>
<li>the pointer of the destination variable</li>
</ul>
//---------------------------------------------------------------------------
void ParserByteCode::AddIfElse(ECmdCode a_Oprt) {
SToken tok;
tok.Cmd = a_Oprt;
m_vRPN.push_back(tok);
}
\sa ParserToken::ECmdCode
*/
void ParserByteCode::AddAssignOp(value_type *a_pVar)
{
//---------------------------------------------------------------------------
/** \brief Add an assignment operator
Operator entries in byte code consist of:
<ul>
<li>cmASSIGN code</li>
<li>the pointer of the destination variable</li>
</ul>
\sa ParserToken::ECmdCode
*/
void ParserByteCode::AddAssignOp(value_type *a_pVar) {
--m_iStackPos;
SToken tok;
tok.Cmd = cmASSIGN;
tok.Oprt.ptr = a_pVar;
m_vRPN.push_back(tok);
}
}
//---------------------------------------------------------------------------
/** \brief Add function to bytecode.
//---------------------------------------------------------------------------
/** \brief Add function to bytecode.
\param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
\param a_pFun Pointer to function callback.
*/
void ParserByteCode::AddFun(generic_fun_type a_pFun, int a_iArgc)
{
if (a_iArgc>=0)
{
m_iStackPos = m_iStackPos - a_iArgc + 1;
}
else
{
// function with unlimited number of arguments
m_iStackPos = m_iStackPos + a_iArgc + 1;
\param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
\param a_pFun Pointer to function callback.
*/
void ParserByteCode::AddFun(generic_fun_type a_pFun, int a_iArgc) {
if (a_iArgc >= 0) {
m_iStackPos = m_iStackPos - a_iArgc + 1;
} else {
// function with unlimited number of arguments
m_iStackPos = m_iStackPos + a_iArgc + 1;
}
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
@ -374,36 +146,16 @@ namespace mu
tok.Fun.argc = a_iArgc;
tok.Fun.ptr = a_pFun;
m_vRPN.push_back(tok);
}
}
//---------------------------------------------------------------------------
/** \brief Add a bulk function to bytecode.
//---------------------------------------------------------------------------
/** \brief Add String function entry to the parser bytecode.
\param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
\param a_pFun Pointer to function callback.
*/
void ParserByteCode::AddBulkFun(generic_fun_type a_pFun, int a_iArgc)
{
m_iStackPos = m_iStackPos - a_iArgc + 1;
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
SToken tok;
tok.Cmd = cmFUNC_BULK;
tok.Fun.argc = a_iArgc;
tok.Fun.ptr = a_pFun;
m_vRPN.push_back(tok);
}
//---------------------------------------------------------------------------
/** \brief Add Strung function entry to the parser bytecode.
\throw nothrow
A string function entry consists of the stack position of the return value,
followed by a cmSTRFUNC code, the function pointer and an index into the
string buffer maintained by the parser.
*/
void ParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx)
{
A string function entry consists of the stack position of the return value,
followed by a cmSTRFUNC code, the function pointer and an index into the
string buffer maintained by the parser.
*/
void ParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx) {
m_iStackPos = m_iStackPos - a_iArgc + 1;
SToken tok;
@ -414,175 +166,173 @@ namespace mu
m_vRPN.push_back(tok);
m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);
}
}
//---------------------------------------------------------------------------
/** \brief Add end marker to bytecode.
\throw nothrow
*/
void ParserByteCode::Finalize()
{
//---------------------------------------------------------------------------
/** \brief Add end marker to bytecode.
*/
void ParserByteCode::Finalize() {
SToken tok;
tok.Cmd = cmEND;
m_vRPN.push_back(tok);
rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit
m_vRPN.shrink_to_fit();
// Determine the if-then-else jump offsets
ParserStack<int> stIf, stElse;
int idx;
for (int i=0; i<(int)m_vRPN.size(); ++i)
{
switch(m_vRPN[i].Cmd)
{
case cmIF:
stIf.push(i);
break;
for (int i = 0; i < (int)m_vRPN.size(); ++i) {
switch (m_vRPN[i].Cmd) {
case cmIF:
stIf.push_back(i);
break;
case cmELSE:
stElse.push(i);
idx = stIf.pop();
m_vRPN[idx].Oprt.offset = i - idx;
break;
case cmENDIF:
idx = stElse.pop();
m_vRPN[idx].Oprt.offset = i - idx;
break;
case cmELSE: {
int idx = stIf.back();
stIf.pop_back();
m_vRPN[idx].Oprt.offset = i - idx;
stElse.push_back(i);
break;
}
default:
break;
}
case cmENDIF: {
int idx = stElse.back();
stElse.pop_back();
m_vRPN[idx].Oprt.offset = i - idx;
break;
}
default:
break;
}
}
}
}
//---------------------------------------------------------------------------
const SToken* ParserByteCode::GetBase() const
{
if (m_vRPN.size()==0)
throw ParserError(ecINTERNAL_ERROR);
else
return &m_vRPN[0];
}
//---------------------------------------------------------------------------
const SToken *ParserByteCode::GetBase() const {
if (m_vRPN.size() == 0) assert(0 && "muParser internal error");
return &m_vRPN[0];
}
//---------------------------------------------------------------------------
std::size_t ParserByteCode::GetMaxStackSize() const
{
return m_iMaxStackSize+1;
}
//---------------------------------------------------------------------------
std::size_t ParserByteCode::GetMaxStackSize() const { return m_iMaxStackSize + 1; }
//---------------------------------------------------------------------------
/** \brief Returns the number of entries in the bytecode. */
std::size_t ParserByteCode::GetSize() const
{
return m_vRPN.size();
}
//---------------------------------------------------------------------------
/** \brief Returns the number of entries in the bytecode. */
std::size_t ParserByteCode::GetSize() const { return m_vRPN.size(); }
//---------------------------------------------------------------------------
/** \brief Delete the bytecode.
\throw nothrow
//---------------------------------------------------------------------------
/** \brief Delete the bytecode.
The name of this function is a violation of my own coding guidelines
but this way it's more in line with the STL functions thus more
intuitive.
*/
void ParserByteCode::clear()
{
The name of this function is a violation of my own coding guidelines
but this way it's more in line with the STL functions thus more
intuitive.
*/
void ParserByteCode::clear() {
m_vRPN.clear();
m_iStackPos = 0;
m_iMaxStackSize = 0;
}
}
//---------------------------------------------------------------------------
/** \brief Dump bytecode (for debugging only!). */
void ParserByteCode::AsciiDump()
{
if (!m_vRPN.size())
{
mu::console() << _T("No bytecode available\n");
return;
//---------------------------------------------------------------------------
/** \brief Dump bytecode (for debugging only!). */
void ParserByteCode::AsciiDump() {
if (!m_vRPN.size()) {
mu::console() << _T("No bytecode available\n");
return;
}
mu::console() << _T("Number of RPN tokens:") << (int)m_vRPN.size() << _T("\n");
for (std::size_t i=0; i<m_vRPN.size() && m_vRPN[i].Cmd!=cmEND; ++i)
{
mu::console() << std::dec << i << _T(" : \t");
switch (m_vRPN[i].Cmd)
{
case cmVAL: mu::console() << _T("VAL \t");
mu::console() << _T("[") << m_vRPN[i].Val.data2 << _T("]\n");
break;
for (std::size_t i = 0; i < m_vRPN.size() && m_vRPN[i].Cmd != cmEND; ++i) {
mu::console() << std::dec << i << _T(" : \t");
switch (m_vRPN[i].Cmd) {
case cmVAL:
mu::console() << _T("VAL \t");
mu::console() << _T("[") << m_vRPN[i].Val.data << _T("]\n");
break;
case cmVAR: mu::console() << _T("VAR \t");
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
break;
case cmVAR:
mu::console() << _T("VAR \t");
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
break;
case cmVARPOW2: mu::console() << _T("VARPOW2 \t");
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
break;
case cmFUNC:
mu::console() << _T("CALL\t");
mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Fun.ptr << _T("]");
mu::console() << _T("\n");
break;
case cmVARPOW3: mu::console() << _T("VARPOW3 \t");
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
break;
case cmFUNC_STR:
mu::console() << _T("CALL STRFUNC\t");
mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
mu::console() << _T("[IDX:") << std::dec << m_vRPN[i].Fun.idx << _T("]");
mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Fun.ptr << _T("]\n");
break;
case cmVARPOW4: mu::console() << _T("VARPOW4 \t");
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n");
break;
case cmLT:
mu::console() << _T("LT\n");
break;
case cmGT:
mu::console() << _T("GT\n");
break;
case cmLE:
mu::console() << _T("LE\n");
break;
case cmGE:
mu::console() << _T("GE\n");
break;
case cmEQ:
mu::console() << _T("EQ\n");
break;
case cmNEQ:
mu::console() << _T("NEQ\n");
break;
case cmADD:
mu::console() << _T("ADD\n");
break;
case cmLAND:
mu::console() << _T("&&\n");
break;
case cmLOR:
mu::console() << _T("||\n");
break;
case cmSUB:
mu::console() << _T("SUB\n");
break;
case cmMUL:
mu::console() << _T("MUL\n");
break;
case cmDIV:
mu::console() << _T("DIV\n");
break;
case cmPOW:
mu::console() << _T("POW\n");
break;
case cmVARMUL: mu::console() << _T("VARMUL \t");
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]");
mu::console() << _T(" * [") << m_vRPN[i].Val.data << _T("]");
mu::console() << _T(" + [") << m_vRPN[i].Val.data2 << _T("]\n");
break;
case cmIF:
mu::console() << _T("IF\t");
mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
break;
case cmFUNC: mu::console() << _T("CALL\t");
mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Fun.ptr << _T("]");
mu::console() << _T("\n");
break;
case cmELSE:
mu::console() << _T("ELSE\t");
mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
break;
case cmFUNC_STR:
mu::console() << _T("CALL STRFUNC\t");
mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");
mu::console() << _T("[IDX:") << std::dec << m_vRPN[i].Fun.idx << _T("]");
mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Fun.ptr << _T("]\n");
break;
case cmENDIF:
mu::console() << _T("ENDIF\n");
break;
case cmLT: mu::console() << _T("LT\n"); break;
case cmGT: mu::console() << _T("GT\n"); break;
case cmLE: mu::console() << _T("LE\n"); break;
case cmGE: mu::console() << _T("GE\n"); break;
case cmEQ: mu::console() << _T("EQ\n"); break;
case cmNEQ: mu::console() << _T("NEQ\n"); break;
case cmADD: mu::console() << _T("ADD\n"); break;
case cmLAND: mu::console() << _T("&&\n"); break;
case cmLOR: mu::console() << _T("||\n"); break;
case cmSUB: mu::console() << _T("SUB\n"); break;
case cmMUL: mu::console() << _T("MUL\n"); break;
case cmDIV: mu::console() << _T("DIV\n"); break;
case cmPOW: mu::console() << _T("POW\n"); break;
case cmASSIGN:
mu::console() << _T("ASSIGN\t");
mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Oprt.ptr << _T("]\n");
break;
case cmIF: mu::console() << _T("IF\t");
mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
break;
case cmELSE: mu::console() << _T("ELSE\t");
mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");
break;
case cmENDIF: mu::console() << _T("ENDIF\n"); break;
case cmASSIGN:
mu::console() << _T("ASSIGN\t");
mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Oprt.ptr << _T("]\n");
break;
default: mu::console() << _T("(unknown code: ") << m_vRPN[i].Cmd << _T(")\n");
break;
} // switch cmdCode
} // while bytecode
default:
mu::console() << _T("(unknown code: ") << m_vRPN[i].Cmd << _T(")\n");
break;
} // switch cmdCode
} // while bytecode
mu::console() << _T("END") << std::endl;
}
} // namespace mu
}
} // namespace mu

View file

@ -1,26 +1,26 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2004-2011 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "muParserCallback.h"
@ -29,435 +29,143 @@
\brief Implementation of the parser callback class.
*/
namespace mu {
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type0 a_pFun)
: m_pFun((void*)a_pFun),
m_iArgc(0),
m_iPri(-1),
m_eOprtAsct(oaNONE),
m_iCode(cmFUNC),
m_iType(tpDBL) {}
namespace mu
{
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(0)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type1 a_pFun, int a_iPrec, ECmdCode a_iCode)
: m_pFun((void*)a_pFun),
m_iArgc(1),
m_iPri(a_iPrec),
m_eOprtAsct(oaNONE),
m_iCode(a_iCode),
m_iType(tpDBL) {}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode)
:m_pFun((void*)a_pFun)
,m_iArgc(1)
,m_iPri(a_iPrec)
,m_eOprtAsct(oaNONE)
,m_iCode(a_iCode)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
/** \brief Constructor for constructing function callbacks taking two arguments.
*/
ParserCallback::ParserCallback(fun_type2 a_pFun)
: m_pFun((void*)a_pFun),
m_iArgc(2),
m_iPri(-1),
m_eOprtAsct(oaNONE),
m_iCode(cmFUNC),
m_iType(tpDBL) {}
//---------------------------------------------------------------------------
/** \brief Constructor for constructing binary operator callbacks.
\param a_pFun Pointer to a static function taking two arguments
\param a_bAllowOpti A flag indicating this function can be optimized
\param a_iPrec The operator precedence
\param a_eOprtAsct The operators associativity
*/
ParserCallback::ParserCallback(fun_type2 a_pFun, int a_iPrec, EOprtAssociativity a_eOprtAsct)
: m_pFun((void*)a_pFun),
m_iArgc(2),
m_iPri(a_iPrec),
m_eOprtAsct(a_eOprtAsct),
m_iCode(cmOPRT_BIN),
m_iType(tpDBL) {}
//---------------------------------------------------------------------------
/** \brief Constructor for constructing function callbacks taking two arguments.
\throw nothrow
*/
ParserCallback::ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(2)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type3 a_pFun)
: m_pFun((void*)a_pFun),
m_iArgc(3),
m_iPri(-1),
m_eOprtAsct(oaNONE),
m_iCode(cmFUNC),
m_iType(tpDBL) {}
//---------------------------------------------------------------------------
/** \brief Constructor for constructing binary operator callbacks.
\param a_pFun Pointer to a static function taking two arguments
\param a_bAllowOpti A flag indicating this function can be optimized
\param a_iPrec The operator precedence
\param a_eOprtAsct The operators associativity
\throw nothrow
*/
ParserCallback::ParserCallback(fun_type2 a_pFun,
bool a_bAllowOpti,
int a_iPrec,
EOprtAssociativity a_eOprtAsct)
:m_pFun((void*)a_pFun)
,m_iArgc(2)
,m_iPri(a_iPrec)
,m_eOprtAsct(a_eOprtAsct)
,m_iCode(cmOPRT_BIN)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(multfun_type a_pFun)
: m_pFun((void*)a_pFun),
m_iArgc(-1),
m_iPri(-1),
m_eOprtAsct(oaNONE),
m_iCode(cmFUNC),
m_iType(tpDBL) {}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(3)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(strfun_type1 a_pFun)
: m_pFun((void*)a_pFun),
m_iArgc(0),
m_iPri(-1),
m_eOprtAsct(oaNONE),
m_iCode(cmFUNC_STR),
m_iType(tpSTR) {}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(strfun_type2 a_pFun)
: m_pFun((void*)a_pFun),
m_iArgc(1),
m_iPri(-1),
m_eOprtAsct(oaNONE),
m_iCode(cmFUNC_STR),
m_iType(tpSTR) {}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(4)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(strfun_type3 a_pFun)
: m_pFun((void*)a_pFun),
m_iArgc(2),
m_iPri(-1),
m_eOprtAsct(oaNONE),
m_iCode(cmFUNC_STR),
m_iType(tpSTR) {}
//---------------------------------------------------------------------------
/** \brief Default constructor.
*/
ParserCallback::ParserCallback()
: m_pFun(0),
m_iArgc(0),
m_iPri(-1),
m_eOprtAsct(oaNONE),
m_iCode(cmUNKNOWN),
m_iType(tpVOID) {}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(5)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
/** \brief Copy constructor.
*/
ParserCallback::ParserCallback(const ParserCallback& ref) = default;
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(6)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
/** \brief Get the callback address for the parser function.
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(7)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
The type of the address is void. It needs to be recasted according to the
argument number to the right type.
\return #pFun
*/
void* ParserCallback::GetAddr() const { return m_pFun; }
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(8)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
/** \brief Return the callback code. */
ECmdCode ParserCallback::GetCode() const { return m_iCode; }
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(9)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ETypeCode ParserCallback::GetType() const { return m_iType; }
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(10)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
/** \brief Return the operator precedence.n
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(0)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
Only valid if the callback token is an operator token (binary or infix).
*/
int ParserCallback::GetPri() const { return m_iPri; }
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(1)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
/** \brief Return the operators associativity.n
Only valid if the callback token is a binary operator token.
*/
EOprtAssociativity ParserCallback::GetAssociativity() const { return m_eOprtAsct; }
//---------------------------------------------------------------------------
/** \brief Constructor for constructing function callbacks taking two arguments.
\throw nothrow
*/
ParserCallback::ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(2)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(3)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(4)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(5)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(6)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(7)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(8)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(9)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(10)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_BULK)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(multfun_type a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(-1)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC)
,m_iType(tpDBL)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(0)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_STR)
,m_iType(tpSTR)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(1)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_STR)
,m_iType(tpSTR)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
ParserCallback::ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti)
:m_pFun((void*)a_pFun)
,m_iArgc(2)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmFUNC_STR)
,m_iType(tpSTR)
,m_bAllowOpti(a_bAllowOpti)
{}
//---------------------------------------------------------------------------
/** \brief Default constructor.
\throw nothrow
*/
ParserCallback::ParserCallback()
:m_pFun(0)
,m_iArgc(0)
,m_iPri(-1)
,m_eOprtAsct(oaNONE)
,m_iCode(cmUNKNOWN)
,m_iType(tpVOID)
,m_bAllowOpti(0)
{}
//---------------------------------------------------------------------------
/** \brief Copy constructor.
\throw nothrow
*/
ParserCallback::ParserCallback(const ParserCallback &ref)
{
m_pFun = ref.m_pFun;
m_iArgc = ref.m_iArgc;
m_bAllowOpti = ref.m_bAllowOpti;
m_iCode = ref.m_iCode;
m_iType = ref.m_iType;
m_iPri = ref.m_iPri;
m_eOprtAsct = ref.m_eOprtAsct;
}
//---------------------------------------------------------------------------
/** \brief Clone this instance and return a pointer to the new instance. */
ParserCallback* ParserCallback::Clone() const
{
return new ParserCallback(*this);
}
//---------------------------------------------------------------------------
/** \brief Return tru if the function is conservative.
Conservative functions return always the same result for the same argument.
\throw nothrow
*/
bool ParserCallback::IsOptimizable() const
{
return m_bAllowOpti;
}
//---------------------------------------------------------------------------
/** \brief Get the callback address for the parser function.
The type of the address is void. It needs to be recasted according to the
argument number to the right type.
\throw nothrow
\return #pFun
*/
void* ParserCallback::GetAddr() const
{
return m_pFun;
}
//---------------------------------------------------------------------------
/** \brief Return the callback code. */
ECmdCode ParserCallback::GetCode() const
{
return m_iCode;
}
//---------------------------------------------------------------------------
ETypeCode ParserCallback::GetType() const
{
return m_iType;
}
//---------------------------------------------------------------------------
/** \brief Return the operator precedence.
\throw nothrown
Only valid if the callback token is an operator token (binary or infix).
*/
int ParserCallback::GetPri() const
{
return m_iPri;
}
//---------------------------------------------------------------------------
/** \brief Return the operators associativity.
\throw nothrown
Only valid if the callback token is a binary operator token.
*/
EOprtAssociativity ParserCallback::GetAssociativity() const
{
return m_eOprtAsct;
}
//---------------------------------------------------------------------------
/** \brief Returns the number of function Arguments. */
int ParserCallback::GetArgc() const
{
return m_iArgc;
}
} // namespace mu
//---------------------------------------------------------------------------
/** \brief Returns the number of function Arguments. */
int ParserCallback::GetArgc() const { return m_iArgc; }
} // namespace mu

File diff suppressed because it is too large Load diff

View file

@ -1,337 +1,238 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2011 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "muParserError.h"
#include "muParserDef.h"
#include <assert.h>
namespace mu
{
const ParserErrorMsg ParserErrorMsg::m_Instance;
namespace mu {
//---------------------------------------------------------------------------
string_type parser_error_for_code(EErrorCodes code) {
switch (code) {
case ecUNASSIGNABLE_TOKEN:
return _T("Unexpected token \"$TOK$\" found at position $POS$.");
case ecINVALID_NAME:
return _T("Invalid function-, variable- or constant name: \"$TOK$\".");
case ecINVALID_BINOP_IDENT:
return _T("Invalid binary operator identifier: \"$TOK$\".");
case ecINVALID_INFIX_IDENT:
return _T("Invalid infix operator identifier: \"$TOK$\".");
case ecINVALID_POSTFIX_IDENT:
return _T("Invalid postfix operator identifier: \"$TOK$\".");
case ecINVALID_FUN_PTR:
return _T("Invalid pointer to callback function.");
case ecEMPTY_EXPRESSION:
return _T("Expression is empty.");
case ecINVALID_VAR_PTR:
return _T("Invalid pointer to variable.");
case ecUNEXPECTED_OPERATOR:
return _T("Unexpected operator \"$TOK$\" found at position $POS$");
case ecUNEXPECTED_EOF:
return _T("Unexpected end of expression at position $POS$");
case ecUNEXPECTED_ARG_SEP:
return _T("Unexpected argument separator at position $POS$");
case ecUNEXPECTED_PARENS:
return _T("Unexpected parenthesis \"$TOK$\" at position $POS$");
case ecUNEXPECTED_FUN:
return _T("Unexpected function \"$TOK$\" at position $POS$");
case ecUNEXPECTED_VAL:
return _T("Unexpected value \"$TOK$\" found at position $POS$");
case ecUNEXPECTED_VAR:
return _T("Unexpected variable \"$TOK$\" found at position $POS$");
case ecUNEXPECTED_ARG:
return _T("Function arguments used without a function (position: $POS$)");
case ecMISSING_PARENS:
return _T("Missing parenthesis");
case ecTOO_MANY_PARAMS:
return _T("Too many parameters for function \"$TOK$\" at expression position $POS$");
case ecTOO_FEW_PARAMS:
return _T("Too few parameters for function \"$TOK$\" at expression position $POS$");
case ecDIV_BY_ZERO:
return _T("Divide by zero");
case ecDOMAIN_ERROR:
return _T("Domain error");
case ecNAME_CONFLICT:
return _T("Name conflict");
case ecOPT_PRI:
return _T("Invalid value for operator priority (must be greater or equal to zero).");
case ecBUILTIN_OVERLOAD:
return _T("user defined binary operator \"$TOK$\" conflicts with a built in operator.");
case ecUNEXPECTED_STR:
return _T("Unexpected string token found at position $POS$.");
case ecUNTERMINATED_STRING:
return _T("Unterminated string starting at position $POS$.");
case ecSTRING_EXPECTED:
return _T("String function called with a non string type of argument.");
case ecVAL_EXPECTED:
return _T("String value used where a numerical argument is expected.");
case ecOPRT_TYPE_CONFLICT:
return _T("No suitable overload for operator \"$TOK$\" at position $POS$.");
case ecSTR_RESULT:
return _T("Function result is a string.");
case ecGENERIC:
return _T("Parser error.");
case ecLOCALE:
return _T("Decimal separator is identic to function argument separator.");
case ecUNEXPECTED_CONDITIONAL:
return _T("The \"$TOK$\" operator must be preceeded by a closing bracket.");
case ecMISSING_ELSE_CLAUSE:
return _T("If-then-else operator is missing an else clause");
case ecMISPLACED_COLON:
return _T("Misplaced colon at position $POS$");
case ecUNREASONABLE_NUMBER_OF_COMPUTATIONS:
return _T("Number of computations to small for bulk mode. (Vectorisation overhead too ")
_T("costly)");
default:
assert(0 && "Invalid error code");
return string_type();
}
}
//------------------------------------------------------------------------------
const ParserErrorMsg& ParserErrorMsg::Instance()
{
return m_Instance;
}
//---------------------------------------------------------------------------
//
// ParserError class
//
//---------------------------------------------------------------------------
//------------------------------------------------------------------------------
string_type ParserErrorMsg::operator[](unsigned a_iIdx) const
{
return (a_iIdx<m_vErrMsg.size()) ? m_vErrMsg[a_iIdx] : string_type();
}
/** \brief Default constructor. */
ParserError::ParserError() {}
//---------------------------------------------------------------------------
ParserErrorMsg::~ParserErrorMsg()
{}
//------------------------------------------------------------------------------
/** \brief This Constructor is used for internal exceptions only.
//---------------------------------------------------------------------------
/** \brief Assignement operator is deactivated.
*/
ParserErrorMsg& ParserErrorMsg::operator=(const ParserErrorMsg& )
{
assert(false);
return *this;
}
//---------------------------------------------------------------------------
ParserErrorMsg::ParserErrorMsg(const ParserErrorMsg&)
{}
//---------------------------------------------------------------------------
ParserErrorMsg::ParserErrorMsg()
:m_vErrMsg(0)
{
m_vErrMsg.resize(ecCOUNT);
m_vErrMsg[ecUNASSIGNABLE_TOKEN] = _T("Unexpected token \"$TOK$\" found at position $POS$.");
m_vErrMsg[ecINTERNAL_ERROR] = _T("Internal error");
m_vErrMsg[ecINVALID_NAME] = _T("Invalid function-, variable- or constant name: \"$TOK$\".");
m_vErrMsg[ecINVALID_BINOP_IDENT] = _T("Invalid binary operator identifier: \"$TOK$\".");
m_vErrMsg[ecINVALID_INFIX_IDENT] = _T("Invalid infix operator identifier: \"$TOK$\".");
m_vErrMsg[ecINVALID_POSTFIX_IDENT] = _T("Invalid postfix operator identifier: \"$TOK$\".");
m_vErrMsg[ecINVALID_FUN_PTR] = _T("Invalid pointer to callback function.");
m_vErrMsg[ecEMPTY_EXPRESSION] = _T("Expression is empty.");
m_vErrMsg[ecINVALID_VAR_PTR] = _T("Invalid pointer to variable.");
m_vErrMsg[ecUNEXPECTED_OPERATOR] = _T("Unexpected operator \"$TOK$\" found at position $POS$");
m_vErrMsg[ecUNEXPECTED_EOF] = _T("Unexpected end of expression at position $POS$");
m_vErrMsg[ecUNEXPECTED_ARG_SEP] = _T("Unexpected argument separator at position $POS$");
m_vErrMsg[ecUNEXPECTED_PARENS] = _T("Unexpected parenthesis \"$TOK$\" at position $POS$");
m_vErrMsg[ecUNEXPECTED_FUN] = _T("Unexpected function \"$TOK$\" at position $POS$");
m_vErrMsg[ecUNEXPECTED_VAL] = _T("Unexpected value \"$TOK$\" found at position $POS$");
m_vErrMsg[ecUNEXPECTED_VAR] = _T("Unexpected variable \"$TOK$\" found at position $POS$");
m_vErrMsg[ecUNEXPECTED_ARG] = _T("Function arguments used without a function (position: $POS$)");
m_vErrMsg[ecMISSING_PARENS] = _T("Missing parenthesis");
m_vErrMsg[ecTOO_MANY_PARAMS] = _T("Too many parameters for function \"$TOK$\" at expression position $POS$");
m_vErrMsg[ecTOO_FEW_PARAMS] = _T("Too few parameters for function \"$TOK$\" at expression position $POS$");
m_vErrMsg[ecDIV_BY_ZERO] = _T("Divide by zero");
m_vErrMsg[ecDOMAIN_ERROR] = _T("Domain error");
m_vErrMsg[ecNAME_CONFLICT] = _T("Name conflict");
m_vErrMsg[ecOPT_PRI] = _T("Invalid value for operator priority (must be greater or equal to zero).");
m_vErrMsg[ecBUILTIN_OVERLOAD] = _T("user defined binary operator \"$TOK$\" conflicts with a built in operator.");
m_vErrMsg[ecUNEXPECTED_STR] = _T("Unexpected string token found at position $POS$.");
m_vErrMsg[ecUNTERMINATED_STRING] = _T("Unterminated string starting at position $POS$.");
m_vErrMsg[ecSTRING_EXPECTED] = _T("String function called with a non string type of argument.");
m_vErrMsg[ecVAL_EXPECTED] = _T("String value used where a numerical argument is expected.");
m_vErrMsg[ecOPRT_TYPE_CONFLICT] = _T("No suitable overload for operator \"$TOK$\" at position $POS$.");
m_vErrMsg[ecSTR_RESULT] = _T("Function result is a string.");
m_vErrMsg[ecGENERIC] = _T("Parser error.");
m_vErrMsg[ecLOCALE] = _T("Decimal separator is identic to function argument separator.");
m_vErrMsg[ecUNEXPECTED_CONDITIONAL] = _T("The \"$TOK$\" operator must be preceeded by a closing bracket.");
m_vErrMsg[ecMISSING_ELSE_CLAUSE] = _T("If-then-else operator is missing an else clause");
m_vErrMsg[ecMISPLACED_COLON] = _T("Misplaced colon at position $POS$");
m_vErrMsg[ecUNREASONABLE_NUMBER_OF_COMPUTATIONS] = _T("Number of computations to small for bulk mode. (Vectorisation overhead too costly)");
#if defined(_DEBUG)
for (int i=0; i<ecCOUNT; ++i)
if (!m_vErrMsg[i].length())
assert(false);
#endif
}
//---------------------------------------------------------------------------
//
// ParserError class
//
//---------------------------------------------------------------------------
/** \brief Default constructor. */
ParserError::ParserError()
:m_strMsg()
,m_strFormula()
,m_strTok()
,m_iPos(-1)
,m_iErrc(ecUNDEFINED)
,m_ErrMsg(ParserErrorMsg::Instance())
{
}
//------------------------------------------------------------------------------
/** \brief This Constructor is used for internal exceptions only.
It does not contain any information but the error code.
*/
ParserError::ParserError(EErrorCodes a_iErrc)
:m_strMsg()
,m_strFormula()
,m_strTok()
,m_iPos(-1)
,m_iErrc(a_iErrc)
,m_ErrMsg(ParserErrorMsg::Instance())
{
m_strMsg = m_ErrMsg[m_iErrc];
It does not contain any information but the error code.
*/
ParserError::ParserError(EErrorCodes a_iErrc) : m_iErrc(a_iErrc) {
m_strMsg = parser_error_for_code(m_iErrc);
stringstream_type stream;
stream << (int)m_iPos;
ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
}
}
//------------------------------------------------------------------------------
/** \brief Construct an error from a message text. */
ParserError::ParserError(const string_type &sMsg)
:m_ErrMsg(ParserErrorMsg::Instance())
{
//------------------------------------------------------------------------------
/** \brief Construct an error from a message text. */
ParserError::ParserError(const string_type &sMsg) {
Reset();
m_strMsg = sMsg;
}
}
//------------------------------------------------------------------------------
/** \brief Construct an error object.
\param [in] a_iErrc the error code.
\param [in] sTok The token string related to this error.
\param [in] sExpr The expression related to the error.
\param [in] a_iPos the position in the expression where the error occurred.
*/
ParserError::ParserError( EErrorCodes iErrc,
const string_type &sTok,
const string_type &sExpr,
int iPos )
:m_strMsg()
,m_strFormula(sExpr)
,m_strTok(sTok)
,m_iPos(iPos)
,m_iErrc(iErrc)
,m_ErrMsg(ParserErrorMsg::Instance())
{
m_strMsg = m_ErrMsg[m_iErrc];
//------------------------------------------------------------------------------
/** \brief Construct an error object.
\param [in] a_iErrc the error code.
\param [in] sTok The token string related to this error.
\param [in] a_iPos the position in the expression where the error occurred.
*/
ParserError::ParserError(EErrorCodes iErrc, const string_type &sTok, int iPos)
: m_strTok(sTok), m_iPos(iPos), m_iErrc(iErrc) {
m_strMsg = parser_error_for_code(m_iErrc);
stringstream_type stream;
stream << (int)m_iPos;
ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
}
}
//------------------------------------------------------------------------------
/** \brief Construct an error object.
\param [in] iErrc the error code.
\param [in] iPos the position in the expression where the error occurred.
\param [in] sTok The token string related to this error.
*/
ParserError::ParserError(EErrorCodes iErrc, int iPos, const string_type &sTok)
:m_strMsg()
,m_strFormula()
,m_strTok(sTok)
,m_iPos(iPos)
,m_iErrc(iErrc)
,m_ErrMsg(ParserErrorMsg::Instance())
{
m_strMsg = m_ErrMsg[m_iErrc];
//------------------------------------------------------------------------------
/** \brief Construct an error object.
\param [in] iErrc the error code.
\param [in] iPos the position in the expression where the error occurred.
\param [in] sTok The token string related to this error.
*/
ParserError::ParserError(EErrorCodes iErrc, int iPos, const string_type &sTok)
: m_strMsg(), m_strTok(sTok), m_iPos(iPos), m_iErrc(iErrc) {
m_strMsg = parser_error_for_code(m_iErrc);
stringstream_type stream;
stream << (int)m_iPos;
ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
}
}
//------------------------------------------------------------------------------
/** \brief Construct an error object.
\param [in] szMsg The error message text.
\param [in] iPos the position related to the error.
\param [in] sTok The token string related to this error.
*/
ParserError::ParserError(const char_type *szMsg, int iPos, const string_type &sTok)
:m_strMsg(szMsg)
,m_strFormula()
,m_strTok(sTok)
,m_iPos(iPos)
,m_iErrc(ecGENERIC)
,m_ErrMsg(ParserErrorMsg::Instance())
{
//------------------------------------------------------------------------------
/** \brief Construct an error object.
\param [in] szMsg The error message text.
\param [in] iPos the position related to the error.
\param [in] sTok The token string related to this error.
*/
ParserError::ParserError(const char_type *szMsg, int iPos, const string_type &sTok)
: m_strMsg(szMsg), m_strTok(sTok), m_iPos(iPos), m_iErrc(ecGENERIC) {
stringstream_type stream;
stream << (int)m_iPos;
ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
}
}
//------------------------------------------------------------------------------
/** \brief Copy constructor. */
ParserError::ParserError(const ParserError &a_Obj)
:m_strMsg(a_Obj.m_strMsg)
,m_strFormula(a_Obj.m_strFormula)
,m_strTok(a_Obj.m_strTok)
,m_iPos(a_Obj.m_iPos)
,m_iErrc(a_Obj.m_iErrc)
,m_ErrMsg(ParserErrorMsg::Instance())
{
}
//------------------------------------------------------------------------------
ParserError::~ParserError() {}
//------------------------------------------------------------------------------
/** \brief Assignment operator. */
ParserError& ParserError::operator=(const ParserError &a_Obj)
{
if (this==&a_Obj)
return *this;
m_strMsg = a_Obj.m_strMsg;
m_strFormula = a_Obj.m_strFormula;
m_strTok = a_Obj.m_strTok;
m_iPos = a_Obj.m_iPos;
m_iErrc = a_Obj.m_iErrc;
return *this;
}
//------------------------------------------------------------------------------
ParserError::~ParserError()
{}
//------------------------------------------------------------------------------
/** \brief Replace all occurrences of a substring with another string.
\param strFind The string that shall be replaced.
\param strReplaceWith The string that should be inserted instead of strFind
*/
void ParserError::ReplaceSubString( string_type &strSource,
const string_type &strFind,
const string_type &strReplaceWith)
{
//------------------------------------------------------------------------------
/** \brief Replace all occurrences of a substring with another string.
\param strFind The string that shall be replaced.
\param strReplaceWith The string that should be inserted instead of strFind
*/
void ParserError::ReplaceSubString(string_type &strSource, const string_type &strFind,
const string_type &strReplaceWith) {
string_type strResult;
string_type::size_type iPos(0), iNext(0);
for(;;)
{
iNext = strSource.find(strFind, iPos);
strResult.append(strSource, iPos, iNext-iPos);
for (;;) {
iNext = strSource.find(strFind, iPos);
strResult.append(strSource, iPos, iNext - iPos);
if( iNext==string_type::npos )
break;
if (iNext == string_type::npos) break;
strResult.append(strReplaceWith);
iPos = iNext + strFind.length();
}
strResult.append(strReplaceWith);
iPos = iNext + strFind.length();
}
strSource.swap(strResult);
}
}
//------------------------------------------------------------------------------
/** \brief Reset the erro object. */
void ParserError::Reset()
{
//------------------------------------------------------------------------------
/** \brief Reset the erro object. */
void ParserError::Reset() {
m_strMsg = _T("");
m_strFormula = _T("");
m_strTok = _T("");
m_iPos = -1;
m_iErrc = ecUNDEFINED;
}
//------------------------------------------------------------------------------
/** \brief Set the expression related to this error. */
void ParserError::SetFormula(const string_type &a_strFormula)
{
m_strFormula = a_strFormula;
}
}
//------------------------------------------------------------------------------
/** \brief gets the expression related tp this error.*/
const string_type& ParserError::GetExpr() const
{
return m_strFormula;
}
//------------------------------------------------------------------------------
/** \brief Returns the message string for this error. */
const string_type &ParserError::GetMsg() const { return m_strMsg; }
//------------------------------------------------------------------------------
/** \brief Returns the message string for this error. */
const string_type& ParserError::GetMsg() const
{
return m_strMsg;
}
//------------------------------------------------------------------------------
/** \brief Return the formula position related to the error.
//------------------------------------------------------------------------------
/** \brief Return the formula position related to the error.
If the error is not related to a distinct position this will return -1
*/
int ParserError::GetPos() const { return m_iPos; }
If the error is not related to a distinct position this will return -1
*/
int ParserError::GetPos() const
{
return m_iPos;
}
//------------------------------------------------------------------------------
/** \brief Return string related with this token (if available). */
const string_type &ParserError::GetToken() const { return m_strTok; }
//------------------------------------------------------------------------------
/** \brief Return string related with this token (if available). */
const string_type& ParserError::GetToken() const
{
return m_strTok;
}
//------------------------------------------------------------------------------
/** \brief Return the error code. */
EErrorCodes ParserError::GetCode() const
{
return m_iErrc;
}
} // namespace mu
//------------------------------------------------------------------------------
/** \brief Return the error code. */
EErrorCodes ParserError::GetCode() const { return m_iErrc; }
} // namespace mu

View file

@ -1,32 +1,32 @@
/*
__________
_____ __ __\______ \_____ _______ ______ ____ _______
__________
_____ __ __\______ \_____ _______ ______ ____ _______
/ \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
| Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
|__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
\/ \/ \/ \/
Copyright (C) 2011 Ingo Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "muParserInt.h"
#include <cmath>
#include <algorithm>
#include <cmath>
#include <numeric>
using namespace std;
@ -36,245 +36,219 @@ using namespace std;
*/
/** \brief Namespace for mathematical applications. */
namespace mu
{
value_type ParserInt::Abs(value_type v) { return (value_type)Round(fabs((double)v)); }
value_type ParserInt::Sign(value_type v) { return (Round(v)<0) ? -1 : (Round(v)>0) ? 1 : 0; }
value_type ParserInt::Ite(value_type v1,
value_type v2,
value_type v3) { return (Round(v1)==1) ? Round(v2) : Round(v3); }
value_type ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); }
value_type ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); }
value_type ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); }
value_type ParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); }
value_type ParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); }
value_type ParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); }
value_type ParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); }
value_type ParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); }
value_type ParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); }
value_type ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); }
value_type ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); }
value_type ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); }
value_type ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); }
value_type ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); }
value_type ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); }
value_type ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); }
value_type ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); }
value_type ParserInt::Not(value_type v) { return !Round(v); }
namespace mu {
ValueOrError ParserInt::Abs(value_type v) { return (value_type)Round(fabs((double)v)); }
ValueOrError ParserInt::Sign(value_type v) { return (Round(v) < 0) ? -1 : (Round(v) > 0) ? 1 : 0; }
ValueOrError ParserInt::Ite(value_type v1, value_type v2, value_type v3) {
return (Round(v1) == 1) ? Round(v2) : Round(v3);
}
ValueOrError ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); }
ValueOrError ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); }
ValueOrError ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); }
ValueOrError ParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); }
ValueOrError ParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); }
ValueOrError ParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); }
ValueOrError ParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); }
ValueOrError ParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); }
ValueOrError ParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); }
ValueOrError ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); }
ValueOrError ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); }
ValueOrError ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); }
ValueOrError ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); }
ValueOrError ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); }
ValueOrError ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); }
ValueOrError ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); }
ValueOrError ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); }
ValueOrError ParserInt::Not(value_type v) { return !Round(v); }
value_type ParserInt::Pow(value_type v1, value_type v2)
{
return std::pow((double)Round(v1), (double)Round(v2));
ValueOrError ParserInt::Pow(value_type v1, value_type v2) {
return std::pow((double)Round(v1), (double)Round(v2));
}
//---------------------------------------------------------------------------
// Unary operator Callbacks: Infix operators
value_type ParserInt::UnaryMinus(value_type v)
{
return -Round(v);
ValueOrError ParserInt::UnaryMinus(value_type v) { return -Round(v); }
//---------------------------------------------------------------------------
ValueOrError ParserInt::Sum(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function sum."));
value_type fRes = 0;
for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i];
return fRes;
}
//---------------------------------------------------------------------------
value_type ParserInt::Sum(const value_type* a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw ParserError(_T("too few arguments for function sum."));
ValueOrError ParserInt::Min(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function min."));
value_type fRes=0;
for (int i=0; i<a_iArgc; ++i)
fRes += a_afArg[i];
value_type fRes = a_afArg[0];
for (int i = 0; i < a_iArgc; ++i) fRes = std::min(fRes, a_afArg[i]);
return fRes;
return fRes;
}
//---------------------------------------------------------------------------
value_type ParserInt::Min(const value_type* a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw ParserError( _T("too few arguments for function min.") );
ValueOrError ParserInt::Max(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) return ParserError(_T("too few arguments for function min."));
value_type fRes=a_afArg[0];
for (int i=0; i<a_iArgc; ++i)
fRes = std::min(fRes, a_afArg[i]);
value_type fRes = a_afArg[0];
for (int i = 0; i < a_iArgc; ++i) fRes = std::max(fRes, a_afArg[i]);
return fRes;
}
//---------------------------------------------------------------------------
value_type ParserInt::Max(const value_type* a_afArg, int a_iArgc)
{
if (!a_iArgc)
throw ParserError(_T("too few arguments for function min."));
value_type fRes=a_afArg[0];
for (int i=0; i<a_iArgc; ++i)
fRes = std::max(fRes, a_afArg[i]);
return fRes;
return fRes;
}
//---------------------------------------------------------------------------
// Default value recognition callback
int ParserInt::IsVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)
{
string_type buf(a_szExpr);
std::size_t pos = buf.find_first_not_of(_T("0123456789"));
int ParserInt::IsVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) {
string_type buf(a_szExpr);
std::size_t pos = buf.find_first_not_of(_T("0123456789"));
if (pos==std::string::npos)
return 0;
if (pos == std::string::npos) return 0;
stringstream_type stream( buf.substr(0, pos ) );
int iVal(0);
stringstream_type stream(buf.substr(0, pos));
int iVal(0);
stream >> iVal;
if (stream.fail())
return 0;
stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading
if (stream.fail())
iEnd = stream.str().length();
stream >> iVal;
if (stream.fail()) return 0;
if (iEnd==(stringstream_type::pos_type)-1)
return 0;
stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading
if (stream.fail()) iEnd = stream.str().length();
*a_iPos += (int)iEnd;
*a_fVal = (value_type)iVal;
return 1;
if (iEnd == (stringstream_type::pos_type)-1) return 0;
*a_iPos += (int)iEnd;
*a_fVal = (value_type)iVal;
return 1;
}
//---------------------------------------------------------------------------
/** \brief Check a given position in the expression for the presence of
a hex value.
/** \brief Check a given position in the expression for the presence of
a hex value.
\param a_szExpr Pointer to the expression string
\param [in/out] a_iPos Pointer to an integer value holding the current parsing
\param [in/out] a_iPos Pointer to an integer value holding the current parsing
position in the expression.
\param [out] a_fVal Pointer to the position where the detected value shall be stored.
Hey values must be prefixed with "0x" in order to be detected properly.
*/
int ParserInt::IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)
{
if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') )
return 0;
int ParserInt::IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) {
if (a_szExpr[1] == 0 || (a_szExpr[0] != '0' || a_szExpr[1] != 'x')) return 0;
unsigned iVal(0);
unsigned iVal(0);
// New code based on streams for UNICODE compliance:
stringstream_type::pos_type nPos(0);
stringstream_type ss(a_szExpr + 2);
ss >> std::hex >> iVal;
nPos = ss.tellg();
// New code based on streams for UNICODE compliance:
stringstream_type::pos_type nPos(0);
stringstream_type ss(a_szExpr + 2);
ss >> std::hex >> iVal;
nPos = ss.tellg();
if (nPos==(stringstream_type::pos_type)0)
if (nPos == (stringstream_type::pos_type)0) return 1;
*a_iPos += (int)(2 + nPos);
*a_fVal = (value_type)iVal;
return 1;
*a_iPos += (int)(2 + nPos);
*a_fVal = (value_type)iVal;
return 1;
}
//---------------------------------------------------------------------------
int ParserInt::IsBinVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)
{
if (a_szExpr[0]!='#')
return 0;
int ParserInt::IsBinVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal) {
if (a_szExpr[0] != '#') return 0;
unsigned iVal(0),
iBits(sizeof(iVal)*8),
i(0);
unsigned iVal(0), iBits(sizeof(iVal) * 8), i(0);
for (i=0; (a_szExpr[i+1]=='0' || a_szExpr[i+1]=='1') && i<iBits; ++i)
iVal |= (int)(a_szExpr[i+1]=='1') << ((iBits-1)-i);
for (i = 0; (a_szExpr[i + 1] == '0' || a_szExpr[i + 1] == '1') && i < iBits; ++i)
iVal |= (int)(a_szExpr[i + 1] == '1') << ((iBits - 1) - i);
if (i==0)
return 0;
if (i == 0) return 0;
if (i==iBits)
throw exception_type(_T("Binary to integer conversion error (overflow)."));
// return false on overflow
if (i == iBits) return 0;
*a_fVal = (unsigned)(iVal >> (iBits-i) );
*a_iPos += i+1;
*a_fVal = (unsigned)(iVal >> (iBits - i));
*a_iPos += i + 1;
return 1;
return 1;
}
//---------------------------------------------------------------------------
/** \brief Constructor.
/** \brief Constructor.
Call ParserBase class constructor and trigger Function, Operator and Constant initialization.
*/
ParserInt::ParserInt()
:ParserBase()
{
AddValIdent(IsVal); // lowest priority
AddValIdent(IsBinVal);
AddValIdent(IsHexVal); // highest priority
ParserInt::ParserInt() : ParserBase() {
AddValIdent(IsVal); // lowest priority
AddValIdent(IsBinVal);
AddValIdent(IsHexVal); // highest priority
InitCharSets();
InitFun();
InitOprt();
InitCharSets();
InitFun();
InitOprt();
}
//---------------------------------------------------------------------------
void ParserInt::InitConst()
{
}
void ParserInt::InitConst() {}
//---------------------------------------------------------------------------
void ParserInt::InitCharSets()
{
DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") );
DefineOprtChars( _T("+-*^/?<>=!%&|~'_") );
DefineInfixOprtChars( _T("/+-*^?<>=!%&|~'_") );
void ParserInt::InitCharSets() {
DefineNameChars(_T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"));
DefineOprtChars(_T("+-*^/?<>=!%&|~'_"));
DefineInfixOprtChars(_T("/+-*^?<>=!%&|~'_"));
}
/// assert that the given optional error \p oerr is not an error.
/// This is used only during initialization, when it ought to be impossible
/// to generate an error.
static void assertNoError(OptionalError oerr) {
assert(!oerr.has_error() && "Unexpected error during initialization");
(void)oerr;
}
//---------------------------------------------------------------------------
/** \brief Initialize the default functions. */
void ParserInt::InitFun()
{
DefineFun( _T("sign"), Sign);
DefineFun( _T("abs"), Abs);
DefineFun( _T("if"), Ite);
DefineFun( _T("sum"), Sum);
DefineFun( _T("min"), Min);
DefineFun( _T("max"), Max);
void ParserInt::InitFun() {
assertNoError(DefineFun(_T("sign"), Sign));
assertNoError(DefineFun(_T("abs"), Abs));
assertNoError(DefineFun(_T("if"), Ite));
assertNoError(DefineFun(_T("sum"), Sum));
assertNoError(DefineFun(_T("min"), Min));
assertNoError(DefineFun(_T("max"), Max));
}
//---------------------------------------------------------------------------
/** \brief Initialize operators. */
void ParserInt::InitOprt()
{
// disable all built in operators, not all of them useful for integer numbers
// (they don't do rounding of values)
EnableBuiltInOprt(false);
void ParserInt::InitOprt() {
// disable all built in operators, not all of them useful for integer numbers
// (they don't do rounding of values)
EnableBuiltInOprt(false);
// Disable all built in operators, they wont work with integer numbers
// since they are designed for floating point numbers
DefineInfixOprt( _T("-"), UnaryMinus);
DefineInfixOprt( _T("!"), Not);
// Disable all built in operators, they wont work with integer numbers
// since they are designed for floating point numbers
assertNoError(DefineInfixOprt(_T("-"), UnaryMinus));
assertNoError(DefineInfixOprt(_T("!"), Not));
DefineOprt( _T("&"), LogAnd, prLOGIC);
DefineOprt( _T("|"), LogOr, prLOGIC);
DefineOprt( _T("&&"), And, prLOGIC);
DefineOprt( _T("||"), Or, prLOGIC);
assertNoError(DefineOprt(_T("&"), LogAnd, prLOGIC));
assertNoError(DefineOprt(_T("|"), LogOr, prLOGIC));
assertNoError(DefineOprt(_T("&&"), And, prLOGIC));
assertNoError(DefineOprt(_T("||"), Or, prLOGIC));
DefineOprt( _T("<"), Less, prCMP);
DefineOprt( _T(">"), Greater, prCMP);
DefineOprt( _T("<="), LessEq, prCMP);
DefineOprt( _T(">="), GreaterEq, prCMP);
DefineOprt( _T("=="), Equal, prCMP);
DefineOprt( _T("!="), NotEqual, prCMP);
assertNoError(DefineOprt(_T("<"), Less, prCMP));
assertNoError(DefineOprt(_T(">"), Greater, prCMP));
assertNoError(DefineOprt(_T("<="), LessEq, prCMP));
assertNoError(DefineOprt(_T(">="), GreaterEq, prCMP));
assertNoError(DefineOprt(_T("=="), Equal, prCMP));
assertNoError(DefineOprt(_T("!="), NotEqual, prCMP));
DefineOprt( _T("+"), Add, prADD_SUB);
DefineOprt( _T("-"), Sub, prADD_SUB);
assertNoError(DefineOprt(_T("+"), Add, prADD_SUB));
assertNoError(DefineOprt(_T("-"), Sub, prADD_SUB));
DefineOprt( _T("*"), Mul, prMUL_DIV);
DefineOprt( _T("/"), Div, prMUL_DIV);
DefineOprt( _T("%"), Mod, prMUL_DIV);
assertNoError(DefineOprt(_T("*"), Mul, prMUL_DIV));
assertNoError(DefineOprt(_T("/"), Div, prMUL_DIV));
assertNoError(DefineOprt(_T("%"), Mod, prMUL_DIV));
DefineOprt( _T("^"), Pow, prPOW, oaRIGHT);
DefineOprt( _T(">>"), Shr, prMUL_DIV+1);
DefineOprt( _T("<<"), Shl, prMUL_DIV+1);
assertNoError(DefineOprt(_T("^"), Pow, prPOW, oaRIGHT));
assertNoError(DefineOprt(_T(">>"), Shr, prMUL_DIV + 1));
assertNoError(DefineOprt(_T("<<"), Shl, prMUL_DIV + 1));
}
} // namespace mu
} // namespace mu

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -116,35 +116,43 @@ static const wchar_t *math_get_arg(int *argidx, wchar_t **argv, wcstring *storag
}
/// Implement integer modulo math operator.
static double moduloOperator(double v, double w) { return (int)v % std::max(1, (int)w); };
static mu::ValueOrError moduloOperator(double v, double w) { return (int)v % std::max(1, (int)w); };
/// Evaluate math expressions.
static int evaluate_expression(wchar_t *cmd, parser_t &parser, io_streams_t &streams,
static int evaluate_expression(const wchar_t *cmd, parser_t &parser, io_streams_t &streams,
math_cmd_opts_t &opts, wcstring &expression) {
UNUSED(parser);
try {
mu::Parser p;
// MuParser doesn't implement the modulo operator so we add it ourselves since there are
// likely users of our old math wrapper around bc that expect it to be available.
p.DefineOprtChars(L"%");
p.DefineOprt(L"%", moduloOperator, mu::prINFIX);
p.SetExpr(expression);
int nNum;
mu::value_type *v = p.Eval(nNum);
for (int i = 0; i < nNum; ++i) {
if (opts.scale == 0) {
streams.out.append_format(L"%ld\n", static_cast<long>(v[i]));
} else {
streams.out.append_format(L"%.*lf\n", opts.scale, v[i]);
}
}
return STATUS_CMD_OK;
} catch (mu::Parser::exception_type &e) {
streams.err.append_format(_(L"%ls: Invalid expression: %ls\n"), cmd, e.GetMsg().c_str());
// Helper to print an error and return an error code.
auto printError = [&streams, cmd](const mu::ParserError &err) {
streams.err.append_format(_(L"%ls: Invalid expression: %ls\n"), cmd, err.GetMsg().c_str());
return STATUS_CMD_ERROR;
};
mu::Parser p;
// MuParser doesn't implement the modulo operator so we add it ourselves since there are
// likely users of our old math wrapper around bc that expect it to be available.
p.DefineOprtChars(L"%");
mu::OptionalError oerr = p.DefineOprt(L"%", moduloOperator, mu::prINFIX);
assert(!oerr.has_error() && "Unexpected error defining modulo operator");
(void)oerr;
oerr = p.SetExpr(expression);
if (oerr.has_error()) return printError(oerr.error());
std::vector<mu::ValueOrError> vs;
p.Eval(&vs);
for (const mu::ValueOrError &v : vs) {
if (v.has_error()) return printError(v.error());
}
for (const mu::ValueOrError &v : vs) {
if (opts.scale == 0) {
streams.out.append_format(L"%ld\n", static_cast<long>(*v));
} else {
streams.out.append_format(L"%.*lf\n", opts.scale, *v);
}
}
return STATUS_CMD_OK;
}
/// The math builtin evaluates math expressions.

View file

@ -4,3 +4,10 @@
####################
# Validate how variables in an expression are handled
####################
# Validate math error reporting
math: Invalid expression: Too few parameters for function "min" at expression position 5
math: Invalid expression: String value used where a numerical argument is expected.
math: Invalid expression: Too few parameters for function "max" at expression position 5
math: Invalid expression: Too few parameters for function "sum" at expression position 5

View file

@ -22,3 +22,9 @@ set x 3
set y 1.5
math "-$x * $y"
math -s1 "-$x * $y"
logmsg Validate math error reporting
not math 'min()'
not math 'min("abc")'
not math 'max()'
not math 'sum()'

View file

@ -22,3 +22,6 @@
2
-4
-4.5
####################
# Validate math error reporting