pax_global_header00006660000000000000000000000064143327123670014522gustar00rootroot0000000000000052 comment=59e0ce1e0d35d42713af67788f19797945d81364 beltoforion-muparser-59e0ce1/000077500000000000000000000000001433271236700163155ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/.gitattributes000066400000000000000000000001051433271236700212040ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=false beltoforion-muparser-59e0ce1/.gitignore000066400000000000000000000005131433271236700203040ustar00rootroot00000000000000 .vs/muparser/v16/.suo *.db *.db-shm *.opendb *.db-wal *.ipch .vs/* build/* out/* CMakeSettings.json CMakeFiles/* libmuparser.so* CMakeCache.txt Makefile muparser-targets.cmake muparser.pc muparserConfig.cmake muparserConfigVersion.cmake t_ParserTest example1 example2 DartConfiguration.tcl cmake_install.cmake CTestTestfile.cmake beltoforion-muparser-59e0ce1/.travis.yml000066400000000000000000000006601433271236700204300ustar00rootroot00000000000000language: c++ sudo: false compiler: - clang - gcc script: # LD_LIBRARY_PATH workaround to find clang's libomp: https://github.com/travis-ci/travis-ci/issues/8613 - if [[ ${CC} = clang ]]; then export LD_LIBRARY_PATH=/usr/local/clang/lib${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH; fi - cmake -DCMAKE_C_FLAGS="-Wall" -DCMAKE_CXX_FLAGS="-Wall" -DCMAKE_INSTALL_PREFIX=~/.local/ . - make install -j2 - ctest --output-on-failure beltoforion-muparser-59e0ce1/CHANGELOG000066400000000000000000000700401433271236700175300ustar00rootroot00000000000000 _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg ======================================================================= https://beltoforion.de/en/muparser ======================================================================= History: -------- Rev 2.3.4: 06.11.2022 --------------------- Build System Changes (CMake): * cmake is using OpenMP target and setting _UNICODE preprocessor definition Compiler Warnings: * fix for issue #117 (sprintf deprecation warning) Rev 2.3.3: 22.01.2022 --------------------- Build System Changes (CMake): * Added a new option "-DENABLE_WIDE_CHAR" to CMake for building muparser with wide character support Compiler Warnings fixed/disabled (Visual Studio): * Disabled compiler warning 26812 (Prefer 'enum class' over 'enum') I consider this a bogus warning. Use of plain old enums has not been deprecated and only MSVC is complaining. * Disabled compiler warning 4251 (... needs to have dll-interface to be used by clients of class ...) When the build system was changed to CMake Linux and Windows builds were unified. Each dynamic library contains the class interface as well as the C-interface. Before the linux shared library was using the class interface and the windows dll was using the C-interface. Only the C-Interface is safe to use when you intent to bring an executable to another linux distribution or windows version! This is up to the client software. I cannot change this because on linux the shared library was always using the class interface. Usually this is not a problem since distributions compile all applications from scratch. If you use the class interface you can not take for granted that your software will run with a muparser version compiled for another operating system or linux distribution! You must either use the C-Interface if you want this or use a static library build of muparser! Security Fixes: (The issues were present in all prior stable releases) * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24167 * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24355 Bugfixes: * fixed a couple of issues for building the C-Interface (muParserDLL.cpp/.h) with wide character support. Rev 2.3.2: 17.06.2020 --------------------- API-Change Revertion (to 2.3.0): * removed final keyword from Parser class (added in 2.3.0) as this was breaking existing Applications Changes: * made Parser class final * using OpenMP is now the default settings for cmake based builds * added optimization for trivial expressions. (Expressions whose RPN only has a single entry) * introduced a maximum length for expressions (5000 Character) * introduced a maximum length for identifiers (100 Characters) * removed the MUP_MATH_EXCEPTION macro and related functionality. (C++ exceptions for divide by zero or sqrt of a negative number are no longer supported) * removed ParserStack.h (replaced with std::stack) * removed macros for defining E and PI (replaced with a static constants) * source code is now aimed at C++17 * the MUP_ASSERT macro is no longer removed in release builds for better protection against segmentation faults Security Fixes: (The issues were present in all prior stable releases) * Prevented multiple access violations for malformed expressions with if then else and functions taking multiple arguments like "sum(0?1,2,3,4:5)" * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23330 * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22922 * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22938 * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23330 * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23410 * Added additional runtime checks for release builds to prevent segmentation faults for invalid expressions Bugfixes: * Fixed an issue where the bulk mode could hang on GCC/CLANG builds due to OpenMP chunksize dropping below 1. Rev 2.3.0 - 2.3.1: ------------------ Short lived releases or prereleases that were replaced by 2.3.2 almost instantly due to API breaking changes. Version 2.3.2 is the successor to version 2.2.6 Rev 2.2.6: 04.10.2018 --------------------- Changes: * Build system is now based on cmake * several compiler warnings fixed Rev 2.2.5: 27.04.2015 --------------------- Changes: * example2 extended to work with UNICODE character set * Applied patch from Issue 9 Bugfixes: * muChar_t in muParserDLL.h was not set properly when UNICODE was used * muparser.dll did not build on UNICODE systems Rev 2.2.4: 02.10.2014 --------------------- Changes: * explicit positive sign allowed Bugfixes: * Fix for Issue 6 (https://code.google.com/p/muparser/issues/detail?id=6) * String constants did not work properly. Using more than a single one was impossible. * Project Files for VS2008 and VS2010 removed from the repository * Fix for Issue 4 (https://code.google.com/p/muparser/issues/detail?id=4) * Fix for VS2013 64 bit build option * return type of ParserError::GetPos changed to int * OpenMP support enabled in the VS2013 project files and precompiled windows DLL's * Bulkmode did not evaluate properly if "=" and "," operator was used in the expression Rev 2.2.3: 22.12.2012 --------------------- Removed features: * build files for msvc2005, borland and watcom compiler were removed Bugfixes: * Bugfix for Intel Compilers added: The power operator did not work properly with Intel C++ composer XE 2011. (see https://sourceforge.net/projects/muparser/forums/forum/462843/topic/5117983/index/page/1) * Issue 3509860: Callbacks of functions with string parameters called twice (see http://sourceforge.net/tracker/?func=detail&aid=3509860&group_id=137191&atid=737979) * Issue 3570423: example1 shows slot number in hexadecimal (see https://sourceforge.net/tracker/?func=detail&aid=3570423&group_id=137191&atid=737979) * Fixes for compiling with the "MUP_MATH_EXCEPTIONS" macro definition: - division by zero in constant expressions was reported with the code "ec_GENERIC" instead of "ecDIV_BY_ZERO" - added throwing of "ecDOMAIN_ERROR" to sqrt and log functions Rev 2.2.2: 18.02.2012 --------------------- Bugfixes: * Optimizer did'nt work properly for division: (see https://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825) Rev 2.2.1: 22.01.2012 --------------------- Bugfixes: * Optimizer bug in 64 bit systems fixed (see https://sourceforge.net/projects/muparser/forums/forum/462843/topic/4977977/index/page/1) Rev 2.2.0: 22.01.2012 --------------------- Improvements: * Optimizer rewritten and improved. In general: more optimizations are now applied to the bytecode. The downside is that callback Functions can no longer be flagged as non-optimizable. (The flag is still present but ignored) This is necessary since the optimizer had to call the functions in order to precalculate the result (see Bugfixes). These calls posed a problems for callback functions with side effects and if-then-else clauses in general since they undermined the shortcut evaluation prinziple. Bugfixes: * Infix operators where not properly detected in the presence of a constant name starting with an underscore which is a valid character for infix operators too (i.e. "-_pi"). * Issue 3463353: Callback functions are called twice during the first call to eval. * Issue 3447007: GetUsedVar unnecessaryly executes callback functions. Rev 2.1.0: 19.11.2011 --------------------- New feature: * Function atan2 added Bugfixes: * Issue 3438380: Changed behaviour of tellg with GCC >4.6 led to failures in value detection callbacks. * Issue 3438715: only "double" is a valid MUP_BASETYPE MUP_BASETYPE can now be any of: float, double, long double, short, unsigned short, unsigned int, long, unsigned long. Previousely only floating point types were allowed. Using "int" is still not allowed! * Compiler issues with GCC 4.6 fixed * Custom value recognition callbacks added with AddValIdent had lower priority than built in functions. This was causing problems with hex value recognition since detection of non hex values had priority over the detection of hex values. The "0" in the hex prefix "0x" would be read as a separate non-hex number leaving the rest of the expression unparseable. Rev 2.0.0: 04.09.2011 --------------------- This release introduces a new version numbering scheme in order to make future changes in the ABI apparent to users of the library. The number is now based on the SONAME property as used by GNU/Linux. Changes: * Beginning with this version all version numbers will be SONAME compliant * Project files for MSVC2010 added * Project files for MSVC2003 removed * Bytecode parsing engine cleaned up and rewritten * Retrieving all results of expressions made up of comma separate subexpressions is now possible with a new Eval overload. * Callback functions with fixed number of arguments can now have up to 10 Parameters (previous limit was 5) New features: * ternary if-then-else operator added (C++ like; "(...) ? ... : ..." ) * new intrinsic binary operators: "&&", "||" (logical and, or) * A new bulkmode allows submitting large arrays as variables to compute large numbers of expressions with a single call. This can drastically improve parsing performance when interfacing the library from managed languages like C#. (It doesn't bring any performance benefit for C++ users though...) Removed features: * intrinsic "and", "or" and "xor" operators have been removed. I'd like to let users the freedom of defining them on their own versions (either as logical or bitwise operators). * Implementation for complex numbers removed. This was merely a hack. If you need complex numbers try muParserX which provides native support for them. (see: http://beltoforion.de/muparserx/math_expression_parser_en.html) Bugfixes: * User defined operators could collide with built in operators that entirely contained their identifier. i.e. user defined "&" would not work with the built in "&&" operator since the user defined operator was detected with a higher priority resulting in a syntax error. * Detection of unknown variables did not work properly in case a postfix operator was defined which was part of the undefined variable. i.e. If a postfix operator "m" was defined expressions like "multi*1.0" did not detect "multi" as an undefined variable. (Reference: http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979) * Postfix operators sharing the first few characters were causing bogus parsing exception. (Reference: https://sourceforge.net/tracker/?func=detail&aid=3358571&group_id=137191&atid=737979) Rev 1.34: 04.09.2010 -------------------- Changes: * The prefix needed for parsing hex values is now "0x" and no longer "$". * AddValIdent reintroduced into the DLL interface New features: * The associativity of binary operators can now be changed. The pow operator is now right associative. (This is what Mathematica is using) * Separator can now be used outside of functions. This allows compound expressions like: "a=10,b=20,c=a*b" The last "argument" will be taken as the return value Bugfixes: * The copy constructor did not copy binary operator definitions. Those were lost in the copied parser instance. * Mixing special characters and alphabetic characters in binary operator names led to inconsistent parsing behaviour when parsing expressions like "a ++ b" and "a++b" when "++" is defined as a binary operator. Binary operators must now consist entirely of special characters or of alphabetic ones. (original bug report: https://sourceforge.net/projects/muparser/forums/forum/462843/topic/3696881/index/page/1) * User defined operators were not exactly handled like built in operators. This led to inconsistencies in expression evaluation when using them. The results differed due to slightly different precedence rules. * Using empty string arguments ("") would cause a crash of muParser Rev 1.32: 29.01.2010 -------------------- Changes: * "example3" renamed to "example2" * Project/Makefiles files are now provided for: - msvc2003 - msvc2005 - msvc2008 - watcom (makefile) - mingw (makefile) - bcc (makefile) * Project files for borland cpp builder were removed New features: * Added function returning muparsers version number * Added function for resetting the locale Bugfixes: * Changes example1 in order to fix issues with irritating memory leak reports. Added conditional code for memory leak detection with MSVC in example1. (see: http://www.codeproject.com/KB/recipes/FastMathParser.aspx?msg=3286367#xx3286367xx) * Fixed some warnings for gcc Rev 1.31cp: 15.01.2010 (Maintenance release for CodeProject) ---------------------- Changes: * Archive structure changed * C# wrapper added * Fixed issued that prevented compiling with VS2010 Beta2 Rev 1.30: 09.06.2008 -------------------- Changes: * Epsilon of the numerical differentiation algorithm changed to allow greater accuracy. New features: * Setting thousands separator and decimal separator is now possible Bugfixes: * The dll interface did not provide a callback for functions without any arguments. Rev 1.29: Januar 2008 --------------------- Unrelease Version available only via SVN. Rev 1.28: 02. July, 2007 --------------------------- Library changes: * Interface for the dynamic library changed and extended to create an interface using pure C functions only. * mupInit() removed Build system: * MSVC7 Project files removed in favor of MSVC8 Bugfixes: * The dynamic library did not build on other systems than linux due to a misplaced preprocessor definition. This is fixed now. Rev 1.27: --------------------------- Build system: * Modified build\ directory layout introducing some subfolders for the various IDE supported * Project files for BCB and MSVC7 added * Switched to use bakefile 0.2.1 which now correctly creates the "make uninstall" target for autoconf's Makefile.in * Now the library debug builds are named "muparserd" instead of "muparser" to allow multiple mixed release/debug builds to coexist; so e.g. on Windows when building with DEBUG=1, you'll get "muparserd.lib" instead of "muparser.lib" New Features: * Factory functions can now take a user defined pointer * String functions can now be used with up to two additional double parameters * Support for UNICODE character types added * Infix operator priority can now be changed by the user Bugfixes: * An internal error was raised when evaluating an empty expressions * The error message raised in case of name collisions between implicitely defined variables and postfix operators did contain misleading data. Rev 1.26: (unofficial release) ------------------------------ New Features: * Unary operator precedence can now be changed by the user. Rev 1.25: 5. February, 2006 --------------------------- Build system: (special thanks to Francesco Montorsi for implementing it!) * created a bakefile-based build system which adds support for the following win32 compilers: -> MS visual C++ (6 and .NET) -> BorlandC++ (5 or greater) -> Mingw32 (tested with gcc 3.2) -> Watcom (not tested) and for GCC on Unix (using a standard autoconf's configure script). Compatibility improvements: * fixed some small warnings when using -Wall with GCC on Unix * added inclusion guards for win32-specific portions of code * added fixes that remove compiler warnings on Intel C++ and the Solaris C++ compiler. Rev 1.24: 29. October, 2005 --------------------------- Changes: Compatibility improvements: * parser now works on 64 bit compilers * (bytecode base datatype can now be changed freely) Rev 1.23: 19. October, 2005 --------------------------- Changes: Bugfixes: * Variable factory examples in Example1.cpp and Example3.cpp contained a subtle bug. New features: * Added a MSVC6 project file and introduced muParserFixes.h in order to make it compile with MSVC6 Rev 1.22: October, 2005 ----------------------- Release notes: All features of Version 1.22 are similar to Version 1.21. Version 1.22 fixes a compilation issue with gcc 4.0. In order to fix this issue I rewrote part of the library to remove some unnecessary templates. This should make the code cleaner. The Borland Project files were removed. If you want to use it with Borland either use the dll version or create your own project files. I can't support it since I don't have this compiler at hand. Changes: Project Changes: * Borland project files removed (The code should still compile with BCB but I can't provide you with project files) Internal Changes: * unnecessary template files have been removed: - new files: muParserError.cpp, muParserTokenReader.cpp, muParserCallback.cpp - removed Files: muIParserTypes.h Rev 1.2 / 1.21: April, 2005 --------------------------- Release Notes: First of all the interface has changed so this version is not backwards compatible. After receiving a couple of questions about it, this version features support for user defined binary operators. Consequently the built in operators can now be turned off, thus you can deactivate them and write complete customized parser subclasses that only contain the functionality you want. Another new feature is the introduction of callback functions taking string arguments, implicit generation of variables and the Assignment operator. Functionality * New built in operator: xor; Logical xor. * New built in operator: Assignment operator; Defining variables in terms of other variables/constants * New feature: Strings as arguments for callback functions * New feature: User defined binary operators * New feature: ParserInt a class with a sample implementation for integer numbers. * New feature: Callbacks to value regognition functions. * Removed: all predefined postfix operators have been removed. * New project file: Now comes with a ready to use windows DLL. * New project file: Makefile for cygwin now included. * New example: Example3 shows usage of the DLL. Interface changes * New member function: DefineOprt For adding user defined binary operators. * New member function: EnableBuiltInOprt(bool) Enables/Disables built in binary operators. * New member function: AddValIdent(...) to add callbacks for custom value recognition functions. * Removed: SetVar(), SetConst(). * Renamed: Most interface functions have been renamed * Changed: The type for multiargument callbacks multfun_type has changed. It no longer takes a std::vector as input. Internal changes * new class muParserTokenReader.h encapsulates the token identification and token assignment. * Internal handling of function callbacks unified as a result the performance of the bytecode evaluation increased. Rev 1.10 : December 30, 2004 ---------------------------- Release Notes: This version does not contain major new feature compared to V1.07 but its internal structure has changed significantly. The String parsing routine is slower than the one of V1.07 but bytecode parsing is equally fast. On the other hand the error messages of V1.09 are more flexible and you can change its value datatype. It should work on 64-bit systems. For this reason I supply both versions for download. If you use V1.07 and are happy with it there is no need for updating your version. * New example program: Archive now contains two demo programs: One for standard C++ and one for managed C++. * New member function: RemoveVar(...) can be used for removing a single variable from the internal storage. * New member function: GetVar() can be used for querying the variable names and pointers of all variables defined in the parser. * New member function: GetConst() can be used for querying all defined constants and their values. * New member function: GetFunDef() can be used for querying all defined functions and the number of arguments they expect. * Internal structure changed; hanging base datatype at compile time is now possible. * Bugfix: Postfix operator parsing could fail in certain cases; This has been fixed now. * Bugfix: Variable names must will now be tested if they conflict with constant or function names. * Internal change: Removed most dependencies from the C-string libraries. * Internal change: Bytecode is now stored in a separate class: ParserByteCode.h * Internal change: GetUsedVar() does no longer require that variables are defined at time of call. * Internal change: Error treatment changed. ParserException is no longer derived from std::runtime_error; Internal treatment of Error messages changed. * New functions in Parser interface: ValidNameChars(), ValidOprtChars() and ValidPrefixOprtChars() they are used for defining the charset allowed for variable-, operator- and function names. Rev 1.09 : November 20, 2004 ---------------------------- * New member function: RemoveVar(...) can be used for removing a single variable from the internal storage. * Internal structure changed; changing base datatype at compile time is now possible. * Bug fix: Postfix operator parsing could fail in certain cases; This has been fixed now. * Internal change: Removed most dependencies from the C-string libraries. * Internal change: Bytecode is now stored in a separate class: ParserByteCode.h. * Internal change: GetUsedVar() does no longer require that variables are defined at time of call. * Internal change: Error treatment changed. ParserException is no longer derived from std::runtime_error; Internal treatment of Error messages changed. * New functions in Parser interface; ValidNameChars(), ValidOprtChars() and ValidPrefixOprtChars() they are used for defining the charset allowed for variable-, operator- and function names. Rev 1.08 : November, 2004 ------------------------- * unpublished; experimental template version with respect to data type and underlying string type (string <-> widestring). The idea was dropped... Rev 1.07 : September 4 2004 --------------------------- * Improved portability; Changes to make life for MSVC 6 user easier, there are probably still some issues left. * Improved portability; Changes in order to allow compiling on BCB. * New function; value_type Diff(value_type *a_Var, value_type a_fPos) 4th order Differentiation with respect to a certain variable; added in muParser.h. Rev 1.06 : August 20 2004 ------------------------- * Volatile functions added; All overloaded AddFun(...) functions can now take a third parameter indicating that the function can not be optimized. * Internal changes: muParserStack.h simplified; refactorings * Parser is now distributed under the MIT License; all comments changed accordingly. Rev 1.05 : August 20 2004 ------------------------- * Variable/constant names will now be checked for invalid characters. * Querying the names of all variables used in an expression is now possible; new function: GetUsedVar(). * Disabling bytecode parsing is now possible; new function: EnableByteCode(bool bStat). * Predefined functions with variable number of arguments added: sum, avg, min, max. * Unary prefix operators added; new functions: AddPrefixOp(...), ClearPrefixOp(). * Postfix operator interface names changed; new function names: AddPostfixOp(...), ClearPostfixOp(). * Hardcoded sign operators removed in favor of prefix operators; bytecode format changed accordingly. * Internal changes: static array removed in Command code calculation routine; misc. changes. Rev 1.04 : August 16 2004 ------------------------- * Support for functions with variable number of arguments added. * Internal structure changed; new: ParserBase.h, ParserBase.cpp; removed: ParserException.h; changed: Parser.h, Parser.cpp. * Bug in the bytecode calculation function fixed (affected the unary minus operator). * Optimizer can be deactivated; new function: EnableOptimizer(bool bStat). Rev 1.03 : August 10 2004 ------------------------- * Support for user-defined unary postfix operators added; new functions: AddPostOp(), InitPostOp(), ClearPostOp(). * Minor changes to the bytecode parsing routine. * User defined functions can now have up to four parameters. * Performance optimized: simple formula optimization added; (precalculation of constant parts of the expression). * Bug fixes: Multi-arg function parameters, constant name lookup and unary minus did not work properly. Rev 1.02 : July 30 2004 ----------------------- * Support for user defined constants added; new functions: InitConst(), AddConst(), SetConst(), ClearConst(). * Single variables can now be added using AddVar(); you have now the choice of adding them either one by one or all at the same time using SetVar(const varmap_type &a_vVar). * Internal handling of variables changed, is now similar to function handling. * Virtual destructor added; InitFun(), InitConst() are now virtual too thus making it possible to derive new parsers with a modified set of default functions and constants. * Support for user defined functions with 2 or 3 parameters added; bytecode format changed to hold function parameter count. Rev 1.01 : July 23 2004 ----------------------- * Support for user defined functions has been added; new functions: AddFun(), ClearFun(), InitFunctions(). * Built in constants have been removed; the parser contained undocumented built in constants pi, e. There was the possibility of name conflicts with user defined variables. * Setting multiple variables with SetVar can now be done with a map of names and pointers as the only argument. For this reason, a new type Parser::varmap_type was added. The old version that took 3 arguments (array of names, array of pointers, and array length) is now marked as deprecated. * The names of logarithm functions have changed. The new names are: log2 for base 2, log10 or log for base 10, and ln for base e. Rev 1.00 : July 21 2004 ----------------------- * Initial release beltoforion-muparser-59e0ce1/CMakeLists.txt000066400000000000000000000113551433271236700210620ustar00rootroot00000000000000# CMake based on work from @xantares cmake_minimum_required (VERSION 3.1.0) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # By default, build in Release mode. Must appear before project() command if (NOT DEFINED CMAKE_BUILD_TYPE) set (CMAKE_BUILD_TYPE Release CACHE STRING "Build type") endif () project(muParserProject) # Bump versions on release set(MUPARSER_VERSION_MAJOR 2) set(MUPARSER_VERSION_MINOR 3) set(MUPARSER_VERSION_PATCH 4) set(MUPARSER_VERSION ${MUPARSER_VERSION_MAJOR}.${MUPARSER_VERSION_MINOR}.${MUPARSER_VERSION_PATCH}) # Build options option(ENABLE_SAMPLES "Build the samples" ON) option(ENABLE_OPENMP "Enable OpenMP for multithreading" ON) option(ENABLE_WIDE_CHAR "Enable wide character support" OFF) option(BUILD_SHARED_LIBS "Build shared/static libs" ON) if(ENABLE_OPENMP) find_package(OpenMP REQUIRED) endif() # Credit: https://stackoverflow.com/questions/2368811/how-to-set-warning-level-in-cmake/3818084 if(MSVC) # Force to always compile with W4 if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") endif() elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) # Update if necessary set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic") endif() FILE(GLOB_RECURSE MUPARSER_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") #all .cpp add_library(muparser ${MUPARSER_SOURCES}) # Use the headers in the build-tree or the installed ones target_include_directories(muparser PUBLIC $ $ ) # This compiles the "DLL" interface (C API) target_compile_definitions(muparser PRIVATE MUPARSER_DLL) if (BUILD_SHARED_LIBS) target_compile_definitions(muparser PRIVATE MUPARSERLIB_EXPORTS) add_definitions( -DMUPARSERLIB_EXPORTS ) else () target_compile_definitions(muparser PUBLIC MUPARSER_STATIC) add_definitions( -DMUPARSER_STATIC ) endif() if (CMAKE_BUILD_TYPE STREQUAL Debug) target_compile_definitions(muparser PRIVATE _DEBUG) endif () if(ENABLE_OPENMP) target_compile_definitions(muparser PRIVATE MUP_USE_OPENMP) target_link_libraries(muparser PRIVATE OpenMP::OpenMP_CXX) endif() if(ENABLE_WIDE_CHAR) target_compile_definitions(muparser PUBLIC _UNICODE) endif() set_target_properties(muparser PROPERTIES VERSION ${MUPARSER_VERSION} SOVERSION ${MUPARSER_VERSION_MAJOR} ) if(ENABLE_SAMPLES) add_executable(example1 samples/example1/example1.cpp) target_link_libraries(example1 muparser) add_executable(example2 samples/example2/example2.c) target_link_libraries(example2 muparser) endif() # The GNUInstallDirs defines ${CMAKE_INSTALL_DATAROOTDIR} # See https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html include (GNUInstallDirs) set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/muparser) install(TARGETS muparser EXPORT muparser-export LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT RuntimeLibraries ) FILE(GLOB_RECURSE MUPARSER_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") #all .h install(FILES ${MUPARSER_HEADERS} DESTINATION include COMPONENT Development ) # Export the target under the build-tree (no need to install) export(EXPORT muparser-export FILE "${CMAKE_BINARY_DIR}/muparser-targets.cmake" NAMESPACE muparser:: ) add_library(muparser::muparser ALIAS muparser) # Export the installed target (typically for packaging) include(CMakePackageConfigHelpers) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/muparserConfigVersion.cmake" VERSION ${MUPARSER_VERSION} COMPATIBILITY AnyNewerVersion ) configure_file(muparserConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/muparserConfig.cmake" COPYONLY ) install(EXPORT muparser-export FILE muparser-targets.cmake NAMESPACE muparser:: DESTINATION ${INSTALL_CONFIGDIR} ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/muparserConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/muparserConfigVersion.cmake DESTINATION ${INSTALL_CONFIGDIR} COMPONENT Development ) # Define variables for the pkg-config file set(PACKAGE_NAME muparser) if(ENABLE_WIDE_CHAR) set(PKG_CONFIG_FLAGS "-D_UNICODE") endif(ENABLE_WIDE_CHAR) configure_file( muparser.pc.in ${CMAKE_BINARY_DIR}/muparser.pc @ONLY ) install( FILES ${CMAKE_BINARY_DIR}/muparser.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) include(CTest) if (BUILD_TESTING) add_executable (t_ParserTest test/t_ParserTest.cpp) target_link_libraries(t_ParserTest muparser) add_test (NAME ParserTest COMMAND t_ParserTest) endif() beltoforion-muparser-59e0ce1/Install.txt000066400000000000000000000040621433271236700204660ustar00rootroot00000000000000 _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg ======================================================================= https://beltoforion.de/en/muparser/ ======================================================================= Installation ============ muParser can be installed just extracting the sources somewhere and then, from a terminal, typing: cd [path to muParser] cmake . [-DENABLE_SAMPLES=ON/OFF] [-DENABLE_OPENMP=OFF/ON] [-DENABLE_WIDE_CHAR=OFF/ON] [-DBUILD_SHARED_LIBS=ON/OFF] make [sudo*] make install [sudo*] ldconfig cd samples/example1 ./example1 * = this command must be executed with root permissions and thus you have to use 'sudo' or just 'su' to gain root access. Note that installation and ldconfig are not strictly required unless you built in shared mode. The "make" step will create the muParser library in 'lib' and the sample binary in samples/example1. The samples/example2 is win32-specific and thus won't be built. Other miscellaneous info Unix-specific ====================================== If you don't like to have your muParser folder filled by temporary files created by GCC, then you can do the following: mkdir mybuild && cd mybuild && cmake .. && make to put all object files in the "mybuild" directory. If you want to use muParser library in your programs, you can use the pkg-config program (this works only if muParser was installed with 'make install' !). The commands: pkg-config muparser --cflags pkg-config muparser --libs will return all useful info you need to build your programs against muParser ! 3. Where to ask for help ======================== Please report any bugs or issues at the muparser project page at GitHub: https://github.com/beltoforion/muparser/issues beltoforion-muparser-59e0ce1/LICENSE000066400000000000000000000024051433271236700173230ustar00rootroot00000000000000Copyright 2020 Ingo Berg All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. beltoforion-muparser-59e0ce1/README.rst000066400000000000000000000060241433271236700200060ustar00rootroot00000000000000.. image:: https://travis-ci.org/beltoforion/muparser.svg?branch=master :target: https://travis-ci.org/beltoforion/muparser .. image:: https://ci.appveyor.com/api/projects/status/u4882uj8btuspj9x?svg=true :target: https://ci.appveyor.com/project/beltoforion/muparser .. image:: https://img.shields.io/github/issues/beltoforion/muparser.svg?maxAge=360 :target: https://github.com/beltoforion/muparser/issues .. image:: https://img.shields.io/github/release/beltoforion/muparser.svg?maxAge=360 :target: https://github.com/beltoforion/muparser/blob/master/CHANGELOG .. image:: https://repology.org/badge/tiny-repos/muparser.svg :target: https://repology.org/project/muparser/versions muparser - fast math parser library =================================== .. image:: http://beltoforion.de/en/muparser/images/title.webp Change Notes for Revision 2.3.4 =========================== Maintainance Release with updates of the cmake build system. Build System: ------------ - cmake is using OpenMP target and setting _UNICODE preprocessor definition Fixed Compiler Warnings: ----------- - fix for https://github.com/beltoforion/muparser/issues/117 (sprintf deprecated) Change Notes for Revision 2.3.3 =========================== To read the full documentation please go to: http://beltoforion.de/en/muparser. See Install.txt for installation Security Fixes: ------------ The following new issues, discovered by oss-fuzz are fixed: * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24167 (Abrt) * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24355 (Heap-buffer-overflow READ 8) * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25402 (Heap-buffer-overflow READ 8) Bugfixes: ----------- * Fixed a couple of issues for building the C-Interface (muParserDLL.cpp/.h) with wide character support. * fix for https://github.com/beltoforion/muparser/issues/93 * fix for https://github.com/beltoforion/muparser/issues/94 * fix for https://github.com/beltoforion/muparser/issues/110; new expression size limit is 20000 Fixed Compiler Warnings: ----------- * Visual Studio: Disabled compiler warning 26812 (Prefer 'enum class' over 'enum') Use of plain old enums has not been deprecated and only MSVC is complaining. * Visual Studio: Disabled compiler warning 4251 (... needs to have dll-interface to be used by clients of class ...) For technical reason the DLL contains the class API and the DLL API. Just do not use the class API if you intent to share the dll accross windows versions. (The same is true for Linux but distributions do compile each application against their own library version anyway) Changes: ------------ * Adding manual definitions to avoid potential issues with MSVC * Adding missing overrides * Added a new option "-DENABLE_WIDE_CHAR" to CMake for building muparser with wide character support * export muparser targets, such that client projects can import it using find_package() (https://github.com/beltoforion/muparser/pull/81#event-3528671228) beltoforion-muparser-59e0ce1/appveyor.yml000066400000000000000000000005711433271236700207100ustar00rootroot00000000000000version: 1.0.{build} os: Visual Studio 2015 clone_folder: C:\projects\muParser test: off branches: only: - master environment: matrix: - CMAKE_PLATFORM: Visual Studio 14 2015 build_script: - cmake -LAH -G "%CMAKE_PLATFORM%" -DCMAKE_INSTALL_PREFIX="%CD:\=/%/install" . - cmake --build . --config Release --target install - ctest -C Release --output-on-failure beltoforion-muparser-59e0ce1/docs/000077500000000000000000000000001433271236700172455ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/docs/Doxyfile000066400000000000000000002014401433271236700207540ustar00rootroot00000000000000# Doxyfile 1.6.3 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "muParser API -" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 1.35 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = html/ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = YES # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 16 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it parses. # With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this tag. # The format is ext=language, where ext is a file extension, and language is one of # the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, # Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C. Note that for custom extensions you also need to set # FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = YES # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = NO # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by # doxygen. The layout file controls the global structure of the generated output files # in an output format independent way. The create the layout file that represents # doxygen's defaults, run doxygen with the -l option. You can optionally specify a # file name after the option, if omitted DoxygenLayout.xml will be used as the name # of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = html/misc/Main.txt \ html/misc/example.txt \ ../src/ \ ../include/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = html/misc/ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = YES # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = NO # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = classdocu/ # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = html/misc/footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER # are set, an additional index file will be generated that can be used as input for # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated # HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. # For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's # filter section matches. # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvances is that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = NO # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = jpg # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = "C:\Program Files (x86)\Graphviz2.20\bin" # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES beltoforion-muparser-59e0ce1/docs/muparser_doc.html000066400000000000000000000010061433271236700226130ustar00rootroot00000000000000
beltoforion-muparser-59e0ce1/include/000077500000000000000000000000001433271236700177405ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/include/muParser.h000066400000000000000000000051231433271236700217100ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_H #define MU_PARSER_H //--- Standard includes ------------------------------------------------------------------------ #include //--- 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. */ class API_EXPORT_CXX Parser : public ParserBase { public: Parser(); void InitCharSets() override; void InitFun() override; void InitConst() override; void InitOprt() override; void OnDetectVar(string_type* pExpr, int& nStart, int& nEnd) override; value_type Diff(value_type* a_Var, value_type a_fPos, value_type a_fEpsilon = 0) const; protected: static int IsVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal); }; } // namespace mu #endif beltoforion-muparser-59e0ce1/include/muParserBase.h000066400000000000000000000267341433271236700225160ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_BASE_H #define MU_PARSER_BASE_H //--- Standard includes ------------------------------------------------------------------------ #include #include #include #include #include #include #include //--- Parser includes -------------------------------------------------------------------------- #include "muParserDef.h" #include "muParserTokenReader.h" #include "muParserBytecode.h" #include "muParserError.h" #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4251) // ...needs to have dll-interface to be used by clients of class ... #endif namespace mu { /** \file \brief This file contains the class definition of the muparser engine. */ /** \brief Mathematical expressions parser (base parser engine). 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. */ class API_EXPORT_CXX ParserBase { friend class ParserTokenReader; private: /** \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 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 valbuf_type; /** \brief Type for a vector of strings. */ typedef std::vector stringbuf_type; /** \brief Typedef for the token reader. */ typedef ParserTokenReader token_reader_type; /** \brief Type used for parser tokens. */ typedef ParserToken token_type; /** \brief Maximum number of threads spawned by OpenMP when using the bulk mode. */ static const int s_MaxNumOpenMPThreads; 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); virtual ~ParserBase(); value_type Eval() const; value_type* Eval(int& nStackSize) const; void Eval(value_type* results, int nBulkSize); int GetNumResults() const; void SetExpr(const string_type& a_sExpr); void SetVarFactory(facfun_type a_pFactory, void* pUserData = nullptr); 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); 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) \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 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()); } /** \fn void mu::ParserBase::DefineFunUserData \brief Define a parser function with user data (not null). \param a_strName Name of the function \param a_pFun Pointer to the callback function \param a_pUserData Pointer that will be passed back to callback (shall not be nullptr) \param a_bAllowOpt A flag indicating this function may be optimized */ template void DefineFunUserData(const string_type& a_strName, T a_pFun, void* a_pUserData, bool a_bAllowOpt = true) { AddCallback(a_strName, ParserCallback(a_pFun, a_pUserData, a_bAllowOpt), 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); // Clear user defined variables, constants or functions void ClearVar(); void ClearFun(); 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 ParserByteCode& GetByteCode() 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; void SetArgSep(char_type cArgSep); char_type GetArgSep() const; protected: void Init(); void Error(EErrorCodes a_iErrc, int a_iPos = static_cast(mu::string_type::npos), const string_type& a_strTok = string_type()) const; virtual void InitCharSets() = 0; virtual void InitFun() = 0; virtual void InitConst() = 0; virtual void InitOprt() = 0; virtual void OnDetectVar(string_type* pExpr, int& nStart, int& nEnd); 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 change_dec_sep : public std::numpunct { public: explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) :std::numpunct() ,m_nGroup(nGroup) ,m_cDecPoint(cDecSep) ,m_cThousandsSep(cThousandsSep) {} protected: char_type do_decimal_point() const override { return m_cDecPoint; } char_type do_thousands_sep() const override { return m_cThousandsSep; } std::string do_grouping() const override { // 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)); } private: int m_nGroup; char_type m_cDecPoint; char_type m_cThousandsSep; }; private: void Assign(const ParserBase& a_Parser); void InitTokenReader(); void ReInit() const; void AddCallback(const string_type& a_strName, const ParserCallback& a_Callback, funmap_type& a_Storage, const char_type* a_szCharSet); void ApplyRemainingOprt(std::stack& a_stOpt, std::stack& a_stVal) const; void ApplyBinOprt(std::stack& a_stOpt, std::stack& a_stVal) const; void ApplyIfElse(std::stack& a_stOpt, std::stack& a_stVal) const; void ApplyFunc(std::stack& a_stOpt, std::stack& a_stVal, int iArgCount) const; token_type ApplyStrFunc(const token_type& a_FunTok, const std::vector& a_vArg) const; int GetOprtPrecedence(const token_type& a_Tok) const; EOprtAssociativity GetOprtAssociativity(const token_type& a_Tok) const; void CreateRPN() const; value_type ParseString() const; value_type ParseCmdCode() const; value_type ParseCmdCodeShort() const; value_type ParseCmdCodeBulk(int nOffset, int nThreadID) 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; void StackDump(const std::stack& a_stVal, const std::stack& a_stOprt) const; /** \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; std::unique_ptr m_pTokenReader; ///< Managed pointer to the token reader object. 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 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; }; } // namespace mu #if defined(_MSC_VER) #pragma warning(pop) #endif #endif beltoforion-muparser-59e0ce1/include/muParserBytecode.h000066400000000000000000000104161433271236700233700ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_BYTECODE_H #define MU_PARSER_BYTECODE_H #include #include #include #include "muParserDef.h" #include "muParserError.h" #include "muParserToken.h" /** \file \brief Definition of the parser bytecode class. */ namespace mu { struct SToken { ECmdCode Cmd; union { struct // SValData { value_type* ptr; value_type data; value_type data2; } Val; struct // SFunData { // Note: the type is erased in generic_callable_type and the signature of the // function to call is tracked elsewhere in regard with the number of // parameters (args) and the general kind of function (Cmd: cmFUNC, // cmFUNC_STR, or cmFUNC_BULK) generic_callable_type cb; int argc; int idx; } Fun; 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. */ class ParserByteCode final { private: /** \brief Token type for internal use only. */ typedef ParserToken token_type; /** \brief Token vector for storing the RPN. */ typedef std::vector 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: ParserByteCode(); ParserByteCode(const ParserByteCode& a_ByteCode); ParserByteCode& operator=(const ParserByteCode& a_ByteCode); void Assign(const ParserByteCode& a_ByteCode); void AddVar(value_type* a_pVar); void AddVal(value_type a_fVal); void AddOp(ECmdCode a_Oprt); void AddIfElse(ECmdCode a_Oprt); void AddAssignOp(value_type* a_pVar); void AddFun(generic_callable_type a_pFun, int a_iArgc, bool isOptimizable); void AddBulkFun(generic_callable_type a_pFun, int a_iArgc); void AddStrFun(generic_callable_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 { return m_vRPN.size(); } inline const SToken* GetBase() const { if (m_vRPN.size() == 0) throw ParserError(ecINTERNAL_ERROR); else return &m_vRPN[0]; } void AsciiDump(); }; } // namespace mu #endif beltoforion-muparser-59e0ce1/include/muParserCallback.h000066400000000000000000000172621433271236700233340ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_CALLBACK_H #define MU_PARSER_CALLBACK_H #include "muParserDef.h" /** \file \brief Definition of the parser callback class. */ 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* and needs to be casted according to the argument count. Negative argument counts indicate a parser function with a variable number of arguments. */ class API_EXPORT_CXX ParserCallback final { public: ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti); ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode); ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti); 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); 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); ParserCallback(strfun_type4 a_pFun, bool a_bAllowOpti); ParserCallback(strfun_type5 a_pFun, bool a_bAllowOpti); ParserCallback(strfun_type6 a_pFun, bool a_bAllowOpti); // note: a_pUserData shall not be nullptr ParserCallback(fun_userdata_type0 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type1 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type2 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type3 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type4 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type5 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type6 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type7 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type8 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type9 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(fun_userdata_type10 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type0 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type1 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type2 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type3 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type4 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type5 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type6 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type7 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type8 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type9 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(bulkfun_userdata_type10 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(multfun_userdata_type a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(strfun_userdata_type1 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(strfun_userdata_type2 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(strfun_userdata_type3 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(strfun_userdata_type4 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(strfun_userdata_type5 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(strfun_userdata_type6 a_pFun, void* a_pUserData, bool a_bAllowOpti); ParserCallback(); ParserCallback(const ParserCallback& a_Fun); ParserCallback & operator=(const ParserCallback& a_Fun); ~ParserCallback(); ParserCallback* Clone() const; bool IsOptimizable() const; bool IsValid() const; void* GetAddr() const; void* GetUserData() const; ECmdCode GetCode() const; ETypeCode GetType() const; int GetPri() const; EOprtAssociativity GetAssociativity() const; int GetArgc() const; private: void Assign(const ParserCallback& ref); void* m_pFun; ///< Pointer to the callback function or internal data, casted to void int m_iArgc; ///< Internal representation of number of numeric function arguments 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 funmap_type; } // namespace mu #endif beltoforion-muparser-59e0ce1/include/muParserDLL.h000066400000000000000000000503671433271236700222560ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_DLL_H #define MU_PARSER_DLL_H #include "muParserFixes.h" #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)(void); 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); // with user data (not null) typedef muFloat_t(*muFunUserData0_t)(void*); typedef muFloat_t(*muFunUserData1_t)(void*, muFloat_t); typedef muFloat_t(*muFunUserData2_t)(void*, muFloat_t, muFloat_t); typedef muFloat_t(*muFunUserData3_t)(void*, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muFunUserData4_t)(void*, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muFunUserData5_t)(void*, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muFunUserData6_t)(void*, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muFunUserData7_t)(void*, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muFunUserData8_t)(void*, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muFunUserData9_t)(void*, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muFunUserData10_t)(void*, 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); // with user data (not null) typedef muFloat_t(*muBulkFunUserData0_t)(void*, int, int); typedef muFloat_t(*muBulkFunUserData1_t)(void*, int, int, muFloat_t); typedef muFloat_t(*muBulkFunUserData2_t)(void*, int, int, muFloat_t, muFloat_t); typedef muFloat_t(*muBulkFunUserData3_t)(void*, int, int, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muBulkFunUserData4_t)(void*, int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muBulkFunUserData5_t)(void*, int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muBulkFunUserData6_t)(void*, int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muBulkFunUserData7_t)(void*, int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muBulkFunUserData8_t)(void*, int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muBulkFunUserData9_t)(void*, int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muBulkFunUserData10_t)(void*, 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(*muMultFunUserData_t)(void*, const muFloat_t*, muInt_t); // with user data (not null) 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); typedef muFloat_t(*muStrFun4_t)(const muChar_t*, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muStrFun5_t)(const muChar_t*, muFloat_t, muFloat_t, muFloat_t, muFloat_t); // with user data (not null) typedef muFloat_t(*muStrFunUserData1_t)(void*, const muChar_t*); typedef muFloat_t(*muStrFunUserData2_t)(void*, const muChar_t*, muFloat_t); typedef muFloat_t(*muStrFunUserData3_t)(void*, const muChar_t*, muFloat_t, muFloat_t); typedef muFloat_t(*muStrFunUserData4_t)(void*, const muChar_t*, muFloat_t, muFloat_t, muFloat_t); typedef muFloat_t(*muStrFunUserData5_t)(void*, const muChar_t*, muFloat_t, muFloat_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); // with user data (not null) API_EXPORT(void) mupDefineFunUserData0(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData0_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData1(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData1_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData2(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData2_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData3(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData3_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData4(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData4_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData5(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData5_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData6(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData6_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData7(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData7_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData8(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData8_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData9(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData9_t a_pFun, void* a_pUserData, muBool_t a_bOptimize); API_EXPORT(void) mupDefineFunUserData10(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData10_t a_pFun, void* a_pUserData, 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); // with user data (not null) API_EXPORT(void) mupDefineBulkFunUserData0(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData0_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData1(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData1_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData2(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData2_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData3(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData3_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData4(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData4_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData5(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData5_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData6(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData6_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData7(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData7_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData8(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData8_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData9(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData9_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineBulkFunUserData10(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData10_t a_pFun, void* a_pUserData); // 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) mupDefineStrFun4(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun4_t a_pFun); API_EXPORT(void) mupDefineStrFun5(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun5_t a_pFun); // with user data (not null) API_EXPORT(void) mupDefineStrFunUserData1(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData1_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineStrFunUserData2(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData2_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineStrFunUserData3(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData3_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineStrFunUserData4(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData4_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineStrFunUserData5(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData5_t a_pFun, void* a_pUserData); API_EXPORT(void) mupDefineMultFun(muParserHandle_t a_hParser, const muChar_t* a_szName, muMultFun_t a_pFun, muBool_t a_bOptimize); // with user data (not null) API_EXPORT(void) mupDefineMultFunUserData(muParserHandle_t a_hParser, const muChar_t* a_szName, muMultFunUserData_t a_pFun, void* a_pUserData, 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(void); API_EXPORT(void) mupReleaseVar(muFloat_t*); #ifdef __cplusplus } #endif #endif // include guard beltoforion-muparser-59e0ce1/include/muParserDef.h000066400000000000000000000546301433271236700223360ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MUP_DEF_H #define MUP_DEF_H #include #include #include #include #include "muParserFixes.h" /** \file \brief This file contains standard definitions used by the parser. */ /** \brief Define the base datatype for values. This datatype must be a built in value type. You can not use custom classes. It should be working with all types except "int"! */ #define MUP_BASETYPE double /** \brief Activate this option in order to compile with OpenMP support. OpenMP is used only in the bulk mode it may increase the performance a bit. !!! DO NOT ACTIVATE THIS MACRO HERE IF YOU USE CMAKE FOR BUILDING !!! use the cmake option instead! */ //#define MUP_USE_OPENMP #if defined(_UNICODE) /** \brief Definition of the basic parser string type. */ #define MUP_STRING_TYPE std::wstring #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 /** \brief An assertion that does not kill the program. */ #define MUP_ASSERT(COND) \ if (!(COND)) \ { \ stringstream_type ss; \ ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") \ << __FILE__ << _T(" line ") \ << __LINE__ << _T("."); \ throw ParserError( ecINTERNAL_ERROR, -1, ss.str()); \ } #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 26812) #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; } #endif /** \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 = 22, cmVARPOW3 = 23, cmVARPOW4 = 24, cmVARMUL = 25, // operators and functions cmFUNC = 26, ///< 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 }; /** \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 EOprtPrecedence { // binary 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) // infix operators prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator prPOSTFIX = 6 ///< Postfix operator priority (currently unused) }; /** \brief Error codes. */ enum EErrorCodes { // Formula syntax errors ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found ecUNASSIGNABLE_TOKEN = 1, ///< Token can't 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, ecIDENTIFIER_TOO_LONG = 36, ///< Thrown when an identifier with more then 255 characters is used. ecEXPRESSION_TOO_LONG = 37, ///< Throw an exception if the expression has more than 10000 characters. (an arbitrary limit) ecINVALID_CHARACTERS_FOUND = 38,///< The expression or identifier contains invalid non printable characters // internal errors ecINTERNAL_ERROR = 39, ///< 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 }; //------------------------------------------------------------------------------ // 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 stringtype used by the parser. Depends on whether UNICODE is used or not. */ typedef MUP_STRING_TYPE string_type; /** \brief The character type used by the parser. Depends on whether UNICODE is used or not. */ typedef string_type::value_type char_type; /** \brief Typedef for easily using stringstream that respect the parser stringtype. */ typedef std::basic_stringstream, std::allocator > stringstream_type; // Data container types /** \brief Type used for storing variables. */ typedef std::map varmap_type; /** \brief Type used for storing constants. */ typedef std::map valmap_type; /** \brief Type for assigning a string name to an index in the internal string table. */ typedef std::map strmap_type; // Parser callbacks /** \brief Function type used to erase type. Voluntarily needs explicit cast with all other *fun_type*. */ typedef void(*erased_fun_type)(); /** \brief Callback type used for functions without arguments. */ typedef value_type(*fun_type0)(); /** \brief Callback type used for functions with a single arguments. */ typedef value_type(*fun_type1)(value_type); /** \brief Callback type used for functions with two arguments. */ typedef value_type(*fun_type2)(value_type, value_type); /** \brief Callback type used for functions with three arguments. */ typedef value_type(*fun_type3)(value_type, value_type, value_type); /** \brief Callback type used for functions with four arguments. */ typedef value_type(*fun_type4)(value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with five arguments. */ typedef value_type(*fun_type5)(value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with six arguments. */ typedef value_type(*fun_type6)(value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with seven arguments. */ typedef value_type(*fun_type7)(value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with eight arguments. */ typedef value_type(*fun_type8)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions with nine 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 ten 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 with user data (not null) used for functions without arguments. */ typedef value_type(*fun_userdata_type0)(void*); /** \brief Callback type with user data (not null) used for functions with a single arguments. */ typedef value_type(*fun_userdata_type1)(void*, value_type); /** \brief Callback type with user data (not null) used for functions with two arguments. */ typedef value_type(*fun_userdata_type2)(void*, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with three arguments. */ typedef value_type(*fun_userdata_type3)(void*, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with four arguments. */ typedef value_type(*fun_userdata_type4)(void*, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with five arguments. */ typedef value_type(*fun_userdata_type5)(void*, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with six arguments. */ typedef value_type(*fun_userdata_type6)(void*, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with seven arguments. */ typedef value_type(*fun_userdata_type7)(void*, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with eight arguments. */ typedef value_type(*fun_userdata_type8)(void*, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with nine arguments. */ typedef value_type(*fun_userdata_type9)(void*, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with ten arguments. */ typedef value_type(*fun_userdata_type10)(void*, 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 six 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 seven 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 eight 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 nine 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 ten 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 with user data (not null) used for functions without arguments. */ typedef value_type(*bulkfun_userdata_type0)(void*, int, int); /** \brief Callback type with user data (not null) used for functions with a single arguments. */ typedef value_type(*bulkfun_userdata_type1)(void*, int, int, value_type); /** \brief Callback type with user data (not null) used for functions with two arguments. */ typedef value_type(*bulkfun_userdata_type2)(void*, int, int, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with three arguments. */ typedef value_type(*bulkfun_userdata_type3)(void*, int, int, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with four arguments. */ typedef value_type(*bulkfun_userdata_type4)(void*, int, int, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with five arguments. */ typedef value_type(*bulkfun_userdata_type5)(void*, int, int, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with six arguments. */ typedef value_type(*bulkfun_userdata_type6)(void*, int, int, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with seven arguments. */ typedef value_type(*bulkfun_userdata_type7)(void*, int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with eight arguments. */ typedef value_type(*bulkfun_userdata_type8)(void*, int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with nine arguments. */ typedef value_type(*bulkfun_userdata_type9)(void*, int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions with ten arguments. */ typedef value_type(*bulkfun_userdata_type10)(void*, 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 with user data (not null) used for functions and a variable argument list. */ typedef value_type(*multfun_userdata_type)(void*, 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 type used for functions taking a string and three values as arguments. */ typedef value_type(*strfun_type4)(const char_type*, value_type, value_type, value_type); /** \brief Callback type used for functions taking a string and four values as arguments. */ typedef value_type(*strfun_type5)(const char_type*, value_type, value_type, value_type, value_type); /** \brief Callback type used for functions taking a string and five values as arguments. */ typedef value_type(*strfun_type6)(const char_type*, value_type, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions taking a string as an argument. */ typedef value_type(*strfun_userdata_type1)(void*, const char_type*); /** \brief Callback type with user data (not null) used for functions taking a string and a value as arguments. */ typedef value_type(*strfun_userdata_type2)(void*, const char_type*, value_type); /** \brief Callback type with user data (not null) used for functions taking a string and two values as arguments. */ typedef value_type(*strfun_userdata_type3)(void*, const char_type*, value_type, value_type); /** \brief Callback type with user data (not null) used for functions taking a string and a value as arguments. */ typedef value_type(*strfun_userdata_type4)(void*, const char_type*, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions taking a string and two values as arguments. */ typedef value_type(*strfun_userdata_type5)(void*, const char_type*, value_type, value_type, value_type, value_type); /** \brief Callback type with user data (not null) used for functions taking a string and five values as arguments. */ typedef value_type(*strfun_userdata_type6)(void*, const char_type*, value_type, value_type, value_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*); static const int MaxLenExpression = 20000; static const int MaxLenIdentifier = 100; static const string_type ParserVersion = string_type(_T("2.3.4 (Release)")); static const string_type ParserVersionDate = string_type(_T("20221019")); } // end of namespace #if defined(_MSC_VER) #pragma warning(pop) #endif #endif beltoforion-muparser-59e0ce1/include/muParserError.h000066400000000000000000000075401433271236700227270ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_ERROR_H #define MU_PARSER_ERROR_H #include #include #include #include #include #include "muParserDef.h" #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4251) // ...needs to have dll-interface to be used by clients of class ... #endif /** \file \brief This file defines the error class used by the parser. */ namespace mu { /** \brief A class that handles the error messages. */ class ParserErrorMsg final { public: static const ParserErrorMsg& Instance(); string_type operator[](unsigned a_iIdx) const; private: ParserErrorMsg& operator=(const ParserErrorMsg&) = delete; ParserErrorMsg(const ParserErrorMsg&) = delete; ParserErrorMsg(); ~ParserErrorMsg() = default; std::vector m_vErrMsg; ///< A vector with the predefined error messages }; /** \brief Error class of the parser. Part of the math parser package. */ class API_EXPORT_CXX 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 #if defined(_MSC_VER) #pragma warning(pop) #endif #endif beltoforion-muparser-59e0ce1/include/muParserFixes.h000066400000000000000000000064421433271236700227140ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_FIXES_H #define MU_PARSER_FIXES_H /** \file \brief This file contains compatibility fixes for some platforms. */ // // Compatibility fixes // /* From http://gcc.gnu.org/wiki/Visibility */ /* Generic helper definitions for shared library support */ #if defined _WIN32 || defined __CYGWIN__ #define MUPARSER_HELPER_DLL_IMPORT __declspec(dllimport) #define MUPARSER_HELPER_DLL_EXPORT __declspec(dllexport) #define MUPARSER_HELPER_DLL_LOCAL #else #if __GNUC__ >= 4 #define MUPARSER_HELPER_DLL_IMPORT __attribute__ ((visibility ("default"))) #define MUPARSER_HELPER_DLL_EXPORT __attribute__ ((visibility ("default"))) #define MUPARSER_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden"))) #else #define MUPARSER_HELPER_DLL_IMPORT #define MUPARSER_HELPER_DLL_EXPORT #define MUPARSER_HELPER_DLL_LOCAL #endif #endif /* Now we use the generic helper definitions above to define API_EXPORT_CXX and MUPARSER_LOCAL. API_EXPORT_CXX is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build) MUPARSER_LOCAL is used for non-api symbols. */ #ifndef MUPARSER_STATIC /* defined if muParser is compiled as a DLL */ #ifdef MUPARSERLIB_EXPORTS /* defined if we are building the muParser DLL (instead of using it) */ #define API_EXPORT_CXX MUPARSER_HELPER_DLL_EXPORT #else #define API_EXPORT_CXX MUPARSER_HELPER_DLL_IMPORT #endif /* MUPARSER_DLL_EXPORTS */ #define MUPARSER_LOCAL MUPARSER_HELPER_DLL_LOCAL #else /* MUPARSER_STATIC is defined: this means muParser is a static lib. */ #define API_EXPORT_CXX #define MUPARSER_LOCAL #endif /* !MUPARSER_STATIC */ #ifdef _WIN32 #define API_EXPORT(TYPE) API_EXPORT_CXX TYPE __cdecl #else #define API_EXPORT(TYPE) TYPE #endif #endif // include guard beltoforion-muparser-59e0ce1/include/muParserInt.h000066400000000000000000000122011433271236700223560ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_INT_H #define MU_PARSER_INT_H #include "muParserBase.h" #include /** \file \brief Definition of a parser using integer value. */ namespace mu { /** \brief Mathematical expressions parser. 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 can't 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); 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 change_dec_sep : public std::numpunct { public: explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) :std::numpunct() , m_cDecPoint(cDecSep) , m_cThousandsSep(cThousandsSep) , m_nGroup(nGroup) {} protected: virtual char_type do_decimal_point() const { return m_cDecPoint; } virtual char_type do_thousands_sep() const { return m_cThousandsSep; } 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)); } private: int m_nGroup; char_type m_cDecPoint; char_type m_cThousandsSep; }; public: ParserInt(); void InitFun() override; void InitOprt() override; void InitConst() override; void InitCharSets() override; }; } // namespace mu #endif beltoforion-muparser-59e0ce1/include/muParserTemplateMagic.h000066400000000000000000000134321433271236700243470ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_TEMPLATE_MAGIC_H #define MU_PARSER_TEMPLATE_MAGIC_H #include #include "muParserError.h" namespace mu { //----------------------------------------------------------------------------------------------- // // Compile time type detection // //----------------------------------------------------------------------------------------------- /** \brief A class singling out integer types at compile time using template meta programming. */ template struct TypeInfo { static bool IsInteger() { return false; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { static bool IsInteger() { return true; } }; template<> struct TypeInfo { 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 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); } static T UnaryMinus(T v) { return -v; } static T UnaryPlus(T v) { return v; } static T Sum(const T *a_afArg, int a_iArgc) { if (!a_iArgc) throw ParserError(_T("too few arguments for function sum.")); T fRes = 0; for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i]; return fRes; } static T Avg(const T *a_afArg, int a_iArgc) { if (!a_iArgc) throw ParserError(_T("too few arguments for function avg.")); T fRes = 0; for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i]; return fRes / (T)a_iArgc; } static T Min(const T *a_afArg, int a_iArgc) { if (!a_iArgc) throw ParserError(_T("too few arguments for function min.")); T fRes = a_afArg[0]; for (int i = 0; i < a_iArgc; ++i) fRes = std::min(fRes, a_afArg[i]); return fRes; } static T Max(const T *a_afArg, int a_iArgc) { if (!a_iArgc) throw ParserError(_T("too few arguments for function max.")); T fRes = a_afArg[0]; for (int i = 0; i < a_iArgc; ++i) fRes = std::max(fRes, a_afArg[i]); return fRes; } #if defined (__GNUG__) // Bei zu genauer definition von pi kann die Berechnung von // sin(pi*a) mit a=1 10 x langsamer sein! static constexpr T CONST_PI = (T)3.141592653589; #else static constexpr T CONST_PI = (T)3.141592653589793238462643; #endif static constexpr T CONST_E = (T)2.718281828459045235360287; }; } #endif beltoforion-muparser-59e0ce1/include/muParserTest.h000066400000000000000000000222431433271236700225520ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_TEST_H #define MU_PARSER_TEST_H #include #include #include #include // for accumulate #include "muParser.h" #include "muParserInt.h" #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4251) // ...needs to have dll-interface to be used by clients of class ... #endif /** \file \brief This file contains the parser test class. */ namespace mu { /** \brief Namespace for test cases. */ namespace Test { /** \brief Test cases for unit testing. */ class API_EXPORT_CXX ParserTester final { private: static int c_iCount; static value_type f0() { return 42; }; // 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 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 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 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 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 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.")); return a_afArg[0]; } 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.")); return a_afArg[a_iArgc - 1]; } 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.")); value_type fRes = 0; for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i]; return fRes; } static value_type Rnd(value_type v) { return (value_type)(1 + (v * std::rand() / (RAND_MAX + 1.0))); } static value_type RndWithString(const char_type*) { return (value_type)(1.0 + (1000.0 * std::rand() / (RAND_MAX + 1.0))); } static value_type Ping() { return 10; } static value_type ValueOf(const char_type*) { return 123; } static value_type StrFun1(const char_type* v1) { int val(0); stringstream_type(v1) >> val; return (value_type)val; } 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 value_type StrFun4(const char_type* v1, value_type v2, value_type v3, value_type v4) { int val(0); stringstream_type(v1) >> val; return val + v2 + v3 + v4; } static value_type StrFun5(const char_type* v1, value_type v2, value_type v3, value_type v4, value_type v5) { int val(0); stringstream_type(v1) >> val; return val + v2 + v3 + v4 + v5; } static value_type StrFun6(const char_type* v1, value_type v2, value_type v3, value_type v4, value_type v5, value_type v6) { int val(0); stringstream_type(v1) >> val; return val + v2 + v3 + v4 + v5 + v6; } static value_type StrToFloat(const char_type* a_szMsg) { value_type val(0); stringstream_type(a_szMsg) >> val; return val; } // 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); // With user data static value_type FunUd0(void* data) { return reinterpret_cast(data); } static value_type FunUd1(void* data, value_type v) { return reinterpret_cast(data) + v; } static value_type FunUd2(void* data, value_type v1, value_type v2) { return reinterpret_cast(data) + v1 + v2; } static value_type FunUd10(void* data, value_type v1, value_type v2, value_type v3, value_type v4, value_type v5, value_type v6, value_type v7, value_type v8, value_type v9, value_type v10) { return reinterpret_cast(data) + v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10; } static value_type StrFunUd3(void* data, const char_type* v1, value_type v2, value_type v3) { int val(0); stringstream_type(v1) >> val; return reinterpret_cast(data) + val + v2 + v3; } static value_type SumUd(void* data, const value_type* a_afArg, int a_iArgc) { if (!a_iArgc) throw mu::Parser::exception_type(_T("too few arguments for function sum.")); value_type fRes = 0; for (int i = 0; i < a_iArgc; ++i) fRes += a_afArg[i]; return reinterpret_cast(data) + fRes; } 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(); int TestOssFuzzTestCases(); int TestOptimizer(); void Abort() const; public: typedef int (ParserTester::* testfun_type)(); ParserTester(); int Run(); private: std::vector 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 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 #if defined(_MSC_VER) #pragma warning(pop) #endif #endif beltoforion-muparser-59e0ce1/include/muParserToken.h000066400000000000000000000421411433271236700227120ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_TOKEN_H #define MU_PARSER_TOKEN_H #include #include #include #include #include #include #include #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 26812) #endif #include "muParserError.h" #include "muParserCallback.h" /** \file \brief This file contains the parser token definition. */ namespace mu { template struct TplCallType; template <> struct TplCallType<0> { using fun_type = fun_type0; using fun_userdata_type = fun_userdata_type0; using bulkfun_type = bulkfun_type0; using bulkfun_userdata_type = bulkfun_userdata_type0; }; template <> struct TplCallType<1> { using fun_type = fun_type1; using fun_userdata_type = fun_userdata_type1; using bulkfun_type = bulkfun_type1; using bulkfun_userdata_type = bulkfun_userdata_type1; using strfun_type = strfun_type1; using strfun_userdata_type = strfun_userdata_type1; }; template <> struct TplCallType<2> { using fun_type = fun_type2; using fun_userdata_type = fun_userdata_type2; using bulkfun_type = bulkfun_type2; using bulkfun_userdata_type = bulkfun_userdata_type2; using strfun_type = strfun_type2; using strfun_userdata_type = strfun_userdata_type2; }; template <> struct TplCallType<3> { using fun_type = fun_type3; using fun_userdata_type = fun_userdata_type3; using bulkfun_type = bulkfun_type3; using bulkfun_userdata_type = bulkfun_userdata_type3; using strfun_type = strfun_type3; using strfun_userdata_type = strfun_userdata_type3; }; template <> struct TplCallType<4> { using fun_type = fun_type4; using fun_userdata_type = fun_userdata_type4; using bulkfun_type = bulkfun_type4; using bulkfun_userdata_type = bulkfun_userdata_type4; using strfun_type = strfun_type4; using strfun_userdata_type = strfun_userdata_type4; }; template <> struct TplCallType<5> { using fun_type = fun_type5; using fun_userdata_type = fun_userdata_type5; using bulkfun_type = bulkfun_type5; using bulkfun_userdata_type = bulkfun_userdata_type5; using strfun_type = strfun_type5; using strfun_userdata_type = strfun_userdata_type5; }; template <> struct TplCallType<6> { using fun_type = fun_type6; using fun_userdata_type = fun_userdata_type6; using bulkfun_type = bulkfun_type6; using bulkfun_userdata_type = bulkfun_userdata_type6; using strfun_type = strfun_type6; using strfun_userdata_type = strfun_userdata_type6; }; template <> struct TplCallType<7> { using fun_type = fun_type7; using fun_userdata_type = fun_userdata_type7; using bulkfun_type = bulkfun_type7; using bulkfun_userdata_type = bulkfun_userdata_type7; }; template <> struct TplCallType<8> { using fun_type = fun_type8; using fun_userdata_type = fun_userdata_type8; using bulkfun_type = bulkfun_type8; using bulkfun_userdata_type = bulkfun_userdata_type8; }; template <> struct TplCallType<9> { using fun_type = fun_type9; using fun_userdata_type = fun_userdata_type9; using bulkfun_type = bulkfun_type9; using bulkfun_userdata_type = bulkfun_userdata_type9; }; template <> struct TplCallType<10> { using fun_type = fun_type10; using fun_userdata_type = fun_userdata_type10; using bulkfun_type = bulkfun_type10; using bulkfun_userdata_type = bulkfun_userdata_type10; }; struct generic_callable_type { // Note: we keep generic_callable_type a pod for the purpose of layout erased_fun_type _pRawFun; void* _pUserData; template value_type call_fun(Args&&... args) const { static_assert(NbParams == sizeof...(Args), "mismatch between NbParams and Args"); if (_pUserData == nullptr) { auto fun_typed_ptr = reinterpret_cast::fun_type>(_pRawFun); return (*fun_typed_ptr)(std::forward(args)...); } else { auto fun_userdata_typed_ptr = reinterpret_cast::fun_userdata_type>(_pRawFun); return (*fun_userdata_typed_ptr)(_pUserData, std::forward(args)...); } } template value_type call_bulkfun(Args&&... args) const { static_assert(NbParams == sizeof...(Args) - 2, "mismatch between NbParams and Args"); if (_pUserData == nullptr) { auto bulkfun_typed_ptr = reinterpret_cast::bulkfun_type>(_pRawFun); return (*bulkfun_typed_ptr)(std::forward(args)...); } else { auto bulkfun_userdata_typed_ptr = reinterpret_cast::bulkfun_userdata_type>(_pRawFun); return (*bulkfun_userdata_typed_ptr)(_pUserData, std::forward(args)...); } } value_type call_multfun(const value_type* a_afArg, int a_iArgc) const { if (_pUserData == nullptr) { auto multfun_typed_ptr = reinterpret_cast(_pRawFun); return (*multfun_typed_ptr)(a_afArg, a_iArgc); } else { auto multfun_userdata_typed_ptr = reinterpret_cast(_pRawFun); return (*multfun_userdata_typed_ptr)(_pUserData, a_afArg, a_iArgc); } } template value_type call_strfun(Args&&... args) const { static_assert(NbParams == sizeof...(Args), "mismatch between NbParams and Args"); if (_pUserData == nullptr) { auto strfun_typed_ptr = reinterpret_cast::strfun_type>(_pRawFun); return (*strfun_typed_ptr)(std::forward(args)...); } else { auto strfun_userdata_typed_ptr = reinterpret_cast::strfun_userdata_type>(_pRawFun); return (*strfun_userdata_typed_ptr)(_pUserData, std::forward(args)...); } } bool operator==(generic_callable_type other) const { return _pRawFun == other._pRawFun && _pUserData == other._pUserData; } explicit operator bool() const { return _pRawFun != nullptr; } bool operator==(std::nullptr_t) const { return _pRawFun == nullptr; } bool operator!=(std::nullptr_t) const { return _pRawFun != nullptr; } }; static_assert(std::is_trivial::value, "generic_callable_type shall be trivial"); static_assert(std::is_standard_layout::value, "generic_callable_type shall have standard layout"); // C++17: static_assert(std::is_aggregate::value, "generic_callable_type shall be an aggregate"); /** \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:
  • value
  • variable
  • function with numerical arguments
  • functions with a string as argument
  • prefix operators
  • infix operators
  • binary operator
*/ template class ParserToken final { 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 m_pCallback; public: /** \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. Implemented by calling Assign(...) \throw nothrow \post m_iType==cmUNKNOWN \sa #Assign */ ParserToken(const ParserToken& a_Tok) { Assign(a_Tok); } /** \brief Assignment operator. Copy token state from another token and return this. Implemented by calling Assign(...). \throw nothrow */ 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) { m_iCode = a_Tok.m_iCode; m_pTok = a_Tok.m_pTok; m_strTok = a_Tok.m_strTok; m_iIdx = a_Tok.m_iIdx; 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); } //------------------------------------------------------------------------------ /** \brief Assign a token type. Token may not be of type value, variable or function. Those have separate 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()) { // The following types can't be set this way, they have special Set functions MUP_ASSERT(a_iType != cmVAR); MUP_ASSERT(a_iType != cmVAL); MUP_ASSERT(a_iType != cmFUNC); m_iCode = a_iType; m_iType = tpVOID; m_pTok = 0; m_strTok = a_strTok; m_iIdx = -1; return *this; } //------------------------------------------------------------------------------ /** \brief Set Callback type. */ ParserToken& Set(const ParserCallback& a_pCallback, const TString& a_sTok) { MUP_ASSERT(a_pCallback.IsValid()); m_iCode = a_pCallback.GetCode(); m_iType = tpVOID; m_strTok = a_sTok; m_pCallback.reset(new ParserCallback(a_pCallback)); 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()) { 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) { m_iCode = cmVAR; m_iType = tpDBL; m_strTok = a_strTok; m_iIdx = -1; 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) { m_iCode = cmSTRING; m_iType = tpSTR; m_strTok = a_strTok; m_iIdx = static_cast(a_iSize); 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) 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. \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); 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; } } //------------------------------------------------------------------------------ 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); return m_pCallback->GetPri(); } //------------------------------------------------------------------------------ EOprtAssociativity GetAssociativity() const { if (m_pCallback.get() == nullptr || m_pCallback->GetCode() != cmOPRT_BIN) throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetAssociativity(); } //------------------------------------------------------------------------------ /** \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:
  • cmFUNC
  • cmSTRFUNC
  • cmPOSTOP
  • cmINFIXOP
  • cmOPRT_BIN
\sa ECmdCode */ generic_callable_type GetFuncAddr() const { return (m_pCallback.get()) ? generic_callable_type{(erased_fun_type)m_pCallback->GetAddr(), m_pCallback->GetUserData()} : generic_callable_type{}; } //------------------------------------------------------------------------------ /** \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); } } //------------------------------------------------------------------------------ /** \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); return (TBase*)m_pTok; } //------------------------------------------------------------------------------ /** \brief Return the number of function arguments. Valid only if m_iType==CmdFUNC. */ int GetArgCount() const { MUP_ASSERT(m_pCallback.get()); if (!m_pCallback->IsValid()) throw ParserError(ecINTERNAL_ERROR); return m_pCallback->GetArgc(); } //------------------------------------------------------------------------------ /** \brief Return true if the token is a function token that can be optimized. */ bool IsOptimizable() const { return m_pCallback->IsValid() && m_pCallback->IsOptimizable(); } //------------------------------------------------------------------------------ /** \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 #if defined(_MSC_VER) #pragma warning(pop) #endif #endif beltoforion-muparser-59e0ce1/include/muParserTokenReader.h000066400000000000000000000127511433271236700240410ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MU_PARSER_TOKEN_READER_H #define MU_PARSER_TOKEN_READER_H #include #include #include #include #include #include #include #include "muParserDef.h" #include "muParserToken.h" /** \file \brief This file contains the parser token reader definition. */ namespace mu { // Forward declaration class ParserBase; /** \brief Token reader for the ParserBase class. */ class ParserTokenReader final { private: typedef ParserToken token_type; public: ParserTokenReader(ParserBase* a_pParent); ParserTokenReader* Clone(ParserBase* a_pParent) const; 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); 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" 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 assignment 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 }; ParserTokenReader(const ParserTokenReader& a_Reader); ParserTokenReader& operator=(const ParserTokenReader& a_Reader); void Assign(const ParserTokenReader& a_Reader); void SetParent(ParserBase* a_pParent); int ExtractToken(const char_type* a_szCharSet, string_type& a_strTok, std::size_t a_iPos) const; int ExtractOperatorToken(string_type& a_sTok, std::size_t 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; token_type& SaveBeforeReturn(const token_type& tok); ParserBase* m_pParser; string_type m_strFormula; int m_iPos; int m_iSynFlags; bool m_bIgnoreUndefVar; 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 m_vIdentFun; ///< Value token identification function varmap_type m_UsedVar; value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables std::stack m_bracketStack; token_type m_lastTok; char_type m_cArgSep; ///< The character used for separating function arguments }; } // namespace mu #endif beltoforion-muparser-59e0ce1/lib/000077500000000000000000000000001433271236700170635ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/lib/Readme.txt000066400000000000000000000001041433271236700210140ustar00rootroot00000000000000Here goes the libraries (both static and shared) for this component.beltoforion-muparser-59e0ce1/muparser.pc.in000066400000000000000000000005201433271236700211010ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ Name: @PACKAGE_NAME@ Description: Mathematical expressions parser library Version: @MUPARSER_VERSION@ Requires: Libs: -L${libdir} -lmuparser Cflags: -I${includedir} @PKG_CONFIG_FLAGS@ beltoforion-muparser-59e0ce1/muparserConfig.cmake.in000066400000000000000000000003261433271236700227110ustar00rootroot00000000000000get_filename_component(muparser_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) include(CMakeFindDependencyMacro) if(NOT TARGET muparser::muparser) include("${muparser_CMAKE_DIR}/muparser-targets.cmake") endif() beltoforion-muparser-59e0ce1/samples/000077500000000000000000000000001433271236700177615ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/samples/example1/000077500000000000000000000000001433271236700214755ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/samples/example1/example1.cpp000066400000000000000000000377611433271236700237330ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "muParserTest.h" #include "muParser.h" using namespace std; using namespace mu; // Forward declarations void CalcBulk(); // Operator callback functions static value_type Mega(value_type a_fVal) { return a_fVal * 1e6; } static value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; } static value_type Rnd(value_type v) { return v * std::rand() / (value_type)(RAND_MAX + 1.0); } static value_type Not(value_type v) { return v == 0; } static value_type Add(value_type v1, value_type v2) { return v1 + v2; } static value_type Mul(value_type v1, value_type v2) { return v1 * v2; } static value_type Arg2Of2(value_type /* v1 */, value_type v2) { return v2; } static value_type Arg1Of2(value_type v1, value_type /* v2 */) { return v1; } static value_type ThrowAnException(value_type) { throw std::runtime_error("This function does throw an exception."); } static 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 (value_type)nBulkIdx + nThreadIdx + v1; } static value_type Ping() { mu::console() << "ping\n"; return 0; } static value_type StrFun0(const char_type* szMsg) { if (szMsg) mu::console() << szMsg << std::endl; return 999; } static value_type StrFun2(const char_type* v1, value_type v2, value_type v3) { mu::console() << v1 << std::endl; return v2 + v3; } static 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; } // Factory function for creating new parser variables // This could as well be a function performing database queries. static 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; 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]; } int IsBinValue(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal) { if (a_szExpr[0] != 0 && a_szExpr[1] != 'b') return 0; unsigned iVal = 0; unsigned iBits = sizeof(iVal) * 8; unsigned i = 0; for (i = 0; (a_szExpr[i + 2] == '0' || a_szExpr[i + 2] == '1') && i < iBits; ++i) iVal |= (int)(a_szExpr[i + 2] == '1') << ((iBits - 1) - i); if (i == 0) return 0; if (i == iBits) throw mu::Parser::exception_type(_T("Binary to integer conversion error (overflow).")); *a_fVal = (unsigned)(iVal >> (iBits - i)); *a_iPos += i + 2; return 1; } static 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); // 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; return 1; } static void Splash() { mu::console() << _T("\n"); mu::console() << _T(R"( _____ __ _____________ ________ _____ ____________ )") << _T("\n"); mu::console() << _T(R"( / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ )") << _T("\n"); mu::console() << _T(R"( | Y Y \ | / |_> > ___ \| | \/\___\\ ___/ | | \/ )") << _T("\n"); mu::console() << _T(R"( |__|_| /____/| __(____ /___| /___ >\___ >|__| )") << _T("\n"); mu::console() << _T(R"( \/ |__| \/ \/ \/ )") << _T("\n"); mu::console() << _T(" Version ") << Parser().GetVersion(pviFULL) << _T("\n"); mu::console() << _T(" (C) 2022 Ingo Berg\n"); mu::console() << _T("\n"); mu::console() << _T("-----------------------------------------------------------\n"); #if defined(__clang__) // Note: CLANG also identifies as GCC 4.2.1 mu::console() << _T(" Compiled with CLANG Version ") << __clang_major__ << _T(".") << __clang_minor__ << _T(".") << __clang_patchlevel__ << _T("\n"); #elif defined (__GNUC__) mu::console() << _T(" Compiled with GCC Version ") << __GNUC__ << _T(".") << __GNUC_MINOR__ << _T(".") << __GNUC_PATCHLEVEL__ << _T("\n"); #elif defined(_MSC_VER) mu::console() << _T(" Compiled with MSVC Version ") << _MSC_VER << _T("\n"); #endif mu::console() << _T(" IEEE 754 (IEC 559) is ") << ((std::numeric_limits::is_iec559) ? "Available" : " NOT AVAILABLE") << _T("\n"); mu::console() << _T(" ") << sizeof(void*) * 8 << _T("-bit build\n"); } static value_type SelfTest() { mu::console() << _T("-----------------------------------------------------------\n"); mu::console() << _T("Running unit tests:\n\n"); // Skip the self test if the value type is set to an integer type. if (mu::TypeInfo::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(); } return 0; } static 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; } static 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"); } static 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"); } } static 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"); } } /** \brief Check for external keywords. */ static 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; } else if (sLine == _T("dbg")) { string_type dbg = _T("((\"\")), 7"); a_Parser.SetExpr(dbg); mu::console() << dbg; int stackSize; double* v = a_Parser.Eval(stackSize); mu::console() << "=" << *v << std::endl; return 1; } 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]; 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; } static void Calc() { mu::Parser parser; // 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); parser.AddValIdent(IsBinValue); // 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, false); // Add an unoptimizeable function parser.DefineFun(_T("throw"), ThrowAnException); 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); parser.DefineFun(_T("arg2of2"), Arg2Of2); parser.DefineFun(_T("arg1of2"), Arg1Of2, false); parser.DefinePostfixOprt(_T("{ft}"), Milli); parser.DefinePostfixOprt(_T("ft"), Milli); // Define the variable factory parser.SetVarFactory(AddVariable, &parser); 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; } if (!sLine.length()) continue; 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"); // 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"); } } } 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 } int main(int, char**) { Splash(); SelfTest(); Help(); 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() // i'll leave it for this example. console() << _T("aborting...\n"); } return 0; } beltoforion-muparser-59e0ce1/samples/example2/000077500000000000000000000000001433271236700214765ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/samples/example2/Readme.txt000066400000000000000000000011731433271236700234360ustar00rootroot00000000000000 __________ _____ __ __\______ \_____ _______ ______ ____ _______ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \/ \/ \/ \/ Copyright (C) 2004-2020 Ingo Berg This sample demonstrates using muParsers C-interface. The C-Interface is useful when interfacing muParser from different languages such as C#. This sample is intended for use with the MS-Windows OS. The sample should work with windows and linux. beltoforion-muparser-59e0ce1/samples/example2/example2.c000066400000000000000000000342531433271236700233660ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2021 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "muParserDLL.h" #define PARSER_CONST_PI 3.141592653589793238462643 #define PARSER_CONST_E 2.718281828459045235360287 #define PARSER_MAXVARS 10 #ifndef _UNICODE #define _T(x) x #define myprintf printf #define mystrlen strlen #define myfgets fgets #define mystrcmp strcmp #else #define _T(x) L##x #define myprintf wprintf #define mystrlen wcslen #define myfgets fgetws #define mystrcmp wcscmp #endif static void CalcBulk(void); //--------------------------------------------------------------------------- // Callbacks for postfix operators static muFloat_t Mega(muFloat_t a_fVal) { return a_fVal * 1.0e6; } static muFloat_t Milli(muFloat_t a_fVal) { return a_fVal / 1.0e3; } static muFloat_t ZeroArg(void) { myprintf(_T("i'm a function without arguments.\n")); return 123; } static muFloat_t BulkTest(int nBulkIdx, int nThreadIdx, muFloat_t v1) { myprintf(_T("%d,%2.2f\n"), nBulkIdx, v1); return v1 / ((muFloat_t)nBulkIdx + 1); } //--------------------------------------------------------------------------- // Callbacks for infix operators static muFloat_t Not(muFloat_t v) { return v == 0; } //--------------------------------------------------------------------------- // Function callbacks static muFloat_t Rnd(muFloat_t v) { return v * rand() / (muFloat_t)(RAND_MAX + 1.0); } static muFloat_t Sum(const muFloat_t* a_afArg, int a_iArgc) { muFloat_t fRes = 0; int i = 0; for (i = 0; i < a_iArgc; ++i) fRes += a_afArg[i]; return fRes; } //--------------------------------------------------------------------------- // Binarty operator callbacks static muFloat_t Add(muFloat_t v1, muFloat_t v2) { return v1 + v2; } static muFloat_t Mul(muFloat_t v1, muFloat_t v2) { return v1 * v2; } //--------------------------------------------------------------------------- // Factory function for creating new parser variables // This could as well be a function performing database queries. static muFloat_t* AddVariable(const muChar_t* a_szName, void* pUserData) { static muFloat_t afValBuf[PARSER_MAXVARS]; // I don't want dynamic allocation here static int iVal = 0; // so i used this buffer myprintf(_T("Generating new variable \"%s\" (slots left: %d; context pointer: %") PRIxPTR _T(")\n"), a_szName, PARSER_MAXVARS - iVal, (intptr_t)pUserData); afValBuf[iVal] = 0; if (iVal >= PARSER_MAXVARS - 1) { myprintf(_T("Variable buffer overflow.")); return NULL; } return &afValBuf[iVal++]; } //--------------------------------------------------------------------------- static void Intro(muParserHandle_t hParser) { myprintf(_T("\n")); myprintf(_T(" _____ __ _____________ ________ _____ ____________ \n")); myprintf(_T(" / \\| | \\____ \\__ \\\\_ __ \\/ ___// __ \\_ __ \\ \n")); myprintf(_T(" | Y Y \\ | / |_> > ___ \\| | \\/\\___\\\\ ___/ | | \\/ \n")); myprintf(_T(" |__|_| /____/| __(____ /___| /___ >\\___ >|__| \n")); myprintf(_T(" \\/ |__| \\/ \\/ \\/ \n")); myprintf(_T(" Version %s (DLL)\n"), mupGetVersion(hParser)); myprintf(_T(" (C) 2004 - 2020 Ingo Berg\n")); myprintf(_T("\n")); myprintf(_T("-----------------------------------------------------------\n")); #if defined(__clang__) // Note: CLANG also identifies as GCC 4.2.1 myprintf(_T(" Compiled with CLANG Version %d.%d.%d\n"), __clang_major__, __clang_minor__, __clang_patchlevel__); #elif defined (__GNUC__) myprintf(_T(" Compiled with GCC Version %d.%d.%d\n"), __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); #elif defined(_MSC_VER) myprintf(_T(" Compiled with MSVC Version %d\n"), _MSC_VER); #endif myprintf(_T(" %ld-bit build\n"), sizeof(void*) * 8); myprintf(_T("-----------------------------------------------------------\n")); myprintf(_T("Commands:\n")); myprintf(_T(" list var - list parser variables\n")); myprintf(_T(" list exprvar - list expression variables\n")); myprintf(_T(" list const - list all numeric parser constants\n")); myprintf(_T(" locale de - switch to german locale\n")); myprintf(_T(" locale en - switch to english locale\n")); myprintf(_T(" locale reset - reset locale\n")); myprintf(_T(" test bulk - test bulk mode\n")); myprintf(_T(" quit - exits the parser\n\n")); myprintf(_T("-----------------------------------------------------------\n")); myprintf(_T("Constants:\n")); myprintf(_T(" \"_e\" 2.718281828459045235360287\n")); myprintf(_T(" \"_pi\" 3.141592653589793238462643\n")); myprintf(_T("-----------------------------------------------------------\n")); myprintf(_T("Please enter an expression:\n")); } //--------------------------------------------------------------------------- // Callback function for parser errors static void OnError(muParserHandle_t hParser) { myprintf(_T("\nError:\n")); myprintf(_T("------\n")); myprintf(_T("Message: \"%s\"\n"), mupGetErrorMsg(hParser)); myprintf(_T("Token: \"%s\"\n"), mupGetErrorToken(hParser)); myprintf(_T("Position: %d\n"), mupGetErrorPos(hParser)); myprintf(_T("Errc: %d\n"), mupGetErrorCode(hParser)); } //--------------------------------------------------------------------------- static void ListVar(muParserHandle_t a_hParser) { int iNumVar = mupGetVarNum(a_hParser); int i = 0; if (iNumVar == 0) { myprintf(_T("No variables defined\n")); return; } myprintf(_T("\nExpression variables:\n")); myprintf(_T("---------------------\n")); myprintf(_T("Number: %d\n"), iNumVar); for (i = 0; i < iNumVar; ++i) { const muChar_t* szName = 0; muFloat_t* pVar = 0; mupGetVar(a_hParser, i, &szName, &pVar); myprintf(_T("Name: %s Address: [%") PRIxPTR _T("]\n"), szName, (uintptr_t)pVar); } } //--------------------------------------------------------------------------- static void ListExprVar(muParserHandle_t a_hParser) { muInt_t iNumVar = mupGetExprVarNum(a_hParser), i = 0; if (iNumVar == 0) { myprintf(_T("Expression dos not contain variables\n")); return; } myprintf(_T("\nExpression variables:\n")); myprintf(_T("---------------------\n")); myprintf(_T("Expression: %s\n"), mupGetExpr(a_hParser)); myprintf(_T("Number: %d\n"), iNumVar); for (i = 0; i < iNumVar; ++i) { const muChar_t* szName = 0; muFloat_t* pVar = 0; mupGetExprVar(a_hParser, i, &szName, &pVar); myprintf(_T("Name: %s Address: [%") PRIxPTR _T("]\n"), szName, (intptr_t)pVar); } } //--------------------------------------------------------------------------- static void ListConst(muParserHandle_t a_hParser) { muInt_t iNumVar = mupGetConstNum(a_hParser), i = 0; if (iNumVar == 0) { myprintf(_T("No constants defined\n")); return; } myprintf(_T("\nParser constants:\n")); myprintf(_T("---------------------\n")); myprintf(_T("Number: %d\n"), iNumVar); for (i = 0; i < iNumVar; ++i) { const muChar_t* szName = 0; muFloat_t fVal = 0; mupGetConst(a_hParser, i, &szName, &fVal); myprintf(_T(" %s = %f\n"), szName, fVal); } } //--------------------------------------------------------------------------- /** \brief Check for external keywords. */ static int CheckKeywords(const muChar_t* a_szLine, muParserHandle_t a_hParser) { if (!mystrcmp(a_szLine, _T("quit"))) { return -1; } else if (!mystrcmp(a_szLine, _T("list var"))) { ListVar(a_hParser); return 1; } else if (!mystrcmp(a_szLine, _T("list exprvar"))) { ListExprVar(a_hParser); return 1; } else if (!mystrcmp(a_szLine, _T("list const"))) { ListConst(a_hParser); return 1; } else if (!mystrcmp(a_szLine, _T("locale de"))) { myprintf(_T("Setting german locale: ArgSep=';' DecSep=',' ThousandsSep='.'\n")); mupSetArgSep(a_hParser, ';'); mupSetDecSep(a_hParser, ','); mupSetThousandsSep(a_hParser, '.'); return 1; } else if (!mystrcmp(a_szLine, _T("locale en"))) { myprintf(_T("Setting english locale: ArgSep=',' DecSep='.' ThousandsSep=''\n")); mupSetArgSep(a_hParser, ','); mupSetDecSep(a_hParser, '.'); mupSetThousandsSep(a_hParser, 0); return 1; } else if (!mystrcmp(a_szLine, _T("locale reset"))) { myprintf(_T("Resetting locale\n")); mupResetLocale(a_hParser); return 1; } else if (!mystrcmp(a_szLine, _T("test bulk"))) { myprintf(_T("Testing bulk mode\n")); CalcBulk(); return 1; } return 0; } //--------------------------------------------------------------------------- static void CalcBulk(void) { int nBulkSize = 200, i; muFloat_t* x = (muFloat_t*)malloc(nBulkSize * sizeof(muFloat_t)); muFloat_t* y = (muFloat_t*)malloc(nBulkSize * sizeof(muFloat_t)); muFloat_t* r = (muFloat_t*)malloc(nBulkSize * sizeof(muFloat_t)); muParserHandle_t hParser = mupCreate(muBASETYPE_FLOAT); // initialize the parser for (i = 0; i < nBulkSize; ++i) { x[i] = i; y[i] = i; r[i] = 0; } mupDefineVar(hParser, _T("x"), x); mupDefineVar(hParser, _T("y"), y); mupDefineBulkFun1(hParser, _T("bulktest"), BulkTest); mupSetExpr(hParser, _T("bulktest(x+y)")); mupEvalBulk(hParser, r, nBulkSize); if (mupError(hParser)) { myprintf(_T("\nError:\n")); myprintf(_T("------\n")); myprintf(_T("Message: %s\n"), mupGetErrorMsg(hParser)); myprintf(_T("Token: %s\n"), mupGetErrorToken(hParser)); myprintf(_T("Position: %d\n"), mupGetErrorPos(hParser)); myprintf(_T("Errc: %d\n"), mupGetErrorCode(hParser)); return; } for (i = 0; i < nBulkSize; ++i) { myprintf(_T("%d: bulkfun(%2.2f + %2.2f) = %2.2f\n"), i, x[i], y[i], r[i]); x[i] = i; y[i] = (muFloat_t)i / 10; } free(x); free(y); free(r); } //--------------------------------------------------------------------------- static void Calc(void) { muChar_t szLine[100]; muFloat_t fVal = 0, afVarVal[] = { 1, 2 }; // Values of the parser variables muParserHandle_t hParser; hParser = mupCreate(muBASETYPE_FLOAT); // initialize the parser Intro(hParser); // Set an error handler [optional] // the only function that does not take a parser instance handle mupSetErrorHandler(hParser, OnError); //#define GERMAN_LOCALS #ifdef GERMAN_LOCALS mupSetArgSep(hParser, ';'); mupSetDecSep(hParser, ','); mupSetThousandsSep(hParser, '.'); #else mupSetArgSep(hParser, ','); mupSetDecSep(hParser, '.'); #endif // Set a variable factory mupSetVarFactory(hParser, AddVariable, NULL); // Define parser variables and bind them to C++ variables [optional] mupDefineConst(hParser, _T("const1"), 1); mupDefineConst(hParser, _T("const2"), 2); mupDefineStrConst(hParser, _T("strBuf"), _T("Hallo welt")); // Define parser variables and bind them to C++ variables [optional] mupDefineVar(hParser, _T("a"), &afVarVal[0]); mupDefineVar(hParser, _T("b"), &afVarVal[1]); // Define postfix operators [optional] mupDefinePostfixOprt(hParser, _T("M"), Mega, 0); mupDefinePostfixOprt(hParser, _T("m"), Milli, 0); // Define infix operator [optional] mupDefineInfixOprt(hParser, _T("!"), Not, 0); // Define functions [optional] // mupDefineStrFun(hParser, "query", SampleQuery, 0); // Add an unoptimizeable function mupDefineFun0(hParser, _T("zero"), ZeroArg, 0); mupDefineFun1(hParser, _T("rnd"), Rnd, 0); // Add an unoptimizeable function mupDefineFun1(hParser, _T("rnd2"), Rnd, 1); mupDefineMultFun(hParser, _T("_sum"), Sum, 0); // "sum" is already a default function // Define binary operators [optional] mupDefineOprt(hParser, _T("add"), Add, 0, muOPRT_ASCT_LEFT, 0); mupDefineOprt(hParser, _T("mul"), Mul, 1, muOPRT_ASCT_LEFT, 0); while (myfgets(szLine, 99, stdin)) { szLine[mystrlen(szLine) - 1] = 0; // overwrite the newline switch (CheckKeywords(szLine, hParser)) { case 0: break; // no keyword found; parse the line case 1: continue; // A Keyword was found do not parse the line case -1: return; // abort the application } mupSetExpr(hParser, szLine); fVal = mupEval(hParser); // Without an Error handler function // you must use this for error treatment: //if (mupError(hParser)) //{ // myprintf("\nError:\n"); // myprintf("------\n"); // myprintf("Message: %s\n", mupGetErrorMsg(hParser) ); // myprintf("Token: %s\n", mupGetErrorToken(hParser) ); // myprintf("Position: %s\n", mupGetErrorPos(hParser) ); // myprintf("Errc: %d\n", mupGetErrorCode(hParser) ); // continue; //} if (!mupError(hParser)) myprintf(_T("%f\n"), fVal); } // while // finally free the parser resources mupRelease(hParser); } //--------------------------------------------------------------------------- int main(int argc, char* argv[]) { // The next line is just for shutting up the compiler warning // about unused variables without getting another warning about not // being able to use type lists in function declarations. myprintf(_T("Executing \"%s\" (argc=%d)\n"), argv[0], argc); Calc(); myprintf(_T("done...")); } beltoforion-muparser-59e0ce1/samples/example3/000077500000000000000000000000001433271236700214775ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/samples/example3/CMakeLists.txt000066400000000000000000000004241433271236700242370ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.2) project(muparser-example3) # find muparser target already installed find_package(muparser 2.0 REQUIRED) add_executable(example3 example3.cpp) target_link_libraries(example3 muparser::muparser) include(CTest) add_test(example3 example3) beltoforion-muparser-59e0ce1/samples/example3/README.md000066400000000000000000000001641433271236700227570ustar00rootroot00000000000000The example3 shows how to import and use muparser as an installed external dependency using cmake `find_package()`. beltoforion-muparser-59e0ce1/samples/example3/build.sh000077500000000000000000000015211433271236700231340ustar00rootroot00000000000000#!/bin/bash -x CWD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" MP_SOURCES=${CWD}/../../ MP_BUILD=${CWD}/muparser-build MP_INSTALL=${CWD}/muparser-install EX3_BUILD_TREE=${CWD}/example3-using-buildtree EX3_INSTALL_TREE=${CWD}/example3-using-installtree # Build muparser and install it cmake -H${MP_SOURCES} -B${MP_BUILD} -DCMAKE_INSTALL_PREFIX=${MP_INSTALL} cmake --build ${MP_BUILD} --target install # Build the example using muparser build tree cmake -H${CWD} -B${EX3_BUILD_TREE} -DCMAKE_PREFIX_PATH=${MP_BUILD} cmake --build ${EX3_BUILD_TREE} --target all cmake --build ${EX3_BUILD_TREE} --target test # Build the example using muparser install tree cmake -H${CWD} -B${EX3_INSTALL_TREE} -DCMAKE_PREFIX_PATH=${MP_INSTALL} cmake --build ${EX3_INSTALL_TREE} --target all cmake --build ${EX3_INSTALL_TREE} --target test beltoforion-muparser-59e0ce1/samples/example3/example3.cpp000066400000000000000000000041001433271236700237140ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Small example using the cmake imported target. Include file and link library // should work automagically. #include #include int main() { mu::Parser parser; mu::value_type values[] = { 1, 2 }; parser.DefineVar("a", &values[0]); parser.DefineVar("b", &values[1]); std::string expr = "a + b"; parser.SetExpr("a + b"); mu::value_type ans = parser.Eval(); std::cout << expr << " == " << ans << "\n"; return (ans == 3.0) ? 0 : -1; } beltoforion-muparser-59e0ce1/src/000077500000000000000000000000001433271236700171045ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/src/muParser.cpp000066400000000000000000000206301433271236700214070ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "muParser.h" #include "muParserTemplateMagic.h" //--- Standard includes ------------------------------------------------------------------------ #include #include #include using namespace std; /** \file \brief Implementation of the standard floating point parser. */ /** \brief Namespace for mathematical applications. */ namespace mu { //--------------------------------------------------------------------------- /** \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.imbue(Parser::s_locale); stream >> fVal; stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading if (iEnd == (stringstream_type::pos_type) - 1) return 0; *a_iPos += (int)iEnd; *a_fVal = fVal; return 1; } //--------------------------------------------------------------------------- /** \brief Constructor. 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 Initialize the default functions. */ void Parser::InitFun() { if (mu::TypeInfo::IsInteger()) { // When setting MUP_BASETYPE to an integer type // Place functions for dealing with integer values here // ... // ... // ... } else { // trigonometric functions DefineFun(_T("sin"), MathImpl::Sin); DefineFun(_T("cos"), MathImpl::Cos); DefineFun(_T("tan"), MathImpl::Tan); // arcus functions DefineFun(_T("asin"), MathImpl::ASin); DefineFun(_T("acos"), MathImpl::ACos); DefineFun(_T("atan"), MathImpl::ATan); DefineFun(_T("atan2"), MathImpl::ATan2); // hyperbolic functions DefineFun(_T("sinh"), MathImpl::Sinh); DefineFun(_T("cosh"), MathImpl::Cosh); DefineFun(_T("tanh"), MathImpl::Tanh); // arcus hyperbolic functions DefineFun(_T("asinh"), MathImpl::ASinh); DefineFun(_T("acosh"), MathImpl::ACosh); DefineFun(_T("atanh"), MathImpl::ATanh); // Logarithm functions DefineFun(_T("log2"), MathImpl::Log2); DefineFun(_T("log10"), MathImpl::Log10); DefineFun(_T("log"), MathImpl::Log); DefineFun(_T("ln"), MathImpl::Log); // misc DefineFun(_T("exp"), MathImpl::Exp); DefineFun(_T("sqrt"), MathImpl::Sqrt); DefineFun(_T("sign"), MathImpl::Sign); DefineFun(_T("rint"), MathImpl::Rint); DefineFun(_T("abs"), MathImpl::Abs); // Functions with variable number of arguments DefineFun(_T("sum"), MathImpl::Sum); DefineFun(_T("avg"), MathImpl::Avg); DefineFun(_T("min"), MathImpl::Min); DefineFun(_T("max"), MathImpl::Max); } } //--------------------------------------------------------------------------- /** \brief Initialize constants. By default the parser recognizes two constants. Pi ("pi") and the Eulerian number ("_e"). */ void Parser::InitConst() { DefineConst(_T("_pi"), MathImpl::CONST_PI); DefineConst(_T("_e"), MathImpl::CONST_E); } //--------------------------------------------------------------------------- /** \brief Initialize operators. By default only the unary minus operator is added. */ void Parser::InitOprt() { DefineInfixOprt(_T("-"), MathImpl::UnaryMinus); DefineInfixOprt(_T("+"), MathImpl::UnaryPlus); } //--------------------------------------------------------------------------- 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... /* 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::epsilon() ^ (1/5). */ value_type Parser::Diff(value_type* a_Var, value_type a_fPos, value_type a_fEpsilon) const { value_type fRes(0); value_type fBuf(*a_Var); value_type f[4] = { 0,0,0,0 }; value_type 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 beltoforion-muparser-59e0ce1/src/muParserBase.cpp000066400000000000000000001700751433271236700222130ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "muParserBase.h" #include "muParserTemplateMagic.h" //--- Standard includes ------------------------------------------------------------------------ #include #include #include #include #include #include #include #include #include #ifdef MUP_USE_OPENMP #include #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 26812) #endif using namespace std; /** \file \brief This file contains the basic implementation of the muparser engine. */ namespace mu { std::locale ParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep('.')); bool ParserBase::g_DbgDumpCmdCode = false; bool ParserBase::g_DbgDumpStack = false; //------------------------------------------------------------------------------ /** \brief Identifiers for built in binary operators. When defining custom binary operators with #AddOprt(...) make sure not to choose names conflicting with these definitions. */ const char_type* ParserBase::c_DefaultOprt[] = { _T("<="), _T(">="), _T("!="), _T("=="), _T("<"), _T(">"), _T("+"), _T("-"), _T("*"), _T("/"), _T("^"), _T("&&"), _T("||"), _T("="), _T("("), _T(")"), _T("?"), _T(":"), 0 }; const int ParserBase::s_MaxNumOpenMPThreads = 16; //------------------------------------------------------------------------------ /** \brief Constructor. \param a_szFormula the formula to interpret. \throw ParserException if a_szFormula is nullptr. */ ParserBase::ParserBase() : m_pParseFormula(&ParserBase::ParseString) , m_vRPN() , m_vStringBuf() , m_pTokenReader() , m_FunDef() , m_PostOprtDef() , m_InfixOprtDef() , m_OprtDef() , m_ConstDef() , m_StrVarDef() , m_VarDef() , m_bBuiltInOp(true) , m_sNameChars() , m_sOprtChars() , m_sInfixOprtChars() , m_vStackBuffer() , m_nFinalResultIdx(0) { InitTokenReader(); } //--------------------------------------------------------------------------- /** \brief Copy constructor. The parser can be safely copy constructed but the bytecode is reset during copy construction. */ ParserBase::ParserBase(const ParserBase& a_Parser) : m_pParseFormula(&ParserBase::ParseString) , m_vRPN() , m_vStringBuf() , m_pTokenReader() , m_FunDef() , m_PostOprtDef() , m_InfixOprtDef() , m_OprtDef() , m_ConstDef() , m_StrVarDef() , m_VarDef() , m_bBuiltInOp(true) , m_sNameChars() , m_sOprtChars() , m_sInfixOprtChars() { m_pTokenReader.reset(new token_reader_type(this)); Assign(a_Parser); } //--------------------------------------------------------------------------- ParserBase::~ParserBase() {} //--------------------------------------------------------------------------- /** \brief Assignment operator. Implemented by calling Assign(a_Parser). Self assignment is suppressed. \param a_Parser Object to copy to this. \return *this \throw nothrow */ ParserBase& ParserBase::operator=(const ParserBase& a_Parser) { Assign(a_Parser); return *this; } //--------------------------------------------------------------------------- /** \brief Copy state of a parser object to this. Clears Variables and Functions of this parser. Copies the states of all internal variables. Resets parse function to string parse mode. \param a_Parser the source object. */ void ParserBase::Assign(const ParserBase& a_Parser) { if (&a_Parser == this) return; // Don't copy bytecode instead cause the parser to create new bytecode // by resetting the parse function. ReInit(); m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants m_VarDef = a_Parser.m_VarDef; // Copy user defined variables m_bBuiltInOp = a_Parser.m_bBuiltInOp; m_vStringBuf = a_Parser.m_vStringBuf; m_vStackBuffer = a_Parser.m_vStackBuffer; m_nFinalResultIdx = a_Parser.m_nFinalResultIdx; m_StrVarDef = a_Parser.m_StrVarDef; m_vStringVarBuf = a_Parser.m_vStringVarBuf; m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this)); // Copy function and operator callbacks m_FunDef = a_Parser.m_FunDef; // Copy function definitions m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation m_OprtDef = a_Parser.m_OprtDef; // binary operators m_sNameChars = a_Parser.m_sNameChars; m_sOprtChars = a_Parser.m_sOprtChars; m_sInfixOprtChars = a_Parser.m_sInfixOprtChars; } //--------------------------------------------------------------------------- /** \brief Set the decimal separator. \param cDecSep Decimal separator as a character value. \sa SetThousandsSep By default muparser uses the "C" locale. The decimal separator of this locale is overwritten by the one provided here. */ void ParserBase::SetDecSep(char_type cDecSep) { char_type cThousandsSep = std::use_facet< change_dec_sep >(s_locale).thousands_sep(); s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); } //--------------------------------------------------------------------------- /** \brief Sets the thousands operator. \param cThousandsSep The thousands separator as a character \sa SetDecSep By default muparser uses the "C" locale. The thousands separator of this locale is overwritten by the one provided here. */ void ParserBase::SetThousandsSep(char_type cThousandsSep) { char_type cDecSep = std::use_facet< change_dec_sep >(s_locale).decimal_point(); s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); } //--------------------------------------------------------------------------- /** \brief Resets the locale. The default locale used "." as decimal separator, no thousands separator and "," as function argument separator. */ void ParserBase::ResetLocale() { s_locale = std::locale(std::locale("C"), new change_dec_sep('.')); SetArgSep(','); } //--------------------------------------------------------------------------- /** \brief Initialize the token reader. Create new token reader object and submit pointers to function, operator, constant and variable definitions. \post m_pTokenReader.get()!=0 \throw nothrow */ void ParserBase::InitTokenReader() { m_pTokenReader.reset(new token_reader_type(this)); } //--------------------------------------------------------------------------- /** \brief Reset parser to string parsing mode and clear internal buffers. Clear bytecode, reset the token reader. \throw nothrow */ void ParserBase::ReInit() const { m_pParseFormula = &ParserBase::ParseString; m_vStringBuf.clear(); m_vRPN.clear(); m_pTokenReader->ReInit(); } //--------------------------------------------------------------------------- void ParserBase::OnDetectVar(string_type* /*pExpr*/, int& /*nStart*/, int& /*nEnd*/) {} //--------------------------------------------------------------------------- /** \brief Returns the bytecode of the current expression. */ const ParserByteCode& ParserBase::GetByteCode() const { return m_vRPN; } //--------------------------------------------------------------------------- /** \brief Returns the version of muparser. \param eInfo A flag indicating whether the full version info should be returned or not. Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS are returned only if eInfo==pviFULL. */ string_type ParserBase::GetVersion(EParserVersionInfo eInfo) const { stringstream_type ss; ss << ParserVersion; if (eInfo == pviFULL) { ss << _T(" (") << ParserVersionDate; ss << std::dec << _T("; ") << sizeof(void*) * 8 << _T("BIT"); #ifdef _DEBUG ss << _T("; DEBUG"); #else ss << _T("; RELEASE"); #endif #ifdef _UNICODE ss << _T("; UNICODE"); #else #ifdef _MBCS ss << _T("; MBCS"); #else ss << _T("; ASCII"); #endif #endif #ifdef MUP_USE_OPENMP ss << _T("; OPENMP"); #endif ss << _T(")"); } return ss.str(); } //--------------------------------------------------------------------------- /** \brief Add a value parsing function. When parsing an expression muParser tries to detect values in the expression string using different valident callbacks. Thus it's possible to parse for hex values, binary values and floating point values. */ void ParserBase::AddValIdent(identfun_type a_pCallback) { m_pTokenReader->AddValIdent(a_pCallback); } //--------------------------------------------------------------------------- /** \brief Set a function that can create variable pointer for unknown expression variables. \param a_pFactory A pointer to the variable factory. \param pUserData A user defined context pointer. */ void ParserBase::SetVarFactory(facfun_type a_pFactory, void* pUserData) { m_pTokenReader->SetVarCreator(a_pFactory, pUserData); } //--------------------------------------------------------------------------- /** \brief Add a function or operator callback to the parser. */ void ParserBase::AddCallback( const string_type& a_strName, const ParserCallback& a_Callback, funmap_type& a_Storage, const char_type* a_szCharSet) { if (!a_Callback.IsValid()) Error(ecINVALID_FUN_PTR); const funmap_type* pFunMap = &a_Storage; // Check for conflicting operator or function names if (pFunMap != &m_FunDef && m_FunDef.find(a_strName) != m_FunDef.end()) Error(ecNAME_CONFLICT, -1, a_strName); if (pFunMap != &m_PostOprtDef && m_PostOprtDef.find(a_strName) != m_PostOprtDef.end()) Error(ecNAME_CONFLICT, -1, a_strName); if (pFunMap != &m_InfixOprtDef && pFunMap != &m_OprtDef && m_InfixOprtDef.find(a_strName) != m_InfixOprtDef.end()) Error(ecNAME_CONFLICT, -1, a_strName); if (pFunMap != &m_InfixOprtDef && pFunMap != &m_OprtDef && m_OprtDef.find(a_strName) != m_OprtDef.end()) Error(ecNAME_CONFLICT, -1, a_strName); CheckOprt(a_strName, a_Callback, a_szCharSet); a_Storage[a_strName] = a_Callback; ReInit(); } //--------------------------------------------------------------------------- /** \brief Check if a name contains invalid characters. \throw ParserException if the name contains invalid characters. */ void ParserBase::CheckOprt(const string_type& a_sName, const ParserCallback& a_Callback, const string_type& a_szCharSet) const { if (!a_sName.length() || (a_sName.find_first_not_of(a_szCharSet) != string_type::npos) || (a_sName[0] >= '0' && a_sName[0] <= '9')) { switch (a_Callback.GetCode()) { case cmOPRT_POSTFIX: Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); break; case cmOPRT_INFIX: Error(ecINVALID_INFIX_IDENT, -1, a_sName); break; default: Error(ecINVALID_NAME, -1, a_sName); } } } /** \brief Check if a name contains invalid characters. \throw ParserException if the name contains invalid characters. */ void ParserBase::CheckName(const string_type& a_sName, const string_type& a_szCharSet) const { if (!a_sName.length() || (a_sName.find_first_not_of(a_szCharSet) != string_type::npos) || (a_sName[0] >= '0' && a_sName[0] <= '9')) { Error(ecINVALID_NAME); } } /** \brief Set the formula. \param a_strFormula Formula as string_type \throw ParserException in case of syntax errors. Triggers first time calculation thus the creation of the bytecode and scanning of used variables. */ void ParserBase::SetExpr(const string_type& a_sExpr) { // Check locale compatibility if (m_pTokenReader->GetArgSep() == std::use_facet >(s_locale).decimal_point()) Error(ecLOCALE); // Check maximum allowed expression length. An arbitrary value small enough so i can debug expressions sent to me if (a_sExpr.length() >= MaxLenExpression) Error(ecEXPRESSION_TOO_LONG, 0, a_sExpr); m_pTokenReader->SetFormula(a_sExpr + _T(" ")); ReInit(); } //--------------------------------------------------------------------------- /** \brief Get the default symbols used for the built in operators. \sa c_DefaultOprt */ const char_type** ParserBase::GetOprtDef() const { return (const char_type**)(&c_DefaultOprt[0]); } //--------------------------------------------------------------------------- /** \brief Define the set of valid characters to be used in names of functions, variables, constants. */ void ParserBase::DefineNameChars(const char_type* a_szCharset) { m_sNameChars = a_szCharset; } //--------------------------------------------------------------------------- /** \brief Define the set of valid characters to be used in names of binary operators and postfix operators. */ void ParserBase::DefineOprtChars(const char_type* a_szCharset) { m_sOprtChars = a_szCharset; } //--------------------------------------------------------------------------- /** \brief Define the set of valid characters to be used in names of infix operators. */ void ParserBase::DefineInfixOprtChars(const char_type* a_szCharset) { m_sInfixOprtChars = a_szCharset; } //--------------------------------------------------------------------------- /** \brief Virtual function that defines the characters allowed in name identifiers. \sa #ValidOprtChars, #ValidPrefixOprtChars */ const char_type* ParserBase::ValidNameChars() const { MUP_ASSERT(m_sNameChars.size()); return m_sNameChars.c_str(); } //--------------------------------------------------------------------------- /** \brief Virtual function that defines the characters allowed in operator definitions. \sa #ValidNameChars, #ValidPrefixOprtChars */ const char_type* ParserBase::ValidOprtChars() const { MUP_ASSERT(m_sOprtChars.size()); return m_sOprtChars.c_str(); } //--------------------------------------------------------------------------- /** \brief Virtual function that defines the characters allowed in infix operator definitions. \sa #ValidNameChars, #ValidOprtChars */ const char_type* ParserBase::ValidInfixOprtChars() const { MUP_ASSERT(m_sInfixOprtChars.size()); return m_sInfixOprtChars.c_str(); } //--------------------------------------------------------------------------- /** \brief Add a user defined operator. \post Will reset the Parser to string parsing mode. */ void ParserBase::DefinePostfixOprt(const string_type& a_sName, fun_type1 a_pFun, bool a_bAllowOpt) { if (a_sName.length() > MaxLenIdentifier) Error(ecIDENTIFIER_TOO_LONG); AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), m_PostOprtDef, ValidOprtChars()); } //--------------------------------------------------------------------------- /** \brief Initialize user defined functions. Calls the virtual functions InitFun(), InitConst() and InitOprt(). */ void ParserBase::Init() { InitCharSets(); InitFun(); InitConst(); InitOprt(); } //--------------------------------------------------------------------------- /** \brief Add a user defined operator. \post Will reset the Parser to string parsing mode. \param [in] a_sName operator Identifier \param [in] a_pFun Operator callback function \param [in] a_iPrec Operator Precedence (default=prSIGN) \param [in] a_bAllowOpt True if operator is volatile (default=false) \sa EPrec */ void ParserBase::DefineInfixOprt(const string_type& a_sName, fun_type1 a_pFun, int a_iPrec, bool a_bAllowOpt) { if (a_sName.length() > MaxLenIdentifier) Error(ecIDENTIFIER_TOO_LONG); AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), m_InfixOprtDef, ValidInfixOprtChars()); } //--------------------------------------------------------------------------- /** \brief Define a binary operator. \param [in] a_sName The identifier of the operator. \param [in] a_pFun Pointer to the callback function. \param [in] a_iPrec Precedence of the operator. \param [in] a_eAssociativity The associativity of the operator. \param [in] a_bAllowOpt If this is true the operator may be optimized away. Adds a new Binary operator the the parser instance. */ void ParserBase::DefineOprt(const string_type& a_sName, fun_type2 a_pFun, unsigned a_iPrec, EOprtAssociativity a_eAssociativity, bool a_bAllowOpt) { if (a_sName.length() > MaxLenIdentifier) Error(ecIDENTIFIER_TOO_LONG); // Check for conflicts with built in operator names for (int i = 0; m_bBuiltInOp && i < cmENDIF; ++i) { if (a_sName == string_type(c_DefaultOprt[i])) { Error(ecBUILTIN_OVERLOAD, -1, a_sName); } } AddCallback(a_sName, ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, a_eAssociativity), m_OprtDef, ValidOprtChars()); } //--------------------------------------------------------------------------- /** \brief Define a new string constant. \param [in] a_strName The name of the constant. \param [in] a_strVal the value of the constant. */ void ParserBase::DefineStrConst(const string_type& a_strName, const string_type& a_strVal) { // Test if a constant with that names already exists if (m_StrVarDef.find(a_strName) != m_StrVarDef.end()) Error(ecNAME_CONFLICT); CheckName(a_strName, ValidNameChars()); m_vStringVarBuf.push_back(a_strVal); // Store variable string in internal buffer m_StrVarDef[a_strName] = m_vStringVarBuf.size() - 1; // bind buffer index to variable name ReInit(); } //--------------------------------------------------------------------------- /** \brief Add a user defined variable. \param [in] a_sName the variable name \param [in] a_pVar A pointer to the variable value. \post Will reset the Parser to string parsing mode. \throw ParserException in case the name contains invalid signs or a_pVar is nullptr. */ void ParserBase::DefineVar(const string_type& a_sName, value_type* a_pVar) { if (a_pVar == 0) Error(ecINVALID_VAR_PTR); if (a_sName.length() > MaxLenIdentifier) Error(ecIDENTIFIER_TOO_LONG); // Test if a constant with that names already exists if (m_ConstDef.find(a_sName) != m_ConstDef.end()) Error(ecNAME_CONFLICT); CheckName(a_sName, ValidNameChars()); m_VarDef[a_sName] = a_pVar; ReInit(); } //--------------------------------------------------------------------------- /** \brief Add a user defined constant. \param [in] a_sName The name of the constant. \param [in] a_fVal the value of the constant. \post Will reset the Parser to string parsing mode. \throw ParserException in case the name contains invalid signs. */ void ParserBase::DefineConst(const string_type& a_sName, value_type a_fVal) { if (a_sName.length() > MaxLenIdentifier) Error(ecIDENTIFIER_TOO_LONG); CheckName(a_sName, ValidNameChars()); m_ConstDef[a_sName] = a_fVal; ReInit(); } //--------------------------------------------------------------------------- /** \brief Get operator priority. \throw ParserException if a_Oprt is no operator code */ int ParserBase::GetOprtPrecedence(const token_type& a_Tok) const { switch (a_Tok.GetCode()) { // built in operators case cmEND: return -5; case cmARG_SEP: return -4; case cmASSIGN: return -1; case cmELSE: case cmIF: return 0; case cmLAND: return prLAND; case cmLOR: return prLOR; case cmLT: case cmGT: case cmLE: case cmGE: case cmNEQ: case cmEQ: return prCMP; case cmADD: case cmSUB: return prADD_SUB; case cmMUL: case cmDIV: return prMUL_DIV; case cmPOW: return prPOW; // user defined binary operators case cmOPRT_INFIX: case cmOPRT_BIN: return a_Tok.GetPri(); default: throw exception_type(ecINTERNAL_ERROR, 5, _T("")); } } //--------------------------------------------------------------------------- /** \brief Get operator priority. \throw ParserException if a_Oprt is no operator code */ EOprtAssociativity ParserBase::GetOprtAssociativity(const token_type& a_Tok) const { switch (a_Tok.GetCode()) { case cmASSIGN: case cmLAND: case cmLOR: case cmLT: case cmGT: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmADD: case cmSUB: case cmMUL: case cmDIV: return oaLEFT; case cmPOW: return oaRIGHT; case cmOPRT_BIN: return a_Tok.GetAssociativity(); default: return oaNONE; } } //--------------------------------------------------------------------------- /** \brief Return a map containing the used variables only. */ const varmap_type& ParserBase::GetUsedVar() const { try { m_pTokenReader->IgnoreUndefVar(true); CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it // may contain references to nonexisting variables. m_pParseFormula = &ParserBase::ParseString; m_pTokenReader->IgnoreUndefVar(false); } catch (exception_type& /*e*/) { // Make sure to stay in string parse mode, don't call ReInit() // because it deletes the array with the used variables m_pParseFormula = &ParserBase::ParseString; m_pTokenReader->IgnoreUndefVar(false); throw; } return m_pTokenReader->GetUsedVar(); } //--------------------------------------------------------------------------- /** \brief Return a map containing the used variables only. */ const varmap_type& ParserBase::GetVar() const { return m_VarDef; } //--------------------------------------------------------------------------- /** \brief Return a map containing all parser constants. */ const valmap_type& ParserBase::GetConst() const { return m_ConstDef; } //--------------------------------------------------------------------------- /** \brief Return prototypes of all parser functions. \return #m_FunDef \sa FunProt \throw nothrow The return type is a map of the public type #funmap_type containing the prototype definitions for all numerical parser functions. String functions are not part of this map. The Prototype definition is encapsulated in objects of the class FunProt one per parser function each associated with function names via a map construct. */ const funmap_type& ParserBase::GetFunDef() const { return m_FunDef; } //--------------------------------------------------------------------------- /** \brief Retrieve the formula. */ const string_type& ParserBase::GetExpr() const { return m_pTokenReader->GetExpr(); } //--------------------------------------------------------------------------- /** \brief Execute a function that takes a single string argument. \param a_FunTok Function token. \throw exception_type If the function token is not a string function */ ParserBase::token_type ParserBase::ApplyStrFunc( const token_type& a_FunTok, const std::vector& a_vArg) const { if (a_vArg.back().GetCode() != cmSTRING) Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); token_type valTok; generic_callable_type pFunc = a_FunTok.GetFuncAddr(); MUP_ASSERT(pFunc); try { // Check function arguments; write dummy value into valtok to represent the result switch (a_FunTok.GetArgCount()) { case 0: valTok.SetVal(1); a_vArg[0].GetAsString(); break; case 1: valTok.SetVal(1); a_vArg[1].GetAsString(); a_vArg[0].GetVal(); break; case 2: valTok.SetVal(1); a_vArg[2].GetAsString(); a_vArg[1].GetVal(); a_vArg[0].GetVal(); break; case 3: valTok.SetVal(1); a_vArg[3].GetAsString(); a_vArg[2].GetVal(); a_vArg[1].GetVal(); a_vArg[0].GetVal(); break; case 4: valTok.SetVal(1); a_vArg[4].GetAsString(); a_vArg[3].GetVal(); a_vArg[2].GetVal(); a_vArg[1].GetVal(); a_vArg[0].GetVal(); break; case 5: valTok.SetVal(1); a_vArg[5].GetAsString(); a_vArg[4].GetVal(); a_vArg[3].GetVal(); a_vArg[2].GetVal(); a_vArg[1].GetVal(); a_vArg[0].GetVal(); break; default: Error(ecINTERNAL_ERROR); } } catch (ParserError&) { Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); } // string functions won't be optimized m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx()); // Push dummy value representing the function result to the stack return valTok; } //--------------------------------------------------------------------------- /** \brief Apply a function token. \param iArgCount Number of Arguments actually gathered used only for multiarg functions. \post The result is pushed to the value stack \post The function token is removed from the stack \throw exception_type if Argument count does not match function requirements. */ void ParserBase::ApplyFunc(std::stack& a_stOpt, std::stack& a_stVal, int a_iArgCount) const { MUP_ASSERT(m_pTokenReader.get()); // Operator stack empty or does not contain tokens with callback functions if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr() == 0) return; token_type funTok = a_stOpt.top(); a_stOpt.pop(); MUP_ASSERT(funTok.GetFuncAddr() != nullptr); // Binary operators must rely on their internal operator number // since counting of operators relies on commas for function arguments // binary operators do not have commas in their expression int iArgCount = (funTok.GetCode() == cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount; // determine how many parameters the function needs. To remember iArgCount includes the // string parameter whilst GetArgCount() counts only numeric parameters. int iArgRequired = funTok.GetArgCount() + ((funTok.GetType() == tpSTR) ? 1 : 0); // That's the number of numerical parameters int iArgNumerical = iArgCount - ((funTok.GetType() == tpSTR) ? 1 : 0); if (funTok.GetCode() == cmFUNC_STR && iArgCount - iArgNumerical > 1) Error(ecINTERNAL_ERROR); if (funTok.GetArgCount() >= 0 && iArgCount > iArgRequired) Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString()); if (funTok.GetCode() != cmOPRT_BIN && iArgCount < iArgRequired) Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString()); if (funTok.GetCode() == cmFUNC_STR && iArgCount > iArgRequired) Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos() - 1, funTok.GetAsString()); // Collect the numeric function arguments from the value stack and store them // in a vector std::vector stArg; for (int i = 0; i < iArgNumerical; ++i) { if (a_stVal.empty()) Error(ecINTERNAL_ERROR, m_pTokenReader->GetPos(), funTok.GetAsString()); stArg.push_back(a_stVal.top()); a_stVal.pop(); if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR) Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); } switch (funTok.GetCode()) { case cmFUNC_STR: if (a_stVal.empty()) Error(ecINTERNAL_ERROR, m_pTokenReader->GetPos(), funTok.GetAsString()); stArg.push_back(a_stVal.top()); a_stVal.pop(); if (stArg.back().GetType() == tpSTR && funTok.GetType() != tpSTR) Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); ApplyStrFunc(funTok, stArg); break; case cmFUNC_BULK: m_vRPN.AddBulkFun(funTok.GetFuncAddr(), (int)stArg.size()); break; case cmOPRT_BIN: case cmOPRT_POSTFIX: case cmOPRT_INFIX: case cmFUNC: if (funTok.GetArgCount() == -1 && iArgCount == 0) Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString()); m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount() == -1) ? -iArgNumerical : iArgNumerical, funTok.IsOptimizable()); break; default: break; } // Push dummy value representing the function result to the stack token_type token; token.SetVal(1); a_stVal.push(token); } //--------------------------------------------------------------------------- void ParserBase::ApplyIfElse(std::stack& a_stOpt, std::stack& a_stVal) const { // Check if there is an if Else clause to be calculated while (a_stOpt.size() && a_stOpt.top().GetCode() == cmELSE) { MUP_ASSERT(!a_stOpt.empty()) token_type opElse = a_stOpt.top(); a_stOpt.pop(); // Take the value associated with the else branch from the value stack MUP_ASSERT(!a_stVal.empty()); token_type vVal2 = a_stVal.top(); if (vVal2.GetType() != tpDBL) Error(ecUNEXPECTED_STR, m_pTokenReader->GetPos()); a_stVal.pop(); // it then else is a ternary operator Pop all three values from the value s // tack and just return the right value MUP_ASSERT(!a_stVal.empty()); token_type vVal1 = a_stVal.top(); if (vVal1.GetType() != tpDBL) Error(ecUNEXPECTED_STR, m_pTokenReader->GetPos()); a_stVal.pop(); MUP_ASSERT(!a_stVal.empty()); token_type vExpr = a_stVal.top(); a_stVal.pop(); a_stVal.push((vExpr.GetVal() != 0) ? vVal1 : vVal2); token_type opIf = a_stOpt.top(); a_stOpt.pop(); MUP_ASSERT(opElse.GetCode() == cmELSE); if (opIf.GetCode() != cmIF) Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); m_vRPN.AddIfElse(cmENDIF); } // while pending if-else-clause found } //--------------------------------------------------------------------------- /** \brief Performs the necessary steps to write code for the execution of binary operators into the bytecode. */ void ParserBase::ApplyBinOprt(std::stack& a_stOpt, std::stack& a_stVal) const { // is it a user defined binary operator? if (a_stOpt.top().GetCode() == cmOPRT_BIN) { ApplyFunc(a_stOpt, a_stVal, 2); } else { if (a_stVal.size() < 2) Error(ecINTERNAL_ERROR, m_pTokenReader->GetPos(), _T("ApplyBinOprt: not enough values in value stack!")); token_type valTok1 = a_stVal.top(); a_stVal.pop(); token_type valTok2 = a_stVal.top(); a_stVal.pop(); token_type optTok = a_stOpt.top(); a_stOpt.pop(); token_type resTok; if (valTok1.GetType() != valTok2.GetType() || (valTok1.GetType() == tpSTR && valTok2.GetType() == tpSTR)) Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString()); if (optTok.GetCode() == cmASSIGN) { if (valTok2.GetCode() != cmVAR) Error(ecUNEXPECTED_OPERATOR, -1, _T("=")); m_vRPN.AddAssignOp(valTok2.GetVar()); } else m_vRPN.AddOp(optTok.GetCode()); resTok.SetVal(1); a_stVal.push(resTok); } } //--------------------------------------------------------------------------- /** \brief Apply a binary operator. \param a_stOpt The operator stack \param a_stVal The value stack */ void ParserBase::ApplyRemainingOprt(std::stack& stOpt, std::stack& stVal) const { while (stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmIF) { token_type tok = stOpt.top(); switch (tok.GetCode()) { case cmOPRT_INFIX: case cmOPRT_BIN: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmLT: case cmGT: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: case cmLAND: case cmLOR: case cmASSIGN: if (stOpt.top().GetCode() == cmOPRT_INFIX) ApplyFunc(stOpt, stVal, 1); else ApplyBinOprt(stOpt, stVal); break; case cmELSE: ApplyIfElse(stOpt, stVal); break; default: Error(ecINTERNAL_ERROR); } } } //--------------------------------------------------------------------------- /** \brief Parse the command code. \sa ParseString(...) Command code contains precalculated stack positions of the values and the associated operators. The Stack is filled beginning from index one the value at index zero is not used at all. */ value_type ParserBase::ParseCmdCode() const { return ParseCmdCodeBulk(0, 0); } value_type ParserBase::ParseCmdCodeShort() const { const SToken *const tok = m_vRPN.GetBase(); value_type buf; switch (tok->Cmd) { case cmVAL: return tok->Val.data2; case cmVAR: return *tok->Val.ptr; case cmVARMUL: return *tok->Val.ptr * tok->Val.data + tok->Val.data2; case cmVARPOW2: buf = *(tok->Val.ptr); return buf * buf; case cmVARPOW3: buf = *(tok->Val.ptr); return buf * buf * buf; case cmVARPOW4: buf = *(tok->Val.ptr); return buf * buf * buf * buf; // numerical function without any argument case cmFUNC: return tok->Fun.cb.call_fun<0>(); // String function without a numerical argument case cmFUNC_STR: return tok->Fun.cb.call_strfun<1>(m_vStringBuf[0].c_str()); default: throw ParserError(ecINTERNAL_ERROR); } } //--------------------------------------------------------------------------- /** \brief Evaluate the RPN. \param nOffset The offset added to variable addresses (for bulk mode) \param nThreadID OpenMP Thread id of the calling thread */ value_type ParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const { assert(nThreadID <= s_MaxNumOpenMPThreads); // Note: The check for nOffset==0 and nThreadID here is not necessary but // brings a minor performance gain when not in bulk mode. value_type *stack = ((nOffset == 0) && (nThreadID == 0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID * (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)]; value_type buf; int sidx(0); for (const SToken* pTok = m_vRPN.GetBase(); pTok->Cmd != cmEND; ++pTok) { switch (pTok->Cmd) { // built in binary operators case cmLE: --sidx; stack[sidx] = stack[sidx] <= stack[sidx + 1]; continue; case cmGE: --sidx; stack[sidx] = stack[sidx] >= stack[sidx + 1]; continue; case cmNEQ: --sidx; stack[sidx] = stack[sidx] != stack[sidx + 1]; continue; case cmEQ: --sidx; stack[sidx] = stack[sidx] == stack[sidx + 1]; continue; case cmLT: --sidx; stack[sidx] = stack[sidx] < stack[sidx + 1]; continue; case cmGT: --sidx; stack[sidx] = stack[sidx] > stack[sidx + 1]; continue; case cmADD: --sidx; stack[sidx] += stack[1 + sidx]; continue; case cmSUB: --sidx; stack[sidx] -= stack[1 + sidx]; continue; case cmMUL: --sidx; stack[sidx] *= stack[1 + sidx]; continue; case cmDIV: --sidx; stack[sidx] /= stack[1 + sidx]; continue; case cmPOW: --sidx; stack[sidx] = MathImpl::Pow(stack[sidx], stack[1 + sidx]); continue; case cmLAND: --sidx; stack[sidx] = stack[sidx] && stack[sidx + 1]; continue; case cmLOR: --sidx; stack[sidx] = stack[sidx] || stack[sidx + 1]; continue; case cmASSIGN: // Bugfix for Bulkmode: // for details see: // https://groups.google.com/forum/embed/?place=forum/muparser-dev&showsearch=true&showpopout=true&showtabs=false&parenturl=http://muparser.beltoforion.de/mup_forum.html&afterlogin&pli=1#!topic/muparser-dev/szgatgoHTws --sidx; stack[sidx] = *(pTok->Oprt.ptr + nOffset) = stack[sidx + 1]; continue; // original code: //--sidx; Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; continue; case cmIF: if (stack[sidx--] == 0) { MUP_ASSERT(sidx >= 0); pTok += pTok->Oprt.offset; } continue; case cmELSE: pTok += pTok->Oprt.offset; continue; case cmENDIF: continue; // value and variable tokens case cmVAR: stack[++sidx] = *(pTok->Val.ptr + nOffset); continue; case cmVAL: stack[++sidx] = pTok->Val.data2; continue; case cmVARPOW2: buf = *(pTok->Val.ptr + nOffset); stack[++sidx] = buf * buf; continue; case cmVARPOW3: buf = *(pTok->Val.ptr + nOffset); stack[++sidx] = buf * buf * buf; continue; case cmVARPOW4: buf = *(pTok->Val.ptr + nOffset); stack[++sidx] = buf * buf * buf * buf; continue; case cmVARMUL: stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2; continue; // Next is treatment of numeric functions case cmFUNC: { int iArgCount = pTok->Fun.argc; // switch according to argument count switch (iArgCount) { case 0: sidx += 1; stack[sidx] = pTok->Fun.cb.call_fun<0 >(); continue; case 1: stack[sidx] = pTok->Fun.cb.call_fun<1 >(stack[sidx]); continue; case 2: sidx -= 1; stack[sidx] = pTok->Fun.cb.call_fun<2 >(stack[sidx], stack[sidx + 1]); continue; case 3: sidx -= 2; stack[sidx] = pTok->Fun.cb.call_fun<3 >(stack[sidx], stack[sidx + 1], stack[sidx + 2]); continue; case 4: sidx -= 3; stack[sidx] = pTok->Fun.cb.call_fun<4 >(stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3]); continue; case 5: sidx -= 4; stack[sidx] = pTok->Fun.cb.call_fun<5 >(stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4]); continue; case 6: sidx -= 5; stack[sidx] = pTok->Fun.cb.call_fun<6 >(stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5]); continue; case 7: sidx -= 6; stack[sidx] = pTok->Fun.cb.call_fun<7 >(stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5], stack[sidx + 6]); continue; case 8: sidx -= 7; stack[sidx] = pTok->Fun.cb.call_fun<8 >(stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5], stack[sidx + 6], stack[sidx + 7]); continue; case 9: sidx -= 8; stack[sidx] = pTok->Fun.cb.call_fun<9 >(stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5], stack[sidx + 6], stack[sidx + 7], stack[sidx + 8]); continue; case 10:sidx -= 9; stack[sidx] = pTok->Fun.cb.call_fun<10>(stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5], stack[sidx + 6], stack[sidx + 7], stack[sidx + 8], stack[sidx + 9]); continue; default: // function with variable arguments store the number as a negative value if (iArgCount > 0) Error(ecINTERNAL_ERROR, -1); sidx -= -iArgCount - 1; // From oss-fuzz. Happend when Multiarg functions and if-then-else are used incorrectly. // Expressions where this was observed: // sum(0?1,2,3,4,5:6) -> fixed // avg(0>3?4:(""),0^3?4:("")) // // The final result normally lieas at position 1. If sixd is smaller there is something wrong. if (sidx <= 0) Error(ecINTERNAL_ERROR, -1); // stack[sidx] = pTok->Fun.cb.call_multfun(&stack[sidx], -iArgCount); continue; } } // Next is treatment of string functions case cmFUNC_STR: { sidx -= pTok->Fun.argc - 1; // The index of the string argument in the string table int iIdxStack = pTok->Fun.idx; if (iIdxStack < 0 || iIdxStack >= (int)m_vStringBuf.size()) Error(ecINTERNAL_ERROR, m_pTokenReader->GetPos()); switch (pTok->Fun.argc) // switch according to argument count { case 0: stack[sidx] = pTok->Fun.cb.call_strfun<1>(m_vStringBuf[iIdxStack].c_str()); continue; case 1: stack[sidx] = pTok->Fun.cb.call_strfun<2>(m_vStringBuf[iIdxStack].c_str(), stack[sidx]); continue; case 2: stack[sidx] = pTok->Fun.cb.call_strfun<3>(m_vStringBuf[iIdxStack].c_str(), stack[sidx], stack[sidx + 1]); continue; case 3: stack[sidx] = pTok->Fun.cb.call_strfun<4>(m_vStringBuf[iIdxStack].c_str(), stack[sidx], stack[sidx + 1], stack[sidx + 2]); continue; case 4: stack[sidx] = pTok->Fun.cb.call_strfun<5>(m_vStringBuf[iIdxStack].c_str(), stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3]); continue; case 5: stack[sidx] = pTok->Fun.cb.call_strfun<6>(m_vStringBuf[iIdxStack].c_str(), stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4]); continue; } continue; } case cmFUNC_BULK: { int iArgCount = pTok->Fun.argc; // switch according to argument count switch (iArgCount) { case 0: sidx += 1; stack[sidx] = pTok->Fun.cb.call_bulkfun<0 >(nOffset, nThreadID); continue; case 1: stack[sidx] = pTok->Fun.cb.call_bulkfun<1 >(nOffset, nThreadID, stack[sidx]); continue; case 2: sidx -= 1; stack[sidx] = pTok->Fun.cb.call_bulkfun<2 >(nOffset, nThreadID, stack[sidx], stack[sidx + 1]); continue; case 3: sidx -= 2; stack[sidx] = pTok->Fun.cb.call_bulkfun<3 >(nOffset, nThreadID, stack[sidx], stack[sidx + 1], stack[sidx + 2]); continue; case 4: sidx -= 3; stack[sidx] = pTok->Fun.cb.call_bulkfun<4 >(nOffset, nThreadID, stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3]); continue; case 5: sidx -= 4; stack[sidx] = pTok->Fun.cb.call_bulkfun<5 >(nOffset, nThreadID, stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4]); continue; case 6: sidx -= 5; stack[sidx] = pTok->Fun.cb.call_bulkfun<6 >(nOffset, nThreadID, stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5]); continue; case 7: sidx -= 6; stack[sidx] = pTok->Fun.cb.call_bulkfun<7 >(nOffset, nThreadID, stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5], stack[sidx + 6]); continue; case 8: sidx -= 7; stack[sidx] = pTok->Fun.cb.call_bulkfun<8 >(nOffset, nThreadID, stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5], stack[sidx + 6], stack[sidx + 7]); continue; case 9: sidx -= 8; stack[sidx] = pTok->Fun.cb.call_bulkfun<9 >(nOffset, nThreadID, stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5], stack[sidx + 6], stack[sidx + 7], stack[sidx + 8]); continue; case 10:sidx -= 9; stack[sidx] = pTok->Fun.cb.call_bulkfun<10>(nOffset, nThreadID, stack[sidx], stack[sidx + 1], stack[sidx + 2], stack[sidx + 3], stack[sidx + 4], stack[sidx + 5], stack[sidx + 6], stack[sidx + 7], stack[sidx + 8], stack[sidx + 9]); continue; default: throw exception_type(ecINTERNAL_ERROR, 2, _T("")); } } default: throw exception_type(ecINTERNAL_ERROR, 3, _T("")); } // switch CmdCode } // for all bytecode tokens return stack[m_nFinalResultIdx]; } //--------------------------------------------------------------------------- void ParserBase::CreateRPN() const { if (!m_pTokenReader->GetExpr().length()) Error(ecUNEXPECTED_EOF, 0); std::stack stOpt, stVal; std::stack stArgCount; token_type opta, opt; // for storing operators token_type val, tval; // for storing value int ifElseCounter = 0; ReInit(); // The outermost counter counts the number of separated items // such as in "a=10,b=20,c=c+a" stArgCount.push(1); for (;;) { opt = m_pTokenReader->ReadNextToken(); switch (opt.GetCode()) { // // Next three are different kind of value entries // case cmSTRING: if (stOpt.empty()) Error(ecSTR_RESULT, m_pTokenReader->GetPos(), opt.GetAsString()); opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token stVal.push(opt); m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer break; case cmVAR: stVal.push(opt); m_vRPN.AddVar(static_cast(opt.GetVar())); break; case cmVAL: stVal.push(opt); m_vRPN.AddVal(opt.GetVal()); break; case cmELSE: if (stArgCount.empty()) Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); if (stArgCount.top() > 1) Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); stArgCount.pop(); ifElseCounter--; if (ifElseCounter < 0) Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); ApplyRemainingOprt(stOpt, stVal); m_vRPN.AddIfElse(cmELSE); stOpt.push(opt); break; case cmARG_SEP: if (!stOpt.empty() && stOpt.top().GetCode() == cmIF) Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); if (stArgCount.empty()) Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); ++stArgCount.top(); // Falls through. // intentional (no break!) case cmEND: ApplyRemainingOprt(stOpt, stVal); break; case cmBC: { // The argument count for parameterless functions is zero // by default an opening bracket sets parameter count to 1 // in preparation of arguments to come. If the last token // was an opening bracket we know better... if (opta.GetCode() == cmBO) --stArgCount.top(); ApplyRemainingOprt(stOpt, stVal); // Check if the bracket content has been evaluated completely if (stOpt.size() && stOpt.top().GetCode() == cmBO) { // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check // if there is either a function or a sign pending // neither the opening nor the closing bracket will be pushed back to // the operator stack // Check if a function is standing in front of the opening bracket, // if yes evaluate it afterwards check for infix operators MUP_ASSERT(stArgCount.size()); int iArgCount = stArgCount.top(); stArgCount.pop(); stOpt.pop(); // Take opening bracket from stack if (iArgCount > 1 && (stOpt.size() == 0 || (stOpt.top().GetCode() != cmFUNC && stOpt.top().GetCode() != cmFUNC_BULK && stOpt.top().GetCode() != cmFUNC_STR))) Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos()); // The opening bracket was popped from the stack now check if there // was a function before this bracket if (stOpt.size() && stOpt.top().GetCode() != cmOPRT_INFIX && stOpt.top().GetCode() != cmOPRT_BIN && stOpt.top().GetFuncAddr() != 0) { ApplyFunc(stOpt, stVal, iArgCount); } } } // if bracket content is evaluated break; // // Next are the binary operator entries // case cmIF: ifElseCounter++; stArgCount.push(1); // Falls through. // intentional (no break!) case cmLAND: case cmLOR: case cmLT: case cmGT: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: case cmASSIGN: case cmOPRT_BIN: // A binary operator (user defined or built in) has been found. while ( stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmELSE && stOpt.top().GetCode() != cmIF) { int nPrec1 = GetOprtPrecedence(stOpt.top()), nPrec2 = GetOprtPrecedence(opt); if (stOpt.top().GetCode() == opt.GetCode()) { // Deal with operator associativity EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt); if ((eOprtAsct == oaRIGHT && (nPrec1 <= nPrec2)) || (eOprtAsct == oaLEFT && (nPrec1 < nPrec2))) { break; } } else if (nPrec1 < nPrec2) { // In case the operators are not equal the precedence decides alone... break; } if (stOpt.top().GetCode() == cmOPRT_INFIX) ApplyFunc(stOpt, stVal, 1); else ApplyBinOprt(stOpt, stVal); } // while ( ... ) if (opt.GetCode() == cmIF) m_vRPN.AddIfElse(opt.GetCode()); // The operator can't be evaluated right now, push back to the operator stack stOpt.push(opt); break; // // Last section contains functions and operators implicitly mapped to functions // case cmBO: stArgCount.push(1); stOpt.push(opt); break; case cmOPRT_INFIX: case cmFUNC: case cmFUNC_BULK: case cmFUNC_STR: stOpt.push(opt); break; case cmOPRT_POSTFIX: stOpt.push(opt); ApplyFunc(stOpt, stVal, 1); // this is the postfix operator break; default: Error(ecINTERNAL_ERROR, 3); } // end of switch operator-token opta = opt; if (opt.GetCode() == cmEND) { m_vRPN.Finalize(); break; } if (ParserBase::g_DbgDumpStack) { StackDump(stVal, stOpt); m_vRPN.AsciiDump(); } // if (ParserBase::g_DbgDumpCmdCode) //m_vRPN.AsciiDump(); } // while (true) if (ParserBase::g_DbgDumpCmdCode) m_vRPN.AsciiDump(); if (ifElseCounter > 0) Error(ecMISSING_ELSE_CLAUSE); // get the last value (= final result) from the stack MUP_ASSERT(stArgCount.size() == 1); m_nFinalResultIdx = stArgCount.top(); if (m_nFinalResultIdx == 0) Error(ecINTERNAL_ERROR, 9); if (stVal.size() == 0) Error(ecEMPTY_EXPRESSION); // 2020-09-17; fix for https://oss-fuzz.com/testcase-detail/5758791700971520 // I don't need the value stack any more. Destructively check if all values in the value // stack represent floating point values while (stVal.size()) { if (stVal.top().GetType() != tpDBL) Error(ecSTR_RESULT); stVal.pop(); } m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads); } //--------------------------------------------------------------------------- /** \brief One of the two main parse functions. \sa ParseCmdCode(...) Parse expression from input string. Perform syntax checking and create bytecode. After parsing the string and creating the bytecode the function pointer #m_pParseFormula will be changed to the second parse routine the uses bytecode instead of string parsing. */ value_type ParserBase::ParseString() const { try { CreateRPN(); if (m_vRPN.GetSize() == 2) { m_pParseFormula = &ParserBase::ParseCmdCodeShort; m_vStackBuffer[1] = (this->*m_pParseFormula)(); return m_vStackBuffer[1]; } else { m_pParseFormula = &ParserBase::ParseCmdCode; return (this->*m_pParseFormula)(); } } catch (ParserError& exc) { exc.SetFormula(m_pTokenReader->GetExpr()); throw; } } //--------------------------------------------------------------------------- /** \brief Create an error containing the parse error position. This function will create an Parser Exception object containing the error text and its position. \param a_iErrc [in] The error code of type #EErrorCodes. \param a_iPos [in] The position where the error was detected. \param a_strTok [in] The token string representation associated with the error. \throw ParserException always throws that's the only purpose of this function. */ void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type& a_sTok) const { throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos); } //------------------------------------------------------------------------------ /** \brief Clear all user defined variables. \throw nothrow Resets the parser to string parsing mode by calling #ReInit. */ void ParserBase::ClearVar() { m_VarDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Remove a variable from internal storage. \throw nothrow Removes a variable if it exists. If the Variable does not exist nothing will be done. */ void ParserBase::RemoveVar(const string_type& a_strVarName) { varmap_type::iterator item = m_VarDef.find(a_strVarName); if (item != m_VarDef.end()) { m_VarDef.erase(item); ReInit(); } } //------------------------------------------------------------------------------ /** \brief Clear all functions. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearFun() { m_FunDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear all user defined constants. Both numeric and string constants will be removed from the internal storage. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearConst() { m_ConstDef.clear(); m_StrVarDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear all user defined postfix operators. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearPostfixOprt() { m_PostOprtDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear all user defined binary operators. \post Resets the parser to string parsing mode. \throw nothrow */ void ParserBase::ClearOprt() { m_OprtDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Clear the user defined Prefix operators. \post Resets the parser to string parser mode. \throw nothrow */ void ParserBase::ClearInfixOprt() { m_InfixOprtDef.clear(); ReInit(); } //------------------------------------------------------------------------------ /** \brief Enable or disable the formula optimization feature. \post Resets the parser to string parser mode. \throw nothrow */ void ParserBase::EnableOptimizer(bool a_bIsOn) { m_vRPN.EnableOptimizer(a_bIsOn); ReInit(); } //--------------------------------------------------------------------------- /** \brief Enable the dumping of bytecode and stack content on the console. \param bDumpCmd Flag to enable dumping of the current bytecode to the console. \param bDumpStack Flag to enable dumping of the stack content is written to the console. This function is for debug purposes only! */ void ParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack) { ParserBase::g_DbgDumpCmdCode = bDumpCmd; ParserBase::g_DbgDumpStack = bDumpStack; } //------------------------------------------------------------------------------ /** \brief Enable or disable the built in binary operators. \throw nothrow \sa m_bBuiltInOp, ReInit() If you disable the built in binary operators there will be no binary operators defined. Thus you must add them manually one by one. It is not possible to disable built in operators selectively. This function will Reinitialize the parser by calling ReInit(). */ void ParserBase::EnableBuiltInOprt(bool a_bIsOn) { m_bBuiltInOp = a_bIsOn; ReInit(); } //------------------------------------------------------------------------------ /** \brief Query status of built in variables. \return #m_bBuiltInOp; true if built in operators are enabled. \throw nothrow */ bool ParserBase::HasBuiltInOprt() const { return m_bBuiltInOp; } //------------------------------------------------------------------------------ /** \brief Get the argument separator character. */ char_type ParserBase::GetArgSep() const { return m_pTokenReader->GetArgSep(); } //------------------------------------------------------------------------------ /** \brief Set argument separator. \param cArgSep the argument separator character. */ void ParserBase::SetArgSep(char_type cArgSep) { m_pTokenReader->SetArgSep(cArgSep); } //------------------------------------------------------------------------------ /** \brief Dump stack content. This function is used for debugging only. */ void ParserBase::StackDump(const std::stack& a_stVal, const std::stack& a_stOprt) const { std::stack stOprt(a_stOprt); std::stack stVal(a_stVal); mu::console() << _T("\nValue stack:\n"); while (!stVal.empty()) { token_type val = stVal.top(); stVal.pop(); if (val.GetType() == tpSTR) mu::console() << _T(" \"") << val.GetAsString() << _T("\" "); else mu::console() << _T(" ") << val.GetVal() << _T(" "); } mu::console() << "\nOperator stack:\n"; while (!stOprt.empty()) { if (stOprt.top().GetCode() <= cmASSIGN) { mu::console() << _T("OPRT_INTRNL \"") << ParserBase::c_DefaultOprt[stOprt.top().GetCode()] << _T("\" \n"); } else { switch (stOprt.top().GetCode()) { case cmVAR: mu::console() << _T("VAR\n"); break; case cmVAL: mu::console() << _T("VAL\n"); break; case cmFUNC: mu::console() << _T("FUNC \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmFUNC_BULK: mu::console() << _T("FUNC_BULK \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmOPRT_INFIX: mu::console() << _T("OPRT_INFIX \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmOPRT_BIN: mu::console() << _T("OPRT_BIN \"") << stOprt.top().GetAsString() << _T("\"\n"); break; case cmFUNC_STR: mu::console() << _T("FUNC_STR\n"); break; case cmEND: mu::console() << _T("END\n"); break; case cmUNKNOWN: mu::console() << _T("UNKNOWN\n"); break; case cmBO: mu::console() << _T("BRACKET \"(\"\n"); break; case cmBC: mu::console() << _T("BRACKET \")\"\n"); break; case cmIF: mu::console() << _T("IF\n"); break; case cmELSE: mu::console() << _T("ELSE\n"); break; case cmENDIF: mu::console() << _T("ENDIF\n"); break; default: mu::console() << stOprt.top().GetCode() << _T(" "); break; } } stOprt.pop(); } mu::console() << dec << endl; } /** \brief Calculate the result. A note on const correctness: I consider it important that Calc is a const function. Due to caching operations Calc changes only the state of internal variables with one exception m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making Calc non const GetUsedVar is non const because it explicitly calls Eval() forcing this update. \pre A formula must be set. \pre Variables must have been set (if needed) \sa #m_pParseFormula \return The evaluation result \throw ParseException if no Formula is set or in case of any other error related to the formula. */ value_type ParserBase::Eval() const { return (this->*m_pParseFormula)(); } //------------------------------------------------------------------------------ /** \brief Evaluate an expression containing comma separated subexpressions \param [out] nStackSize The total number of results available \return Pointer to the array containing all expression results This member function can be used to retrieve all results of an expression made up of multiple comma separated subexpressions (i.e. "x+y,sin(x),cos(y)") */ value_type* ParserBase::Eval(int& nStackSize) const { if (m_vRPN.GetSize() > 0) { ParseCmdCode(); } else { ParseString(); } nStackSize = m_nFinalResultIdx; // (for historic reasons the stack starts at position 1) return &m_vStackBuffer[1]; } //--------------------------------------------------------------------------- /** \brief Return the number of results on the calculation stack. If the expression contains comma separated subexpressions (i.e. "sin(y), x+y"). There may be more than one return value. This function returns the number of available results. */ int ParserBase::GetNumResults() const { return m_nFinalResultIdx; } //--------------------------------------------------------------------------- void ParserBase::Eval(value_type* results, int nBulkSize) { CreateRPN(); int i = 0; #ifdef MUP_USE_OPENMP //#define DEBUG_OMP_STUFF #ifdef DEBUG_OMP_STUFF int* pThread = new int[nBulkSize]; int* pIdx = new int[nBulkSize]; #endif int nMaxThreads = std::min(omp_get_max_threads(), s_MaxNumOpenMPThreads); int nThreadID = 0; #ifdef DEBUG_OMP_STUFF int ct = 0; #endif omp_set_num_threads(nMaxThreads); #pragma omp parallel for schedule(static, std::max(nBulkSize/nMaxThreads, 1)) private(nThreadID) for (i = 0; i < nBulkSize; ++i) { nThreadID = omp_get_thread_num(); results[i] = ParseCmdCodeBulk(i, nThreadID); #ifdef DEBUG_OMP_STUFF #pragma omp critical { pThread[ct] = nThreadID; pIdx[ct] = i; ct++; } #endif } #ifdef DEBUG_OMP_STUFF FILE* pFile = fopen("bulk_dbg.txt", "w"); for (i = 0; i < nBulkSize; ++i) { fprintf(pFile, "idx: %d thread: %d \n", pIdx[i], pThread[i]); } delete[] pIdx; delete[] pThread; fclose(pFile); #endif #else for (i = 0; i < nBulkSize; ++i) { results[i] = ParseCmdCodeBulk(i, 0); } #endif } } // namespace mu #if defined(_MSC_VER) #pragma warning(pop) #endif beltoforion-muparser-59e0ce1/src/muParserBytecode.cpp000066400000000000000000000475501433271236700231000ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "muParserBytecode.h" #include #include #include #include #include #include "muParserDef.h" #include "muParserError.h" #include "muParserToken.h" #include "muParserTemplateMagic.h" #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 26812) #endif namespace mu { /** \brief Bytecode default constructor. */ ParserByteCode::ParserByteCode() :m_iStackPos(0) , m_iMaxStackSize(0) , m_vRPN() , m_bEnableOptimizer(true) { 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) { ++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; m_vRPN.push_back(tok); } /** \brief Add a Variable pointer to bytecode. Value entries in byte code consist of:
  • value array position of the value
  • the operator code according to ParserToken::cmVAL
  • the value stored in #mc_iSizeVal number of bytecode entries.
\param a_pVal Value to be added. \throw nothrow */ 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 = nullptr; tok.Val.data = 0; tok.Val.data2 = 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; value_type& 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: x = x / y; m_vRPN.pop_back(); break; case cmPOW: x = MathImpl::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:
  • value array position of the result
  • the operator code according to ParserToken::ECmdCode
\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 == 0) { m_vRPN[sz - 2].Cmd = cmVAL; m_vRPN[sz - 2].Val.ptr = nullptr; m_vRPN[sz - 2].Val.data = 0; m_vRPN[sz - 2].Val.data2 = 1; } else if (m_vRPN[sz - 1].Val.data2 == 1) m_vRPN[sz - 2].Cmd = cmVAR; else 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)) { MUP_ASSERT( (m_vRPN[sz - 2].Val.ptr == nullptr && m_vRPN[sz - 1].Val.ptr != nullptr) || (m_vRPN[sz - 2].Val.ptr != nullptr && m_vRPN[sz - 1].Val.ptr == nullptr) || (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; // no optimization for other opcodes default: 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) { SToken tok; tok.Cmd = a_Oprt; m_vRPN.push_back(tok); } /** \brief Add an assignment operator Operator entries in byte code consist of:
  • cmASSIGN code
  • the pointer of the destination variable
\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. \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. \param a_pFun Pointer to function callback. */ void ParserByteCode::AddFun(generic_callable_type a_pFun, int a_iArgc, bool isFunctionOptimizable) { std::size_t sz = m_vRPN.size(); bool optimize = false; // only optimize functions with fixed number of more than a single arguments if (isFunctionOptimizable && m_bEnableOptimizer && a_iArgc > 0) { // Unary Plus is a no-op if (a_pFun == generic_callable_type{(erased_fun_type)&MathImpl::UnaryPlus, nullptr}) return; optimize = true; for (int i = 0; i < std::abs(a_iArgc); ++i) { if (m_vRPN[sz - i - 1].Cmd != cmVAL) { optimize = false; break; } } } if (optimize) { value_type val = 0; switch (a_iArgc) { case 1: val = a_pFun.call_fun<1>(m_vRPN[sz - 1].Val.data2); break; case 2: val = a_pFun.call_fun<2>(m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; case 3: val = a_pFun.call_fun<3>(m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; case 4: val = a_pFun.call_fun<4>(m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; case 5: val = a_pFun.call_fun<5>(m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; case 6: val = a_pFun.call_fun<6>(m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; case 7: val = a_pFun.call_fun<7>(m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; case 8: val = a_pFun.call_fun<8>(m_vRPN[sz - 8].Val.data2, m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; case 9: val = a_pFun.call_fun<9>(m_vRPN[sz - 9].Val.data2, m_vRPN[sz - 8].Val.data2, m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; case 10: val = a_pFun.call_fun<10>(m_vRPN[sz - 10].Val.data2, m_vRPN[sz - 9].Val.data2, m_vRPN[sz - 8].Val.data2, m_vRPN[sz - 7].Val.data2, m_vRPN[sz - 6].Val.data2, m_vRPN[sz - 5].Val.data2, m_vRPN[sz - 4].Val.data2, m_vRPN[sz - 3].Val.data2, m_vRPN[sz - 2].Val.data2, m_vRPN[sz - 1].Val.data2); break; default: // For now functions with unlimited number of arguments are not optimized throw ParserError(ecINTERNAL_ERROR); } // remove the folded values m_vRPN.erase(m_vRPN.end() - a_iArgc, m_vRPN.end()); SToken tok; tok.Cmd = cmVAL; tok.Val.data = 0; tok.Val.data2 = val; tok.Val.ptr = nullptr; m_vRPN.push_back(tok); } else { SToken tok; tok.Cmd = cmFUNC; tok.Fun.argc = a_iArgc; tok.Fun.cb = a_pFun; m_vRPN.push_back(tok); } m_iStackPos = m_iStackPos - std::abs(a_iArgc) + 1; m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); } /** \brief Add a bulk function to bytecode. \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. \param a_pFun Pointer to function callback. */ void ParserByteCode::AddBulkFun(generic_callable_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.cb = 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_callable_type a_pFun, int a_iArgc, int a_iIdx) { m_iStackPos = m_iStackPos - a_iArgc + 1; SToken tok; tok.Cmd = cmFUNC_STR; tok.Fun.argc = a_iArgc; tok.Fun.idx = a_iIdx; tok.Fun.cb = a_pFun; 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() { SToken tok; tok.Cmd = cmEND; m_vRPN.push_back(tok); rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit // Determine the if-then-else jump offsets std::stack 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; case cmELSE: stElse.push(i); idx = stIf.top(); stIf.pop(); m_vRPN[idx].Oprt.offset = i - idx; break; case cmENDIF: idx = stElse.top(); stElse.pop(); m_vRPN[idx].Oprt.offset = i - idx; break; default: break; } } } std::size_t ParserByteCode::GetMaxStackSize() const { return m_iMaxStackSize + 1; } /** \brief Delete the bytecode. \throw nothrow 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; } 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; 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 cmVARPOW3: mu::console() << _T("VARPOW3 \t"); mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.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 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 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 << reinterpret_cast(m_vRPN[i].Fun.cb._pRawFun) << _T("]"); mu::console() << _T("[USERDATA: 0x") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb._pUserData) << _T("]"); mu::console() << _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") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb._pRawFun) << _T("]"); mu::console() << _T("[USERDATA: 0x") << std::hex << reinterpret_cast(m_vRPN[i].Fun.cb._pUserData) << _T("]"); mu::console() << _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 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 mu::console() << _T("END") << std::endl; } } // namespace mu #if defined(_MSC_VER) #pragma warning(pop) #endif beltoforion-muparser-59e0ce1/src/muParserCallback.cpp000066400000000000000000000553331433271236700230340ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "muParserCallback.h" #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 26812) #endif /** \file \brief Implementation of the parser callback class. */ namespace mu { static constexpr int CALLBACK_INTERNAL_VAR_ARGS = 1 << 14; static constexpr int CALLBACK_INTERNAL_FIXED_ARGS_MASK = 0xf; static constexpr int CALLBACK_INTERNAL_WITH_USER_DATA = 1 << 13; struct CbWithUserData { void* pFun; void* pUserData; }; 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, 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) {} ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti) : ParserCallback(a_pFun, a_bAllowOpti, -1, cmFUNC) {} /** \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) {} /** \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(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(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(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) {} 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) {} 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) {} 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) {} 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) {} 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) {} ParserCallback::ParserCallback(fun_userdata_type0 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(0 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type1 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(1 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type2 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(2 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type3 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(3 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type4 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(4 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type5 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(5 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type6 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(6 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type7 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(7 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type8 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(8 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type9 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(9 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(fun_userdata_type10 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(10 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} 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) {} 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 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(bulkfun_userdata_type0 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(0 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type1 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(1 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type2 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(2 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type3 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(3 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type4 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(4 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type5 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(5 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type6 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(6 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type7 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(7 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type8 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(8 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type9 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(9 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_BULK) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(bulkfun_userdata_type10 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(10 | CALLBACK_INTERNAL_WITH_USER_DATA) , 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(CALLBACK_INTERNAL_VAR_ARGS) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC) , m_iType(tpDBL) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(multfun_userdata_type a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(CALLBACK_INTERNAL_VAR_ARGS | CALLBACK_INTERNAL_WITH_USER_DATA) , 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) {} ParserCallback::ParserCallback(strfun_type4 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) , m_iArgc(3) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_STR) , m_iType(tpSTR) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(strfun_type5 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) , m_iArgc(4) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_STR) , m_iType(tpSTR) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(strfun_type6 a_pFun, bool a_bAllowOpti) :m_pFun((void*)a_pFun) , m_iArgc(5) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_STR) , m_iType(tpSTR) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(strfun_userdata_type1 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(0 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_STR) , m_iType(tpSTR) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(strfun_userdata_type2 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(1 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_STR) , m_iType(tpSTR) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(strfun_userdata_type3 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(2 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_STR) , m_iType(tpSTR) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(strfun_userdata_type4 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(3 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_STR) , m_iType(tpSTR) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(strfun_userdata_type5 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{reinterpret_cast(a_pFun), a_pUserData}) , m_iArgc(4 | CALLBACK_INTERNAL_WITH_USER_DATA) , m_iPri(-1) , m_eOprtAsct(oaNONE) , m_iCode(cmFUNC_STR) , m_iType(tpSTR) , m_bAllowOpti(a_bAllowOpti) {} ParserCallback::ParserCallback(strfun_userdata_type6 a_pFun, void* a_pUserData, bool a_bAllowOpti) :m_pFun(new CbWithUserData{ reinterpret_cast(a_pFun), a_pUserData }) , m_iArgc(5 | CALLBACK_INTERNAL_WITH_USER_DATA) , 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) :ParserCallback() { Assign(ref); } ParserCallback & ParserCallback::operator=(const ParserCallback & ref) { Assign(ref); return *this; } ParserCallback::~ParserCallback() { if (m_iArgc & CALLBACK_INTERNAL_WITH_USER_DATA) delete reinterpret_cast(m_pFun); } /** \brief Copy callback from argument. \throw nothrow */ void ParserCallback::Assign(const ParserCallback& ref) { if (this == &ref) return; if (m_iArgc & CALLBACK_INTERNAL_WITH_USER_DATA) { delete reinterpret_cast(m_pFun); m_pFun = nullptr; } if (ref.m_iArgc & CALLBACK_INTERNAL_WITH_USER_DATA) m_pFun = new CbWithUserData(*reinterpret_cast(ref.m_pFun)); else 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 */ void* ParserCallback::GetAddr() const { if (m_iArgc & CALLBACK_INTERNAL_WITH_USER_DATA) return reinterpret_cast(m_pFun)->pFun; else return m_pFun; } /** \brief Get the user data if present, else nullptr \throw nothrow */ void* ParserCallback::GetUserData() const { if (m_iArgc & CALLBACK_INTERNAL_WITH_USER_DATA) return reinterpret_cast(m_pFun)->pUserData; else return nullptr; } /** \brief Check that the callback looks valid \throw nothrow Check that the function pointer is not null, and if there are user data that they are not null. */ bool ParserCallback::IsValid() const { return GetAddr() != nullptr && !((m_iArgc & CALLBACK_INTERNAL_WITH_USER_DATA) && GetUserData() == nullptr); } /** \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 numeric function Arguments. This number is negative for functions with variable number of arguments. */ int ParserCallback::GetArgc() const { return (m_iArgc & CALLBACK_INTERNAL_VAR_ARGS) ? -1 : (m_iArgc & CALLBACK_INTERNAL_FIXED_ARGS_MASK); } } // namespace mu #if defined(_MSC_VER) #pragma warning(pop) #endif beltoforion-muparser-59e0ce1/src/muParserDLL.cpp000066400000000000000000001044321433271236700217460ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(MUPARSER_DLL) #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_DEPRECATE #include #endif #include #include "muParserDLL.h" #include "muParser.h" #include "muParserInt.h" #include "muParserError.h" #if _UNICODE #include #endif #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 26812) #endif #define MU_TRY \ try \ { #define MU_CATCH \ } \ catch (muError_t &e) \ { \ ParserTag *pTag = static_cast(a_hParser); \ pTag->exc = e; \ pTag->bError = true; \ if (pTag->errHandler) \ (pTag->errHandler)(a_hParser); \ } \ catch (...) \ { \ ParserTag *pTag = static_cast(a_hParser); \ pTag->exc = muError_t(mu::ecINTERNAL_ERROR); \ pTag->bError = true; \ if (pTag->errHandler) \ (pTag->errHandler)(a_hParser); \ } /** \file \brief This file contains the implementation of the DLL interface of muparser. */ typedef mu::ParserBase::exception_type muError_t; typedef mu::ParserBase muParser_t; int g_nBulkSize; class ParserTag { public: ParserTag(int nType) : pParser((nType == muBASETYPE_FLOAT) ? (mu::ParserBase*)new mu::Parser() : (nType == muBASETYPE_INT) ? (mu::ParserBase*)new mu::ParserInt() : nullptr) , exc() , errHandler(nullptr) , bError(false) , m_nParserType(nType) {} ~ParserTag() { delete pParser; } mu::ParserBase* pParser; mu::ParserBase::exception_type exc; muErrorHandler_t errHandler; bool bError; private: ParserTag(const ParserTag& ref); ParserTag& operator=(const ParserTag& ref); int m_nParserType; }; static muChar_t s_tmpOutBuf[2048]; template constexpr std::size_t count_of(const T& array) { return (sizeof(array) / sizeof(array[0])); } //--------------------------------------------------------------------------- // // // unexported functions // // //--------------------------------------------------------------------------- inline muParser_t* AsParser(muParserHandle_t a_hParser) { return static_cast(a_hParser)->pParser; } inline ParserTag* AsParserTag(muParserHandle_t a_hParser) { return static_cast(a_hParser); } #if defined(_WIN32) BOOL APIENTRY DllMain(HANDLE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } #endif //--------------------------------------------------------------------------- // // // exported functions // // //--------------------------------------------------------------------------- API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void* pUserData) { MU_TRY muParser_t* p(AsParser(a_hParser)); p->SetVarFactory(a_pFactory, pUserData); MU_CATCH } /** \brief Create a new Parser instance and return its handle. */ API_EXPORT(muParserHandle_t) mupCreate(int nBaseType) { switch (nBaseType) { case muBASETYPE_FLOAT: return (void*)(new ParserTag(muBASETYPE_FLOAT)); case muBASETYPE_INT: return (void*)(new ParserTag(muBASETYPE_INT)); default: return nullptr; } } /** \brief Release the parser instance related with a parser handle. */ API_EXPORT(void) mupRelease(muParserHandle_t a_hParser) { MU_TRY ParserTag* p = static_cast(a_hParser); delete p; MU_CATCH } API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); #ifndef _UNICODE snprintf(s_tmpOutBuf, count_of(s_tmpOutBuf), "%s", p->GetVersion().c_str()); #else swprintf(s_tmpOutBuf, count_of(s_tmpOutBuf), _T("%s"), p->GetVersion().c_str()); #endif return s_tmpOutBuf; MU_CATCH return _T(""); } /** \brief Evaluate the expression. */ API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); return p->Eval(); MU_CATCH return 0; } API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int* nNum) { MU_TRY if (nNum == nullptr) throw std::runtime_error("Argument is null!"); muParser_t* const p(AsParser(a_hParser)); return p->Eval(*nNum); MU_CATCH return 0; } API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t* a_res, int nSize) { MU_TRY muParser_t* p(AsParser(a_hParser)); p->Eval(a_res, nSize); MU_CATCH } API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t* a_szExpr) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->SetExpr(a_szExpr); MU_CATCH } API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->RemoveVar(a_szName); MU_CATCH } /** \brief Release all parser variables. \param a_hParser Handle to the parser instance. */ API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ClearVar(); MU_CATCH } /** \brief Release all parser variables. \param a_hParser Handle to the parser instance. */ API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ClearConst(); MU_CATCH } /** \brief Clear all user defined operators. \param a_hParser Handle to the parser instance. */ API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ClearOprt(); MU_CATCH } API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ClearFun(); MU_CATCH } API_EXPORT(void) mupDefineFun0(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun0_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun2_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun3_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun4(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun4_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun5(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun5_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun6(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun6_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun7(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun7_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun8(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun8_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun9(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun9_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFun10(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun10_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData0(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData0_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData1(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData1_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData2(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData2_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData3(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData3_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData4(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData4_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData5(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData5_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData6(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData6_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData7(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData7_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData8(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData8_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData9(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData9_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineFunUserData10(muParserHandle_t a_hParser, const muChar_t* a_szName, muFunUserData10_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun0_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun1_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun2_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun3_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun4_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun5_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun6_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun7_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun8_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun9_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFun10_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData0(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData0_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData1(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData1_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData2(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData2_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData3(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData3_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData4(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData4_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData5(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData5_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData6(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData6_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData7(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData7_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData8(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData8_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData9(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData9_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineBulkFunUserData10(muParserHandle_t a_hParser, const muChar_t* a_szName, muBulkFunUserData10_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun1_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun2_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun3_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineStrFun4(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun4_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineStrFun5(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFun5_t a_pFun) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, false); MU_CATCH } API_EXPORT(void) mupDefineStrFunUserData1(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData1_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineStrFunUserData2(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData2_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineStrFunUserData3(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData3_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineStrFunUserData4(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData4_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineStrFunUserData5(muParserHandle_t a_hParser, const muChar_t* a_szName, muStrFunUserData5_t a_pFun, void* a_pUserData) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, false); MU_CATCH } API_EXPORT(void) mupDefineMultFun(muParserHandle_t a_hParser, const muChar_t* a_szName, muMultFun_t a_pFun, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFun(a_szName, a_pFun, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineMultFunUserData(muParserHandle_t a_hParser, const muChar_t* a_szName, muMultFunUserData_t a_pFun, void* a_pUserData, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineFunUserData(a_szName, a_pFun, a_pUserData, a_bAllowOpt != 0); MU_CATCH } 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_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineOprt(a_szName, a_pFun, a_nPrec, (mu::EOprtAssociativity)a_nOprtAsct, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineVar(muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t* a_pVar) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineVar(a_szName, a_pVar); MU_CATCH } API_EXPORT(void) mupDefineBulkVar(muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t* a_pVar) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineVar(a_szName, a_pVar); MU_CATCH } API_EXPORT(void) mupDefineConst(muParserHandle_t a_hParser, const muChar_t* a_szName, muFloat_t a_fVal) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineConst(a_szName, a_fVal); MU_CATCH } API_EXPORT(void) mupDefineStrConst(muParserHandle_t a_hParser, const muChar_t* a_szName, const muChar_t* a_szVal) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineStrConst(a_szName, a_szVal); MU_CATCH } API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); // C# explodes when pMsg is returned directly. For some reason it can't access // the memory where the message lies directly. #ifndef _UNICODE snprintf(s_tmpOutBuf, count_of(s_tmpOutBuf), "%s", p->GetExpr().c_str()); #else swprintf(s_tmpOutBuf, count_of(s_tmpOutBuf), _T("%s"), p->GetExpr().c_str()); #endif return s_tmpOutBuf; MU_CATCH return _T(""); } API_EXPORT(void) mupDefinePostfixOprt(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefinePostfixOprt(a_szName, a_pOprt, a_bAllowOpt != 0); MU_CATCH } API_EXPORT(void) mupDefineInfixOprt(muParserHandle_t a_hParser, const muChar_t* a_szName, muFun1_t a_pOprt, muBool_t a_bAllowOpt) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->DefineInfixOprt(a_szName, a_pOprt, a_bAllowOpt != 0); MU_CATCH } // Define character sets for identifiers API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset) { muParser_t* const p(AsParser(a_hParser)); p->DefineNameChars(a_szCharset); } API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset) { muParser_t* const p(AsParser(a_hParser)); p->DefineOprtChars(a_szCharset); } API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset) { muParser_t* const p(AsParser(a_hParser)); p->DefineInfixOprtChars(a_szCharset); } /** \brief Get the number of variables defined in the parser. \param a_hParser [in] Must be a valid parser handle. \return The number of used variables. \sa mupGetExprVar */ API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetVar(); return (int)VarMap.size(); MU_CATCH return 0; // never reached } /** \brief Return a variable that is used in an expression. \param a_hParser [in] A valid parser handle. \param a_iVar [in] The index of the variable to return. \param a_szName [out] Pointer to the variable name. \param a_pVar [out] Pointer to the variable. \throw nothrow Prior to calling this function call mupGetExprVarNum in order to get the number of variables in the expression. If the parameter a_iVar is greater than the number of variables both a_szName and a_pVar will be set to zero. As a side effect this function will trigger an internal calculation of the expression undefined variables will be set to zero during this calculation. During the calculation user defined callback functions present in the expression will be called, this is unavoidable. */ API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_szName, muFloat_t** a_pVar) { // A static buffer is needed for the name since i can't return the // pointer from the map. static muChar_t szName[1024]; MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetVar(); if (a_iVar >= VarMap.size()) { *a_szName = 0; *a_pVar = 0; return; } mu::varmap_type::const_iterator item; item = VarMap.begin(); for (unsigned i = 0; i < a_iVar; ++i) ++item; #ifndef _UNICODE strncpy(szName, item->first.c_str(), count_of(szName)); #else wcsncpy(szName, item->first.c_str(), count_of(szName)); #endif szName[count_of(szName) - 1] = 0; *a_szName = &szName[0]; *a_pVar = item->second; return; MU_CATCH * a_szName = 0; *a_pVar = 0; } /** \brief Get the number of variables used in the expression currently set in the parser. \param a_hParser [in] Must be a valid parser handle. \return The number of used variables. \sa mupGetExprVar */ API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetUsedVar(); return (int)VarMap.size(); MU_CATCH return 0; // never reached } /** \brief Return a variable that is used in an expression. Prior to calling this function call mupGetExprVarNum in order to get the number of variables in the expression. If the parameter a_iVar is greater than the number of variables both a_szName and a_pVar will be set to zero. As a side effect this function will trigger an internal calculation of the expression undefined variables will be set to zero during this calculation. During the calculation user defined callback functions present in the expression will be called, this is unavoidable. \param a_hParser [in] A valid parser handle. \param a_iVar [in] The index of the variable to return. \param a_szName [out] Pointer to the variable name. \param a_pVar [out] Pointer to the variable. \throw nothrow */ API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_szName, muFloat_t** a_pVar) { // A static buffer is needed for the name since i can't return the // pointer from the map. static muChar_t szName[1024]; MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::varmap_type VarMap = p->GetUsedVar(); if (a_iVar >= VarMap.size()) { *a_szName = 0; *a_pVar = 0; return; } mu::varmap_type::const_iterator item; item = VarMap.begin(); for (unsigned i = 0; i < a_iVar; ++i) ++item; #ifndef _UNICODE strncpy(szName, item->first.c_str(), count_of(szName)); #else wcsncpy(szName, item->first.c_str(), count_of(szName)); #endif szName[count_of(szName) - 1] = 0; *a_szName = &szName[0]; *a_pVar = item->second; return; MU_CATCH * a_szName = 0; *a_pVar = 0; } /** \brief Return the number of constants defined in a parser. */ API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::valmap_type ValMap = p->GetConst(); return (int)ValMap.size(); MU_CATCH return 0; // never reached } API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->SetArgSep(cArgSep); MU_CATCH } API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->ResetLocale(); MU_CATCH } API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cDecSep) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->SetDecSep(cDecSep); MU_CATCH } API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cThousandsSep) { MU_TRY muParser_t* const p(AsParser(a_hParser)); p->SetThousandsSep(cThousandsSep); MU_CATCH } //--------------------------------------------------------------------------- /** \brief Retrieve name and value of a single parser constant. \param a_hParser [in] a valid parser handle \param a_iVar [in] Index of the constant to query \param a_pszName [out] pointer to a null terminated string with the constant name \param [out] The constant value */ API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t* a_fVal) { // A static buffer is needed for the name since i can't return the // pointer from the map. static muChar_t szName[1024]; MU_TRY muParser_t* const p(AsParser(a_hParser)); const mu::valmap_type ValMap = p->GetConst(); if (a_iVar >= ValMap.size()) { *a_pszName = 0; *a_fVal = 0; return; } mu::valmap_type::const_iterator item; item = ValMap.begin(); for (unsigned i = 0; i < a_iVar; ++i) ++item; #ifndef _UNICODE strncpy(szName, item->first.c_str(), count_of(szName)); #else wcsncpy(szName, item->first.c_str(), count_of(szName)); #endif szName[count_of(szName) - 1] = 0; *a_pszName = &szName[0]; *a_fVal = item->second; return; MU_CATCH * a_pszName = 0; *a_fVal = 0; } /** \brief Add a custom value recognition function. */ API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, muIdentFun_t a_pFun) { MU_TRY muParser_t* p(AsParser(a_hParser)); p->AddValIdent(a_pFun); MU_CATCH } /** \brief Query if an error occurred. After querying the internal error bit will be reset. So a consecutive call will return false. */ API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser) { bool bError(AsParserTag(a_hParser)->bError); AsParserTag(a_hParser)->bError = false; return bError; } /** \brief Reset the internal error flag. */ API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser) { AsParserTag(a_hParser)->bError = false; } API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t a_pHandler) { AsParserTag(a_hParser)->errHandler = a_pHandler; } /** \brief Return the message associated with the last error. */ API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser) { ParserTag* const p(AsParserTag(a_hParser)); const muChar_t* pMsg = p->exc.GetMsg().c_str(); // C# explodes when pMsg is returned directly. For some reason it can't access // the memory where the message lies directly. #ifndef _UNICODE snprintf(s_tmpOutBuf, count_of(s_tmpOutBuf), "%s", pMsg); #else swprintf(s_tmpOutBuf, count_of(s_tmpOutBuf), _T("%s"), pMsg); #endif return s_tmpOutBuf; } /** \brief Return the message associated with the last error. */ API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser) { ParserTag* const p(AsParserTag(a_hParser)); const muChar_t* pToken = p->exc.GetToken().c_str(); // C# explodes when pMsg is returned directly. For some reason it can't access // the memory where the message lies directly. #ifndef _UNICODE snprintf(s_tmpOutBuf, count_of(s_tmpOutBuf), "%s", pToken); #else swprintf(s_tmpOutBuf, count_of(s_tmpOutBuf), _T("%s"), pToken); #endif return s_tmpOutBuf; } /** \brief Return the code associated with the last error. */ API_EXPORT(int) mupGetErrorCode(muParserHandle_t a_hParser) { return AsParserTag(a_hParser)->exc.GetCode(); } /** \brief Return the position associated with the last error. */ API_EXPORT(int) mupGetErrorPos(muParserHandle_t a_hParser) { return (int)AsParserTag(a_hParser)->exc.GetPos(); } API_EXPORT(muFloat_t*) mupCreateVar() { return new muFloat_t(0); } API_EXPORT(void) mupReleaseVar(muFloat_t* ptr) { delete ptr; } #if defined(_MSC_VER) #pragma warning(pop) #endif #endif // MUPARSER_DLL beltoforion-muparser-59e0ce1/src/muParserError.cpp000066400000000000000000000307421433271236700224260ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "muParserError.h" #include #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 26812) // MSVC wants to force me te use enum classes or bother me with pointless warnings #endif namespace mu { //------------------------------------------------------------------------------ const ParserErrorMsg& ParserErrorMsg::Instance() { static const ParserErrorMsg instance; return instance; } //------------------------------------------------------------------------------ string_type ParserErrorMsg::operator[](unsigned a_iIdx) const { return (a_iIdx < m_vErrMsg.size()) ? m_vErrMsg[a_iIdx] : string_type(); } //--------------------------------------------------------------------------- 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("Strings must only be used as function arguments!"); 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 preceded 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)"); m_vErrMsg[ecIDENTIFIER_TOO_LONG] = _T("Identifier too long."); m_vErrMsg[ecEXPRESSION_TOO_LONG] = _T("Expression too long."); m_vErrMsg[ecINVALID_CHARACTERS_FOUND] = _T("Invalid non printable characters found in expression/identifer!"); for (int i = 0; i < ecCOUNT; ++i) { if (!m_vErrMsg[i].length()) throw std::runtime_error("Error definitions are incomplete!"); } } //--------------------------------------------------------------------------- // // 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]; 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()) { 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]; 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]; 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()) { 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()) { } //------------------------------------------------------------------------------ /** \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) { string_type strResult; string_type::size_type iPos(0), iNext(0); for (;;) { iNext = strSource.find(strFind, iPos); strResult.append(strSource, iPos, iNext - iPos); if (iNext == string_type::npos) break; strResult.append(strReplaceWith); iPos = iNext + strFind.length(); } strSource.swap(strResult); } //------------------------------------------------------------------------------ /** \brief Reset the error 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 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; } //------------------------------------------------------------------------------ /** \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 #if defined(_MSC_VER) #pragma warning(pop) #endif beltoforion-muparser-59e0ce1/src/muParserInt.cpp000066400000000000000000000212651433271236700220670ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "muParserInt.h" #include #include #include using namespace std; /** \file \brief Implementation of a parser using integer value. */ /** \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); } value_type ParserInt::Pow(value_type v1, value_type v2) { return std::pow((double)Round(v1), (double)Round(v2)); } value_type ParserInt::UnaryMinus(value_type v) { return -Round(v); } value_type ParserInt::Sum(const value_type* a_afArg, int a_iArgc) { if (!a_iArgc) throw 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::Min(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::min(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; } 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; 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(); 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. \param a_szExpr Pointer to the expression string \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; 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(); if (nPos == (stringstream_type::pos_type)0) 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; 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); if (i == 0) return 0; if (i == iBits) throw exception_type(_T("Binary to integer conversion error (overflow).")); *a_fVal = (unsigned)(iVal >> (iBits - i)); *a_iPos += i + 1; return 1; } /** \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 InitCharSets(); InitFun(); InitOprt(); } void ParserInt::InitConst() { } void ParserInt::InitCharSets() { DefineNameChars(_T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")); DefineOprtChars(_T("+-*^/?<>=!%&|~'_")); DefineInfixOprtChars(_T("/+-*^?<>=!%&|~'_")); } /** \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); } /** \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); // Disable all built in operators, they won't work with integer numbers // since they are designed for floating point numbers DefineInfixOprt(_T("-"), UnaryMinus); DefineInfixOprt(_T("!"), Not); DefineOprt(_T("&"), LogAnd, prLOGIC); DefineOprt(_T("|"), LogOr, prLOGIC); DefineOprt(_T("&&"), And, prLOGIC); 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); DefineOprt(_T("+"), Add, prADD_SUB); DefineOprt(_T("-"), Sub, prADD_SUB); DefineOprt(_T("*"), Mul, prMUL_DIV); DefineOprt(_T("/"), Div, prMUL_DIV); DefineOprt(_T("%"), Mod, prMUL_DIV); DefineOprt(_T("^"), Pow, prPOW, oaRIGHT); DefineOprt(_T(">>"), Shr, prMUL_DIV + 1); DefineOprt(_T("<<"), Shl, prMUL_DIV + 1); } } // namespace mu beltoforion-muparser-59e0ce1/src/muParserTest.cpp000066400000000000000000002021341433271236700222500ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "muParserTest.h" #include #include #include #include using namespace std; /** \file \brief This file contains the implementation of parser test cases. */ namespace mu { namespace Test { int ParserTester::c_iCount = 0; //--------------------------------------------------------------------------------------------- ParserTester::ParserTester() :m_vTestFun() { AddTest(&ParserTester::TestNames); AddTest(&ParserTester::TestSyntax); AddTest(&ParserTester::TestPostFix); AddTest(&ParserTester::TestInfixOprt); AddTest(&ParserTester::TestVarConst); AddTest(&ParserTester::TestMultiArg); AddTest(&ParserTester::TestExpression); AddTest(&ParserTester::TestIfThenElse); AddTest(&ParserTester::TestInterface); AddTest(&ParserTester::TestBinOprt); AddTest(&ParserTester::TestException); AddTest(&ParserTester::TestStrArg); AddTest(&ParserTester::TestBulkMode); AddTest(&ParserTester::TestOptimizer); ParserTester::c_iCount = 0; } //--------------------------------------------------------------------------------------------- int ParserTester::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); // 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; return 1; } //--------------------------------------------------------------------------------------------- int ParserTester::TestInterface() { int iStat = 0; mu::console() << _T("testing member functions..."); // Test RemoveVar value_type afVal[3] = { 1,2,3 }; Parser p; try { p.DefineVar(_T("a"), &afVal[0]); p.DefineVar(_T("b"), &afVal[1]); p.DefineVar(_T("c"), &afVal[2]); p.SetExpr(_T("a+b+c")); p.Eval(); } catch (...) { iStat += 1; // this is not supposed to happen } try { p.RemoveVar(_T("c")); p.Eval(); iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted... } catch (...) { // failure is expected... } if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------------------------- int ParserTester::TestOptimizer() { int iStat = 0; mu::console() << _T("testing optimizer..."); // Test RemoveVar Parser p; try { // test for #93 (https://github.com/beltoforion/muparser/issues/93) // expected bytecode is: // VAL, FUN { p.DefineFun(_T("unoptimizable"), f1of1, false); p.SetExpr(_T("unoptimizable(1)")); p.Eval(); auto& bc = p.GetByteCode(); const SToken* tok = bc.GetBase(); if (bc.GetSize() != 2 && tok[1].Cmd != cmFUNC) { mu::console() << _T("#93 an unoptimizable expression was optimized!") << endl; iStat += 1; } } { p.ClearFun(); p.DefineFun(_T("unoptimizable"), f1of1, true); p.SetExpr(_T("unoptimizable(1)")); p.Eval(); auto& bc = p.GetByteCode(); const SToken* tok = bc.GetBase(); if (bc.GetSize() != 1 && tok[0].Cmd != cmVAL) { mu::console() << _T("#93 optimizer error") << endl; iStat += 1; } } } catch (...) { iStat += 1; // this is not supposed to happen } if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------------------------- int ParserTester::TestStrArg() { int iStat = 0; mu::console() << _T("testing string arguments..."); // from oss-fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23410 iStat += ThrowTest(_T(R"(6 - 6 ? 4 : "", ? 4 : "", ? 4 : "")"), ecUNEXPECTED_STR, true); // variations: iStat += ThrowTest(_T(R"(avg(0?4:(""),1))"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(1 ? 4 : "")"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(1 ? "" : 4)"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(1 ? "" : "")"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(0 ? 4 : "")"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(0 ? 4 : (""))"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(1 ? 4 : "")"), ecUNEXPECTED_STR); // from oss-fuzz: https://oss-fuzz.com/testcase-detail/5106868061208576 iStat += ThrowTest(_T(R"("","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",8)"), ecSTR_RESULT); // derived from oss-fuzz: https://oss-fuzz.com/testcase-detail/5758791700971520 iStat += ThrowTest(_T("(\"\"), 7"), ecSTR_RESULT); iStat += ThrowTest(_T("((\"\")), 7"), ecSTR_RESULT); //iStat += ThrowTest(_T("(\"\"),(\" \"), 7, (3)"), ecSTR_RESULT); //iStat += ThrowTest(_T("(\"\"),(\"\"), 7, (3)"), ecSTR_RESULT); //iStat += ThrowTest(_T("(\"\"),(\"\"), (3)"), ecSTR_RESULT); //iStat += ThrowTest(_T("(\"\"),(\"\"), 7"), ecSTR_RESULT); // variations: iStat += ThrowTest(_T(R"("","",9)"), ecSTR_RESULT); iStat += EqnTest(_T("valueof(\"\")"), 123, true); // empty string arguments caused a crash iStat += EqnTest(_T("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true); iStat += EqnTest(_T("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true); // use in expressions with variables iStat += EqnTest(_T("a*(atof(\"10\")-b)"), 8, true); iStat += EqnTest(_T("a-(atof(\"10\")*b)"), -19, true); // string + numeric arguments iStat += EqnTest(_T("strfun1(\"100\")"), 100, true); iStat += EqnTest(_T("strfun2(\"100\",1)"), 101, true); iStat += EqnTest(_T("strfun3(\"99\",1,2)"), 102, true); iStat += EqnTest(_T("strfun4(\"99\",1,2,3)"), 105, true); iStat += EqnTest(_T("strfun5(\"99\",1,2,3,4)"), 109, true); iStat += EqnTest(_T("strfun6(\"99\",1,2,3,4,5)"), 114, true); // string constants iStat += EqnTest(_T("atof(str1)+atof(str2)"), 3.33, true); // user data iStat += EqnTest(_T("strfunud3_10(\"99\",1,2)"), 112, true); if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------------------------- int ParserTester::TestBulkMode() { int iStat = 0; mu::console() << _T("testing bulkmode..."); #define EQN_TEST_BULK(EXPR, R1, R2, R3, R4, PASS) \ { \ double res[] = { R1, R2, R3, R4 }; \ iStat += EqnTestBulk(_T(EXPR), res, (PASS)); \ } // Bulk Variables for the test: // a: 1,2,3,4 // b: 2,2,2,2 // c: 3,3,3,3 // d: 5,4,3,2 EQN_TEST_BULK("a", 1, 1, 1, 1, false) EQN_TEST_BULK("a", 1, 2, 3, 4, true) EQN_TEST_BULK("b=a", 1, 2, 3, 4, true) EQN_TEST_BULK("b=a, b*10", 10, 20, 30, 40, true) EQN_TEST_BULK("b=a, b*10, a", 1, 2, 3, 4, true) EQN_TEST_BULK("a+b", 3, 4, 5, 6, true) EQN_TEST_BULK("c*(a+b)", 9, 12, 15, 18, true) #undef EQN_TEST_BULK if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------------------------- int ParserTester::TestBinOprt() { int iStat = 0; mu::console() << _T("testing binary operators..."); // built in operators // xor operator iStat += EqnTest(_T("a++b"), 3, true); iStat += EqnTest(_T("a ++ b"), 3, true); iStat += EqnTest(_T("1++2"), 3, true); iStat += EqnTest(_T("1 ++ 2"), 3, true); iStat += EqnTest(_T("a add b"), 3, true); iStat += EqnTest(_T("1 add 2"), 3, true); iStat += EqnTest(_T("aa"), 1, true); iStat += EqnTest(_T("a>a"), 0, true); iStat += EqnTest(_T("aa"), 0, true); iStat += EqnTest(_T("a<=a"), 1, true); iStat += EqnTest(_T("a<=b"), 1, true); iStat += EqnTest(_T("b<=a"), 0, true); iStat += EqnTest(_T("a>=a"), 1, true); iStat += EqnTest(_T("b>=a"), 1, true); iStat += EqnTest(_T("a>=b"), 0, true); // Test logical operators, especially if user defined "&" and the internal "&&" collide iStat += EqnTest(_T("1 && 1"), 1, true); iStat += EqnTest(_T("1 && 0"), 0, true); iStat += EqnTest(_T("(aa)"), 1, true); iStat += EqnTest(_T("(ab)"), 0, true); //iStat += EqnTest(_T("12 and 255"), 12, true); //iStat += EqnTest(_T("12 and 0"), 0, true); iStat += EqnTest(_T("12 & 255"), 12, true); iStat += EqnTest(_T("12 & 0"), 0, true); iStat += EqnTest(_T("12&255"), 12, true); iStat += EqnTest(_T("12&0"), 0, true); // Assignment operator iStat += EqnTest(_T("a = b"), 2, true); iStat += EqnTest(_T("a = sin(b)"), 0.909297, true); iStat += EqnTest(_T("a = 1+sin(b)"), 1.909297, true); iStat += EqnTest(_T("(a=b)*2"), 4, true); iStat += EqnTest(_T("2*(a=b)"), 4, true); iStat += EqnTest(_T("2*(a=b+1)"), 6, true); iStat += EqnTest(_T("(a=b+1)*2"), 6, true); iStat += EqnTest(_T("a=c, a*10"), 30, true); iStat += EqnTest(_T("2^2^3"), 256, true); iStat += EqnTest(_T("1/2/3"), 1.0 / 6.0, true); // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3 iStat += EqnTest(_T("3+4*2/(1-5)^2^3"), 3.0001220703125, true); // Test user defined binary operators iStat += EqnTestInt(_T("1 | 2"), 3, true); iStat += EqnTestInt(_T("1 || 2"), 1, true); iStat += EqnTestInt(_T("123 & 456"), 72, true); iStat += EqnTestInt(_T("(123 & 456) % 10"), 2, true); iStat += EqnTestInt(_T("1 && 0"), 0, true); iStat += EqnTestInt(_T("123 && 456"), 1, true); iStat += EqnTestInt(_T("1 << 3"), 8, true); iStat += EqnTestInt(_T("8 >> 3"), 1, true); iStat += EqnTestInt(_T("9 / 4"), 2, true); iStat += EqnTestInt(_T("9 % 4"), 1, true); iStat += EqnTestInt(_T("if(5%2,1,0)"), 1, true); iStat += EqnTestInt(_T("if(4%2,1,0)"), 0, true); iStat += EqnTestInt(_T("-10+1"), -9, true); iStat += EqnTestInt(_T("1+2*3"), 7, true); iStat += EqnTestInt(_T("const1 != const2"), 1, true); iStat += EqnTestInt(_T("const1 != const2"), 0, false); iStat += EqnTestInt(_T("const1 == const2"), 0, true); iStat += EqnTestInt(_T("const1 == 1"), 1, true); iStat += EqnTestInt(_T("10*(const1 == 1)"), 10, true); iStat += EqnTestInt(_T("2*(const1 | const2)"), 6, true); iStat += EqnTestInt(_T("2*(const1 | const2)"), 7, false); iStat += EqnTestInt(_T("const1 < const2"), 1, true); iStat += EqnTestInt(_T("const2 > const1"), 1, true); iStat += EqnTestInt(_T("const1 <= 1"), 1, true); iStat += EqnTestInt(_T("const2 >= 2"), 1, true); iStat += EqnTestInt(_T("2*(const1 + const2)"), 6, true); iStat += EqnTestInt(_T("2*(const1 - const2)"), -2, true); iStat += EqnTestInt(_T("a != b"), 1, true); iStat += EqnTestInt(_T("a != b"), 0, false); iStat += EqnTestInt(_T("a == b"), 0, true); iStat += EqnTestInt(_T("a == 1"), 1, true); iStat += EqnTestInt(_T("10*(a == 1)"), 10, true); iStat += EqnTestInt(_T("2*(a | b)"), 6, true); iStat += EqnTestInt(_T("2*(a | b)"), 7, false); iStat += EqnTestInt(_T("a < b"), 1, true); iStat += EqnTestInt(_T("b > a"), 1, true); iStat += EqnTestInt(_T("a <= 1"), 1, true); iStat += EqnTestInt(_T("b >= 2"), 1, true); iStat += EqnTestInt(_T("2*(a + b)"), 6, true); iStat += EqnTestInt(_T("2*(a - b)"), -2, true); iStat += EqnTestInt(_T("a + (a << b)"), 5, true); iStat += EqnTestInt(_T("-2^2"), -4, true); iStat += EqnTestInt(_T("3--a"), 4, true); iStat += EqnTestInt(_T("3+-3^2"), -6, true); // Test reading of hex values: iStat += EqnTestInt(_T("0xff"), 255, true); iStat += EqnTestInt(_T("10+0xff"), 265, true); iStat += EqnTestInt(_T("0xff+10"), 265, true); iStat += EqnTestInt(_T("10*0xff"), 2550, true); iStat += EqnTestInt(_T("0xff*10"), 2550, true); iStat += EqnTestInt(_T("10+0xff+1"), 266, true); iStat += EqnTestInt(_T("1+0xff+10"), 266, true); // incorrect: '^' is yor here, not power // iStat += EqnTestInt("-(1+2)^2", -9, true); // iStat += EqnTestInt("-1^3", -1, true); // Test precedence // a=1, b=2, c=3 iStat += EqnTestInt(_T("a + b * c"), 7, true); iStat += EqnTestInt(_T("a * b + c"), 5, true); iStat += EqnTestInt(_T("a10"), 0, true); iStat += EqnTestInt(_T("a"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1) PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1) // Binary operator // The following must fail with builtin operators activated // p.EnableBuiltInOp(true); -> this is the default p.ClearPostfixOprt(); PARSER_THROWCHECK(Oprt, false, _T("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), f1of2); PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("^"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("&&"), f1of2) PARSER_THROWCHECK(Oprt, false, _T("||"), f1of2) // without activated built in operators it should work p.EnableBuiltInOprt(false); PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("^"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("&&"), f1of2) PARSER_THROWCHECK(Oprt, true, _T("||"), f1of2) #undef PARSER_THROWCHECK if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestSyntax() { int iStat = 0; mu::console() << _T("testing syntax engine..."); iStat += ThrowTest(_T("1,"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += ThrowTest(_T("a,"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += ThrowTest(_T("sin(8),"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += ThrowTest(_T("(sin(8)),"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += ThrowTest(_T("a{m},"), ecUNEXPECTED_EOF); // incomplete hex definition iStat += EqnTest(_T("(1+ 2*a)"), 3, true); // Spaces within formula iStat += EqnTest(_T("sqrt((4))"), 2, true); // Multiple brackets iStat += EqnTest(_T("sqrt((2)+2)"), 2, true);// Multiple brackets iStat += EqnTest(_T("sqrt(2+(2))"), 2, true);// Multiple brackets iStat += EqnTest(_T("sqrt(a+(3))"), 2, true);// Multiple brackets iStat += EqnTest(_T("sqrt((3)+a)"), 2, true);// Multiple brackets iStat += EqnTest(_T("order(1,2)"), 1, true); // May not cause name collision with operator "or" iStat += EqnTest(_T("(2+"), 0, false); // missing closing bracket iStat += EqnTest(_T("2++4"), 0, false); // unexpected operator iStat += EqnTest(_T("2+-4"), 0, false); // unexpected operator iStat += EqnTest(_T("(2+)"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("--2"), 0, false); // double sign iStat += EqnTest(_T("ksdfj"), 0, false); // unknown token iStat += EqnTest(_T("()"), 0, false); // empty bracket without a function iStat += EqnTest(_T("5+()"), 0, false); // empty bracket without a function iStat += EqnTest(_T("sin(cos)"), 0, false); // unexpected function iStat += EqnTest(_T("5t6"), 0, false); // unknown token iStat += EqnTest(_T("5 t 6"), 0, false); // unknown token iStat += EqnTest(_T("8*"), 0, false); // unexpected end of formula iStat += EqnTest(_T(",3"), 0, false); // unexpected comma iStat += EqnTest(_T("3,5"), 0, false); // unexpected comma iStat += EqnTest(_T("sin(8,8)"), 0, false); // too many function args iStat += EqnTest(_T("(7,8)"), 0, false); // too many function args iStat += EqnTest(_T("sin)"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("a)"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("pi)"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("sin(())"), 0, false); // unexpected closing bracket iStat += EqnTest(_T("sin()"), 0, false); // unexpected closing bracket if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestVarConst() { int iStat = 0; mu::console() << _T("testing variable/constant detection..."); // Test if the result changes when a variable changes iStat += EqnTestWithVarChange(_T("a"), 1, 1, 2, 2); iStat += EqnTestWithVarChange(_T("2*a"), 2, 4, 3, 6); // distinguish constants with same basename iStat += EqnTest(_T("const"), 1, true); iStat += EqnTest(_T("const1"), 2, true); iStat += EqnTest(_T("const2"), 3, true); iStat += EqnTest(_T("2*const"), 2, true); iStat += EqnTest(_T("2*const1"), 4, true); iStat += EqnTest(_T("2*const2"), 6, true); iStat += EqnTest(_T("2*const+1"), 3, true); iStat += EqnTest(_T("2*const1+1"), 5, true); iStat += EqnTest(_T("2*const2+1"), 7, true); iStat += EqnTest(_T("const"), 0, false); iStat += EqnTest(_T("const1"), 0, false); iStat += EqnTest(_T("const2"), 0, false); // distinguish variables with same basename iStat += EqnTest(_T("a"), 1, true); iStat += EqnTest(_T("aa"), 2, true); iStat += EqnTest(_T("2*a"), 2, true); iStat += EqnTest(_T("2*aa"), 4, true); iStat += EqnTest(_T("2*a-1"), 1, true); iStat += EqnTest(_T("2*aa-1"), 3, true); // custom value recognition iStat += EqnTest(_T("0xff"), 255, true); iStat += EqnTest(_T("0x97 + 0xff"), 406, true); // Finally test querying of used variables try { int idx; mu::Parser p; mu::value_type vVarVal[] = { 1, 2, 3, 4, 5 }; p.DefineVar(_T("a"), &vVarVal[0]); p.DefineVar(_T("b"), &vVarVal[1]); p.DefineVar(_T("c"), &vVarVal[2]); p.DefineVar(_T("d"), &vVarVal[3]); p.DefineVar(_T("e"), &vVarVal[4]); // Test lookup of defined variables // 4 used variables p.SetExpr(_T("a+b+c+d")); mu::varmap_type UsedVar = p.GetUsedVar(); int iCount = (int)UsedVar.size(); if (iCount != 4) throw false; // the next check will fail if the parser // erroneously creates new variables internally if (p.GetVar().size() != 5) throw false; mu::varmap_type::const_iterator item = UsedVar.begin(); for (idx = 0; item != UsedVar.end(); ++item) { if (&vVarVal[idx++] != item->second) throw false; } // Test lookup of undefined variables p.SetExpr(_T("undef1+undef2+undef3")); UsedVar = p.GetUsedVar(); iCount = (int)UsedVar.size(); if (iCount != 3) throw false; // the next check will fail if the parser // erroneously creates new variables internally if (p.GetVar().size() != 5) throw false; for (item = UsedVar.begin(); item != UsedVar.end(); ++item) { if (item->second != 0) throw false; // all pointers to undefined variables must be null } // 1 used variables p.SetExpr(_T("a+b")); UsedVar = p.GetUsedVar(); iCount = (int)UsedVar.size(); if (iCount != 2) throw false; item = UsedVar.begin(); for (idx = 0; item != UsedVar.end(); ++item) if (&vVarVal[idx++] != item->second) throw false; } catch (...) { iStat += 1; } if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestMultiArg() { int iStat = 0; mu::console() << _T("testing multiarg functions..."); // from oss-fzz.com: UNKNOWN READ; https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23330#c1 iStat += ThrowTest(_T("6, +, +, +, +, +, +, +, +, +, +, +, +, +, +, 1, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +, +"), ecUNEXPECTED_ARG_SEP, true); // misplaced string argument iStat += ThrowTest(_T(R"(sin(0?4:("")))"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(avg(0?4:(""),1))"), ecUNEXPECTED_STR); // Compound expressions iStat += EqnTest(_T("1,2,3"), 3, true); iStat += EqnTest(_T("a,b,c"), 3, true); iStat += EqnTest(_T("a=10,b=20,c=a*b"), 200, true); iStat += EqnTest(_T("1,\n2,\n3"), 3, true); iStat += EqnTest(_T("a,\nb,\nc"), 3, true); iStat += EqnTest(_T("a=10,\nb=20,\nc=a*b"), 200, true); iStat += EqnTest(_T("1,\r\n2,\r\n3"), 3, true); iStat += EqnTest(_T("a,\r\nb,\r\nc"), 3, true); iStat += EqnTest(_T("a=10,\r\nb=20,\r\nc=a*b"), 200, true); // picking the right argument iStat += EqnTest(_T("f1of1(1)"), 1, true); iStat += EqnTest(_T("f1of2(1, 2)"), 1, true); iStat += EqnTest(_T("f2of2(1, 2)"), 2, true); iStat += EqnTest(_T("f1of3(1, 2, 3)"), 1, true); iStat += EqnTest(_T("f2of3(1, 2, 3)"), 2, true); iStat += EqnTest(_T("f3of3(1, 2, 3)"), 3, true); iStat += EqnTest(_T("f1of4(1, 2, 3, 4)"), 1, true); iStat += EqnTest(_T("f2of4(1, 2, 3, 4)"), 2, true); iStat += EqnTest(_T("f3of4(1, 2, 3, 4)"), 3, true); iStat += EqnTest(_T("f4of4(1, 2, 3, 4)"), 4, true); iStat += EqnTest(_T("f1of5(1, 2, 3, 4, 5)"), 1, true); iStat += EqnTest(_T("f2of5(1, 2, 3, 4, 5)"), 2, true); iStat += EqnTest(_T("f3of5(1, 2, 3, 4, 5)"), 3, true); iStat += EqnTest(_T("f4of5(1, 2, 3, 4, 5)"), 4, true); iStat += EqnTest(_T("f5of5(1, 2, 3, 4, 5)"), 5, true); // Too few arguments / Too many arguments iStat += EqnTest(_T("1+ping()"), 11, true); iStat += EqnTest(_T("ping()+1"), 11, true); iStat += EqnTest(_T("2*ping()"), 20, true); iStat += EqnTest(_T("ping()*2"), 20, true); iStat += EqnTest(_T("ping(1,2)"), 0, false); iStat += EqnTest(_T("1+ping(1,2)"), 0, false); iStat += EqnTest(_T("f1of1(1,2)"), 0, false); iStat += EqnTest(_T("f1of1()"), 0, false); iStat += EqnTest(_T("f1of2(1, 2, 3)"), 0, false); iStat += EqnTest(_T("f1of2(1)"), 0, false); iStat += EqnTest(_T("f1of3(1, 2, 3, 4)"), 0, false); iStat += EqnTest(_T("f1of3(1)"), 0, false); iStat += EqnTest(_T("f1of4(1, 2, 3, 4, 5)"), 0, false); iStat += EqnTest(_T("f1of4(1)"), 0, false); iStat += EqnTest(_T("(1,2,3)"), 0, false); iStat += EqnTest(_T("1,2,3"), 0, false); iStat += EqnTest(_T("(1*a,2,3)"), 0, false); iStat += EqnTest(_T("1,2*a,3"), 0, false); // correct calculation of arguments iStat += EqnTest(_T("min(a, 1)"), 1, true); iStat += EqnTest(_T("min(3*2, 1)"), 1, true); iStat += EqnTest(_T("min(3*2, 1)"), 6, false); iStat += EqnTest(_T("firstArg(2,3,4)"), 2, true); iStat += EqnTest(_T("lastArg(2,3,4)"), 4, true); iStat += EqnTest(_T("min(3*a+1, 1)"), 1, true); iStat += EqnTest(_T("max(3*a+1, 1)"), 4, true); iStat += EqnTest(_T("max(3*a+1, 1)*2"), 8, true); iStat += EqnTest(_T("2*max(3*a+1, 1)+2"), 10, true); // functions with Variable argument count iStat += EqnTest(_T("sum(a)"), 1, true); iStat += EqnTest(_T("sum(1,2,3)"), 6, true); iStat += EqnTest(_T("sum(a,b,c)"), 6, true); iStat += EqnTest(_T("sum(1,-max(1,2),3)*2"), 4, true); iStat += EqnTest(_T("2*sum(1,2,3)"), 12, true); iStat += EqnTest(_T("2*sum(1,2,3)+2"), 14, true); iStat += EqnTest(_T("2*sum(-1,2,3)+2"), 10, true); iStat += EqnTest(_T("2*sum(-1,2,-(-a))+2"), 6, true); iStat += EqnTest(_T("2*sum(-1,10,-a)+2"), 18, true); iStat += EqnTest(_T("2*sum(1,2,3)*2"), 24, true); iStat += EqnTest(_T("sum(1,-max(1,2),3)*2"), 4, true); iStat += EqnTest(_T("sum(1*3, 4, a+2)"), 10, true); iStat += EqnTest(_T("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true); iStat += EqnTest(_T("sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 24, true); // some failures iStat += EqnTest(_T("sum()"), 0, false); iStat += EqnTest(_T("sum(,)"), 0, false); iStat += EqnTest(_T("sum(1,2,)"), 0, false); iStat += EqnTest(_T("sum(,1,2)"), 0, false); // user data iStat += EqnTest(_T("funud0_8()"), 8, true); iStat += EqnTest(_T("funud1_16(10)"), 26, true); iStat += EqnTest(_T("funud2_24(10, 100)"), 134, true); iStat += EqnTest(_T("funud10_32(1,2,3,4,5,6,7,8,9,10)"), 87, true); iStat += EqnTest(_T("funud0_9()"), 9, true); iStat += EqnTest(_T("funud1_17(10)"), 27, true); iStat += EqnTest(_T("funud2_25(10, 100)"), 135, true); iStat += EqnTest(_T("funud10_33(1,2,3,4,5,6,7,8,9,10)"), 88, true); iStat += EqnTest(_T("sumud_100(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 124, true); iStat += EqnTest(_T("sumud_100()"), 0, false); if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestInfixOprt() { int iStat(0); mu::console() << "testing infix operators..."; iStat += EqnTest(_T("+1"), +1, true); iStat += EqnTest(_T("-(+1)"), -1, true); iStat += EqnTest(_T("-(+1)*2"), -2, true); iStat += EqnTest(_T("-(+2)*sqrt(4)"), -4, true); iStat += EqnTest(_T("3-+a"), 2, true); iStat += EqnTest(_T("+1*3"), 3, true); iStat += EqnTest(_T("-1"), -1, true); iStat += EqnTest(_T("-(-1)"), 1, true); iStat += EqnTest(_T("-(-1)*2"), 2, true); iStat += EqnTest(_T("-(-2)*sqrt(4)"), 4, true); iStat += EqnTest(_T("-_pi"), -MathImpl::CONST_PI, true); iStat += EqnTest(_T("-a"), -1, true); iStat += EqnTest(_T("-(a)"), -1, true); iStat += EqnTest(_T("-(-a)"), 1, true); iStat += EqnTest(_T("-(-a)*2"), 2, true); iStat += EqnTest(_T("-(8)"), -8, true); iStat += EqnTest(_T("-8"), -8, true); iStat += EqnTest(_T("-(2+1)"), -3, true); iStat += EqnTest(_T("-(f1of1(1+2*3)+1*2)"), -9, true); iStat += EqnTest(_T("-(-f1of1(1+2*3)+1*2)"), 5, true); iStat += EqnTest(_T("-sin(8)"), -0.989358, true); iStat += EqnTest(_T("3-(-a)"), 4, true); iStat += EqnTest(_T("3--a"), 4, true); iStat += EqnTest(_T("-1*3"), -3, true); // Postfix / infix priorities iStat += EqnTest(_T("~2#"), 8, true); iStat += EqnTest(_T("~f1of1(2)#"), 8, true); iStat += EqnTest(_T("~(b)#"), 8, true); iStat += EqnTest(_T("(~b)#"), 12, true); iStat += EqnTest(_T("~(2#)"), 8, true); iStat += EqnTest(_T("~(f1of1(2)#)"), 8, true); // iStat += EqnTest(_T("-2^2"), -4, true); iStat += EqnTest(_T("-(a+b)^2"), -9, true); iStat += EqnTest(_T("(-3)^2"), 9, true); iStat += EqnTest(_T("-(-2^2)"), 4, true); iStat += EqnTest(_T("3+-3^2"), -6, true); // The following assumes use of sqr as postfix operator together // with a sign operator of low priority: iStat += EqnTest(_T("-2'"), -4, true); iStat += EqnTest(_T("-(1+1)'"), -4, true); iStat += EqnTest(_T("2+-(1+1)'"), -2, true); iStat += EqnTest(_T("2+-2'"), -2, true); // This is the classic behaviour of the infix sign operator (here: "$") which is // now deprecated: iStat += EqnTest(_T("$2^2"), 4, true); iStat += EqnTest(_T("$(a+b)^2"), 9, true); iStat += EqnTest(_T("($3)^2"), 9, true); iStat += EqnTest(_T("$($2^2)"), -4, true); iStat += EqnTest(_T("3+$3^2"), 12, true); // infix operators sharing the first few characters iStat += EqnTest(_T("~ 123"), (value_type)123.0 + 2, true); iStat += EqnTest(_T("~~ 123"), (value_type)123.0 + 2, true); if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestPostFix() { int iStat = 0; mu::console() << _T("testing postfix operators..."); // application iStat += EqnTest(_T("3{m}+5"), 5.003, true); iStat += EqnTest(_T("1000{m}"), 1, true); iStat += EqnTest(_T("1000 {m}"), 1, true); iStat += EqnTest(_T("(a){m}"), 1e-3, true); iStat += EqnTest(_T("a{m}"), 1e-3, true); iStat += EqnTest(_T("a {m}"), 1e-3, true); iStat += EqnTest(_T("-(a){m}"), -1e-3, true); iStat += EqnTest(_T("-2{m}"), -2e-3, true); iStat += EqnTest(_T("-2 {m}"), -2e-3, true); iStat += EqnTest(_T("f1of1(1000){m}"), 1, true); iStat += EqnTest(_T("-f1of1(1000){m}"), -1, true); iStat += EqnTest(_T("-f1of1(-1000){m}"), 1, true); iStat += EqnTest(_T("f4of4(0,0,0,1000){m}"), 1, true); iStat += EqnTest(_T("2+(a*1000){m}"), 3, true); // can postfix operators "m" und "meg" be told apart properly? iStat += EqnTest(_T("2*3000meg+2"), 2 * 3e9 + 2, true); // some incorrect results iStat += EqnTest(_T("1000{m}"), 0.1, false); iStat += EqnTest(_T("(a){m}"), 2, false); // failure due to syntax checking iStat += ThrowTest(_T("0x"), ecUNASSIGNABLE_TOKEN); // incomplete hex definition iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF); iStat += ThrowTest(_T("4 + {m}"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest(_T("{m}4"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest(_T("sin({m})"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest(_T("{m} {m}"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest(_T("{m}(8)"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest(_T("4,{m}"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest(_T("-{m}"), ecUNASSIGNABLE_TOKEN); iStat += ThrowTest(_T("2(-{m})"), ecUNEXPECTED_PARENS); iStat += ThrowTest(_T("2({m})"), ecUNEXPECTED_PARENS); iStat += ThrowTest(_T("multi*1.0"), ecUNASSIGNABLE_TOKEN); if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestExpression() { int iStat = 0; mu::console() << _T("testing expression samples..."); value_type b = 2; iStat += EqnTest(_T("f0()"), 42, true); iStat += EqnTest(_T("b^2"), 4, true); iStat += EqnTest(_T("b^1"), 2, true); iStat += EqnTest(_T("b^0"), 1, true); iStat += EqnTest(_T("b^-1"), 0.5, true); // Optimization iStat += EqnTest(_T("2*b*5"), 20, true); iStat += EqnTest(_T("2*b*5 + 4*b"), 28, true); iStat += EqnTest(_T("2*a/3"), 2.0 / 3.0, true); // Addition auf cmVARMUL iStat += EqnTest(_T("3+b"), b + 3, true); iStat += EqnTest(_T("b+3"), b + 3, true); iStat += EqnTest(_T("b*3+2"), b * 3 + 2, true); iStat += EqnTest(_T("3*b+2"), b * 3 + 2, true); iStat += EqnTest(_T("2+b*3"), b * 3 + 2, true); iStat += EqnTest(_T("2+3*b"), b * 3 + 2, true); iStat += EqnTest(_T("b+3*b"), b + 3 * b, true); iStat += EqnTest(_T("3*b+b"), b + 3 * b, true); iStat += EqnTest(_T("2+b*3+b"), 2 + b * 3 + b, true); iStat += EqnTest(_T("b+2+b*3"), b + 2 + b * 3, true); iStat += EqnTest(_T("(2*b+1)*4"), (2 * b + 1) * 4, true); iStat += EqnTest(_T("4*(2*b+1)"), (2 * b + 1) * 4, true); // operator precedences iStat += EqnTest(_T("1+2-3*4/5^6"), 2.99923, true); iStat += EqnTest(_T("1^2/3*4-5+6"), 2.33333333, true); iStat += EqnTest(_T("1+2*3"), 7, true); iStat += EqnTest(_T("1+2*3"), 7, true); iStat += EqnTest(_T("(1+2)*3"), 9, true); iStat += EqnTest(_T("(1+2)*(-3)"), -9, true); iStat += EqnTest(_T("2/4"), 0.5, true); iStat += EqnTest(_T("exp(ln(7))"), 7, true); iStat += EqnTest(_T("e^ln(7)"), 7, true); iStat += EqnTest(_T("e^(ln(7))"), 7, true); iStat += EqnTest(_T("(e^(ln(7)))"), 7, true); iStat += EqnTest(_T("1-(e^(ln(7)))"), -6, true); iStat += EqnTest(_T("2*(e^(ln(7)))"), 14, true); iStat += EqnTest(_T("10^log(5)"), pow(10.0, log(5.0)), true); iStat += EqnTest(_T("10^log10(5)"), 5, true); iStat += EqnTest(_T("2^log2(4)"), 4, true); iStat += EqnTest(_T("-(sin(0)+1)"), -1, true); iStat += EqnTest(_T("-(2^1.1)"), -2.14354692, true); iStat += EqnTest(_T("(cos(2.41)/b)"), -0.372056, true); iStat += EqnTest(_T("(1*(2*(3*(4*(5*(6*(a+b)))))))"), 2160, true); iStat += EqnTest(_T("(1*(2*(3*(4*(5*(6*(7*(a+b))))))))"), 15120, true); iStat += EqnTest(_T("(a/((((b+(((e*(((((pi*((((3.45*((pi+a)+pi))+b)+b)*a))+0.68)+e)+a)/a))+a)+b))+b)*a)-pi))"), 0.00377999, true); // long formula (Reference: Matlab) iStat += EqnTest( _T("(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))") _T("/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/") _T("((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-") _T("e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6") _T("+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e") _T("*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)"), -12.23016549, true); // long formula (Reference: Matlab) iStat += EqnTest( _T("(atan(sin((((((((((((((((pi/cos((a/((((0.53-b)-pi)*e)/b))))+2.51)+a)-0.54)/0.98)+b)*b)+e)/a)+b)+a)+b)+pi)/e") _T(")+a)))*2.77)"), -2.16995656, true); // long formula (Reference: Matlab) iStat += EqnTest(_T("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true); if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- int ParserTester::TestIfThenElse() { int iStat = 0; mu::console() << _T("testing if-then-else operator..."); // from oss-fuzz.com: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24167 iStat += ThrowTest(_T(R"(0^3^avg(0>3?4:(""),0^3?4:("")))"), ecUNEXPECTED_STR); // derivatives iStat += ThrowTest(_T(R"(avg(0?(""):4,1))"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(avg(0>3?4:(""),0^3?4:("")))"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(0?4:(""))"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"((0)?4:(""))"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"((0>3)?4:(""))"), ecUNEXPECTED_STR); iStat += ThrowTest(_T(R"(0>3?4:(""))"), ecUNEXPECTED_STR); // from oss-fuzz.com: https://oss-fuzz.com/testcase-detail/4777121158529024 iStat += ThrowTest(_T("3!=min(0?2>2,2>5,1:6)"), ecUNEXPECTED_ARG_SEP); // Test error detection iStat += ThrowTest(_T(":3"), ecUNEXPECTED_CONDITIONAL); iStat += ThrowTest(_T("? 1 : 2"), ecUNEXPECTED_CONDITIONAL); iStat += ThrowTest(_T("(a3?2,4,2:4)"), ecUNEXPECTED_ARG_SEP); iStat += ThrowTest(_T("sum(2>3?2,4,sin(2):4)"), ecUNEXPECTED_ARG_SEP); iStat += ThrowTest(_T("sum(2>3?sin(2),4,2:4)"), ecUNEXPECTED_ARG_SEP); iStat += ThrowTest(_T("sum(2>3?sin(a),4,2:4)"), ecUNEXPECTED_ARG_SEP); iStat += ThrowTest(_T("sum(2>3?sin(2),4,2:4)"), ecUNEXPECTED_ARG_SEP); iStat += EqnTest(_T("1 ? 128 : 255"), 128, true); iStat += EqnTest(_T("1<2 ? 128 : 255"), 128, true); iStat += EqnTest(_T("ab) ? 10 : 11"), 11, true); iStat += EqnTest(_T("(ab) ? c : d"), -2, true); iStat += EqnTest(_T("(a>b) ? 1 : 0"), 0, true); iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : 2"), 2, true); iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)"), 2, true); iStat += EqnTest(_T("((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)"), 1, true); iStat += EqnTest(_T("sum((a>b) ? 1 : 2)"), 2, true); iStat += EqnTest(_T("sum((1) ? 1 : 2)"), 1, true); iStat += EqnTest(_T("sum((a>b) ? 1 : 2, 100)"), 102, true); iStat += EqnTest(_T("sum((1) ? 1 : 2, 100)"), 101, true); iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)"), 13, true); iStat += EqnTest(_T("sum(3, (ab) ? 3 : 10)"), 130, true); iStat += EqnTest(_T("10*sum(3, (ab) ? 3 : 10)*10"), 130, true); iStat += EqnTest(_T("sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab)&&(a2)&&(1<2) ? 128 : 255"), 255, true); iStat += EqnTest(_T("((1<2)&&(1<2)) ? 128 : 255"), 128, true); iStat += EqnTest(_T("((1>2)&&(1<2)) ? 128 : 255"), 255, true); iStat += EqnTest(_T("((ab)&&(a0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 255, true); iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)"), 255, true); iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 128, true); iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)"), 128, true); iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 32, true); iStat += EqnTest(_T("1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 64, true); iStat += EqnTest(_T("1>0 ? 50 : 1>0 ? 128 : 255"), 50, true); iStat += EqnTest(_T("1>0 ? 50 : (1>0 ? 128 : 255)"), 50, true); iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 50"), 128, true); iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16"), 32, true); iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)"), 32, true); iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16"), 255, true); iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)"), 255, true); iStat += EqnTest(_T("1 ? 0 ? 128 : 255 : 1 ? 32 : 64"), 255, true); // assignment operators iStat += EqnTest(_T("a= 0 ? 128 : 255, a"), 255, true); iStat += EqnTest(_T("a=((a>b)&&(a // this is now legal, for reference see: // https://sourceforge.net/forum/message.php?msg_id=7411373 // iStat += ThrowTest( _T("sin=9"), ecUNEXPECTED_OPERATOR); // iStat += ThrowTest(_T("(8)=5"), ecUNEXPECTED_OPERATOR); iStat += ThrowTest(_T("(a)=5"), ecUNEXPECTED_OPERATOR); iStat += ThrowTest(_T("a=\"tttt\""), ecOPRT_TYPE_CONFLICT); if (iStat == 0) mu::console() << _T("passed") << endl; else mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl; return iStat; } //--------------------------------------------------------------------------- void ParserTester::AddTest(testfun_type a_pFun) { m_vTestFun.push_back(a_pFun); } //--------------------------------------------------------------------------- int ParserTester::Run() { int iStat = 0; try { for (int i = 0; i < (int)m_vTestFun.size(); ++i) iStat += (this->*m_vTestFun[i])(); } catch (Parser::exception_type& e) { mu::console() << "\n" << e.GetMsg() << endl; mu::console() << e.GetToken() << endl; Abort(); } catch (std::exception& e) { mu::console() << e.what() << endl; Abort(); } catch (...) { mu::console() << "Internal error"; Abort(); } if (iStat == 0) { mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl; } else { mu::console() << "Test failed with " << iStat << " errors (" << ParserTester::c_iCount << " expressions)" << endl; } ParserTester::c_iCount = 0; return iStat; } //--------------------------------------------------------------------------- int ParserTester::ThrowTest(const string_type& a_str, int a_iErrc, bool a_expectedToFail) { ParserTester::c_iCount++; try { value_type fVal[] = { 1,1,1 }; Parser p; p.DefineVar(_T("a"), &fVal[0]); p.DefineVar(_T("b"), &fVal[1]); p.DefineVar(_T("c"), &fVal[2]); p.DefinePostfixOprt(_T("{m}"), Milli); p.DefinePostfixOprt(_T("m"), Milli); p.DefineFun(_T("ping"), Ping); p.DefineFun(_T("valueof"), ValueOf); p.DefineFun(_T("strfun1"), StrFun1); p.DefineFun(_T("strfun2"), StrFun2); p.DefineFun(_T("strfun3"), StrFun3); p.DefineFun(_T("strfun4"), StrFun4); p.DefineFun(_T("strfun5"), StrFun5); p.DefineFun(_T("strfun6"), StrFun6); p.SetExpr(a_str); // p.EnableDebugDump(1, 0); p.Eval(); } catch (ParserError& e) { // output the formula in case of an failed test if (a_expectedToFail == false || (a_expectedToFail == true && a_iErrc != e.GetCode())) { mu::console() << _T("\n ") << _T("Expression: ") << a_str << _T(" Code:") << e.GetCode() << _T("(") << e.GetMsg() << _T(")") << _T(" Expected:") << a_iErrc; } return (a_iErrc == e.GetCode()) ? 0 : 1; } // if a_expectedToFail == false no exception is expected bool bRet((a_expectedToFail == false) ? 0 : 1); if (bRet == 1) { mu::console() << _T("\n ") << _T("Expression: ") << a_str << _T(" did evaluate; Expected error:") << a_iErrc; } return bRet; } //--------------------------------------------------------------------------- /** \brief Evaluate a tet expression. \return 1 in case of a failure, 0 otherwise. */ int ParserTester::EqnTestWithVarChange(const string_type& a_str, double a_fVar1, double a_fRes1, double a_fVar2, double a_fRes2) { ParserTester::c_iCount++; try { value_type fVal[2] = { -999, -999 }; // should be equal Parser p; value_type var = 0; // variable p.DefineVar(_T("a"), &var); p.SetExpr(a_str); var = a_fVar1; fVal[0] = p.Eval(); var = a_fVar2; fVal[1] = p.Eval(); if (fabs(a_fRes1 - fVal[0]) > 0.0000000001) throw std::runtime_error("incorrect result (first pass)"); if (fabs(a_fRes2 - fVal[1]) > 0.0000000001) throw std::runtime_error("incorrect result (second pass)"); } catch (Parser::exception_type& e) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")"); return 1; } catch (std::exception& e) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")"); return 1; // always return a failure since this exception is not expected } catch (...) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); return 1; // exceptions other than ParserException are not allowed } return 0; } //--------------------------------------------------------------------------- /** \brief Evaluate a tet expression. \return 1 in case of a failure, 0 otherwise. */ int ParserTester::EqnTest(const string_type& a_str, double a_fRes, bool a_fPass) { ParserTester::c_iCount++; int iRet(0); value_type fVal[6] = { -999, -998, -997, -996, -995, -994 }; // initially should be different try { std::unique_ptr p1; Parser p2, p3; // three parser objects // they will be used for testing copy and assignment operators // p1 is a pointer since i'm going to delete it in order to test if // parsers after copy construction still refer to members of it. // !! If this is the case this function will crash !! p1.reset(new mu::Parser()); // Add constants p1->DefineConst(_T("pi"), MathImpl::CONST_PI); p1->DefineConst(_T("e"), MathImpl::CONST_E); p1->DefineConst(_T("const"), 1); p1->DefineConst(_T("const1"), 2); p1->DefineConst(_T("const2"), 3); // string constants p1->DefineStrConst(_T("str1"), _T("1.11")); p1->DefineStrConst(_T("str2"), _T("2.22")); // variables value_type vVarVal[] = { 1, 2, 3, -2 }; p1->DefineVar(_T("a"), &vVarVal[0]); p1->DefineVar(_T("aa"), &vVarVal[1]); p1->DefineVar(_T("b"), &vVarVal[1]); p1->DefineVar(_T("c"), &vVarVal[2]); p1->DefineVar(_T("d"), &vVarVal[3]); // custom value ident functions p1->AddValIdent(&ParserTester::IsHexVal); // functions p1->DefineFun(_T("ping"), Ping); p1->DefineFun(_T("f0"), f0); // no parameter p1->DefineFun(_T("f1of1"), f1of1); // one parameter p1->DefineFun(_T("f1of2"), f1of2); // two parameter p1->DefineFun(_T("f2of2"), f2of2); p1->DefineFun(_T("f1of3"), f1of3); // three parameter p1->DefineFun(_T("f2of3"), f2of3); p1->DefineFun(_T("f3of3"), f3of3); p1->DefineFun(_T("f1of4"), f1of4); // four parameter p1->DefineFun(_T("f2of4"), f2of4); p1->DefineFun(_T("f3of4"), f3of4); p1->DefineFun(_T("f4of4"), f4of4); p1->DefineFun(_T("f1of5"), f1of5); // five parameter p1->DefineFun(_T("f2of5"), f2of5); p1->DefineFun(_T("f3of5"), f3of5); p1->DefineFun(_T("f4of5"), f4of5); p1->DefineFun(_T("f5of5"), f5of5); // binary operators p1->DefineOprt(_T("add"), add, 0); p1->DefineOprt(_T("++"), add, 0); p1->DefineOprt(_T("&"), land, prLAND); // sample functions p1->DefineFun(_T("min"), Min); p1->DefineFun(_T("max"), Max); p1->DefineFun(_T("sum"), Sum); p1->DefineFun(_T("valueof"), ValueOf); p1->DefineFun(_T("atof"), StrToFloat); p1->DefineFun(_T("strfun1"), StrFun1); p1->DefineFun(_T("strfun2"), StrFun2); p1->DefineFun(_T("strfun3"), StrFun3); p1->DefineFun(_T("strfun4"), StrFun4); p1->DefineFun(_T("strfun5"), StrFun5); p1->DefineFun(_T("strfun6"), StrFun6); p1->DefineFun(_T("lastArg"), LastArg); p1->DefineFun(_T("firstArg"), FirstArg); p1->DefineFun(_T("order"), FirstArg); // functions with user data p1->DefineFunUserData(_T("funud0_8"), FunUd0, reinterpret_cast(8)); p1->DefineFunUserData(_T("funud1_16"), FunUd1, reinterpret_cast(16)); p1->DefineFunUserData(_T("funud2_24"), FunUd2, reinterpret_cast(24)); p1->DefineFunUserData(_T("funud10_32"), FunUd10, reinterpret_cast(32)); p1->DefineFunUserData(_T("funud0_9"), FunUd0, reinterpret_cast(9)); p1->DefineFunUserData(_T("funud1_17"), FunUd1, reinterpret_cast(17)); p1->DefineFunUserData(_T("funud2_25"), FunUd2, reinterpret_cast(25)); p1->DefineFunUserData(_T("funud10_33"), FunUd10, reinterpret_cast(33)); p1->DefineFunUserData(_T("strfunud3_10"), StrFunUd3, reinterpret_cast(10)); p1->DefineFunUserData(_T("sumud_100"), SumUd, reinterpret_cast(100)); // infix / postfix operator // Note: Identifiers used here do not have any meaning // they are mere placeholders to test certain features. p1->DefineInfixOprt(_T("$"), sign, prPOW + 1); // sign with high priority p1->DefineInfixOprt(_T("~"), plus2); // high priority p1->DefineInfixOprt(_T("~~"), plus2); p1->DefinePostfixOprt(_T("{m}"), Milli); p1->DefinePostfixOprt(_T("{M}"), Mega); p1->DefinePostfixOprt(_T("m"), Milli); p1->DefinePostfixOprt(_T("meg"), Mega); p1->DefinePostfixOprt(_T("#"), times3); p1->DefinePostfixOprt(_T("'"), sqr); p1->SetExpr(a_str); // Test bytecode integrity // String parsing and bytecode parsing must yield the same result fVal[0] = p1->Eval(); // result from stringparsing fVal[1] = p1->Eval(); // result from bytecode if (fVal[0] != fVal[1]) throw Parser::exception_type(_T("Bytecode / string parsing mismatch.")); // Test copy and assignment operators try { // Test copy constructor std::vector vParser; vParser.push_back(*(p1.get())); mu::Parser p4 = vParser[0]; // take parser from vector // destroy the originals from p2 vParser.clear(); // delete the vector p1.reset(nullptr); fVal[2] = p4.Eval(); // Test assignment operator // additionally disable Optimizer this time mu::Parser p5; p5 = p4; p5.EnableOptimizer(false); fVal[3] = p5.Eval(); // Test Eval function for multiple return values // use p2 since it has the optimizer enabled! int nNum; p4.SetExpr(a_str); // reset bytecode to trigger #94 (https://github.com/beltoforion/muparser/issues/94) value_type* v = p4.Eval(nNum); fVal[4] = v[nNum - 1]; v = p4.Eval(nNum); fVal[5] = v[nNum - 1]; } catch (std::exception& e) { mu::console() << _T("\n ") << e.what() << _T("\n"); } // limited floating point accuracy requires the following test bool bCloseEnough(true); for (unsigned i = 0; i < sizeof(fVal) / sizeof(value_type); ++i) { bCloseEnough &= (fabs(a_fRes - fVal[i]) <= fabs(fVal[i] * 0.00001)); // The tests equations never result in infinity, if they do thats a bug. // reference: // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825 #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4127) #endif if (std::numeric_limits::has_infinity) #ifdef _MSC_VER #pragma warning(pop) #endif { bCloseEnough &= (fabs(fVal[i]) != numeric_limits::infinity()); } } iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1; if (iRet == 1) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (incorrect result; expected: ") << a_fRes << _T(" ;calculated: ") << fVal[0] << _T(",") << fVal[1] << _T(",") << fVal[2] << _T(",") << fVal[3] << _T(",") << fVal[4] << _T(",") << fVal[5] << _T(")."); } } catch (Parser::exception_type& e) { if (a_fPass) { if (fVal[0] != fVal[2] && fVal[0] != -999 && fVal[1] != -998) mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (copy construction)"); else mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")"); return 1; } } catch (std::exception& e) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")"); return 1; // always return a failure since this exception is not expected } catch (...) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); return 1; // exceptions other than ParserException are not allowed } return iRet; } //--------------------------------------------------------------------------- int ParserTester::EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass) { ParserTester::c_iCount++; value_type vVarVal[] = { 1, 2, 3 }; // variable values int iRet(0); try { value_type fVal[2] = { -99, -999 }; // results: initially should be different ParserInt p; p.DefineConst(_T("const1"), 1); p.DefineConst(_T("const2"), 2); p.DefineVar(_T("a"), &vVarVal[0]); p.DefineVar(_T("b"), &vVarVal[1]); p.DefineVar(_T("c"), &vVarVal[2]); p.SetExpr(a_str); fVal[0] = p.Eval(); // result from stringparsing fVal[1] = p.Eval(); // result from bytecode if (fVal[0] != fVal[1]) throw Parser::exception_type(_T("Bytecode corrupt.")); iRet = ((a_fRes == fVal[0] && a_fPass) || (a_fRes != fVal[0] && !a_fPass)) ? 0 : 1; if (iRet == 1) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (incorrect result; expected: ") << a_fRes << _T(" ;calculated: ") << fVal[0] << _T(")."); } } catch (Parser::exception_type& e) { if (a_fPass) { mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg(); iRet = 1; } } catch (...) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); iRet = 1; // exceptions other than ParserException are not allowed } return iRet; } //--------------------------------------------------------------------------- /** \brief Test an expression in Bulk Mode. */ int ParserTester::EqnTestBulk(const string_type& a_str, double a_fRes[4], bool a_fPass) { ParserTester::c_iCount++; // Define Bulk Variables int nBulkSize = 4; value_type vVariableA[] = { 1, 2, 3, 4 }; // variable values value_type vVariableB[] = { 2, 2, 2, 2 }; // variable values value_type vVariableC[] = { 3, 3, 3, 3 }; // variable values value_type vResults[] = { 0, 0, 0, 0 }; // variable values int iRet(0); try { Parser p; p.DefineConst(_T("const1"), 1); p.DefineConst(_T("const2"), 2); p.DefineVar(_T("a"), vVariableA); p.DefineVar(_T("b"), vVariableB); p.DefineVar(_T("c"), vVariableC); p.SetExpr(a_str); p.Eval(vResults, nBulkSize); bool bCloseEnough(true); for (int i = 0; i < nBulkSize; ++i) { bCloseEnough &= (fabs(a_fRes[i] - vResults[i]) <= fabs(a_fRes[i] * 0.00001)); } iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1; if (iRet == 1) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (incorrect result; expected: {") << a_fRes[0] << _T(",") << a_fRes[1] << _T(",") << a_fRes[2] << _T(",") << a_fRes[3] << _T("}") << _T(" ;calculated: ") << vResults[0] << _T(",") << vResults[1] << _T(",") << vResults[2] << _T(",") << vResults[3] << _T("}"); } } catch (Parser::exception_type& e) { if (a_fPass) { mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg(); iRet = 1; } } catch (...) { mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)"); iRet = 1; // exceptions other than ParserException are not allowed } return iRet; } //--------------------------------------------------------------------------- /** \brief Internal error in test class Test is going to be aborted. */ void ParserTester::Abort() const { mu::console() << _T("Test failed (internal error in test class)") << endl; while (!getchar()); exit(-1); } } // namespace test } // namespace mu beltoforion-muparser-59e0ce1/src/muParserTokenReader.cpp000066400000000000000000000712141433271236700235370ustar00rootroot00000000000000/* _____ __ _____________ _______ ______ ___________ / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |__|_| /____/| __(____ /__| /____ >\___ >__| \/ |__| \/ \/ \/ Copyright (C) 2004 - 2022 Ingo Berg Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "muParserTokenReader.h" #include "muParserBase.h" #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 26812) #endif /** \file \brief This file contains the parser token reader implementation. */ namespace mu { // Forward declaration class ParserBase; /** \brief Copy constructor. \sa Assign \throw nothrow */ ParserTokenReader::ParserTokenReader(const ParserTokenReader& a_Reader) { Assign(a_Reader); } /** \brief Assignment operator. Self assignment will be suppressed otherwise #Assign is called. \param a_Reader Object to copy to this token reader. \throw nothrow */ ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader& a_Reader) { if (&a_Reader != this) Assign(a_Reader); return *this; } /** \brief Assign state of a token reader to this token reader. \param a_Reader Object from which the state should be copied. \throw nothrow */ void ParserTokenReader::Assign(const ParserTokenReader& a_Reader) { m_pParser = a_Reader.m_pParser; m_strFormula = a_Reader.m_strFormula; m_iPos = a_Reader.m_iPos; m_iSynFlags = a_Reader.m_iSynFlags; m_UsedVar = a_Reader.m_UsedVar; m_pFunDef = a_Reader.m_pFunDef; m_pConstDef = a_Reader.m_pConstDef; m_pVarDef = a_Reader.m_pVarDef; m_pStrVarDef = a_Reader.m_pStrVarDef; m_pPostOprtDef = a_Reader.m_pPostOprtDef; m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; m_pOprtDef = a_Reader.m_pOprtDef; m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar; m_vIdentFun = a_Reader.m_vIdentFun; m_pFactory = a_Reader.m_pFactory; m_pFactoryData = a_Reader.m_pFactoryData; m_bracketStack = a_Reader.m_bracketStack; m_cArgSep = a_Reader.m_cArgSep; m_fZero = a_Reader.m_fZero; m_lastTok = a_Reader.m_lastTok; } /** \brief Constructor. Create a Token reader and bind it to a parser object. \pre [assert] a_pParser may not be NULL \post #m_pParser==a_pParser \param a_pParent Parent parser object of the token reader. */ ParserTokenReader::ParserTokenReader(ParserBase* a_pParent) :m_pParser(a_pParent) , m_strFormula() , m_iPos(0) , m_iSynFlags(0) , m_bIgnoreUndefVar(false) , m_pFunDef(nullptr) , m_pPostOprtDef(nullptr) , m_pInfixOprtDef(nullptr) , m_pOprtDef(nullptr) , m_pConstDef(nullptr) , m_pStrVarDef(nullptr) , m_pVarDef(nullptr) , m_pFactory(nullptr) , m_pFactoryData(nullptr) , m_vIdentFun() , m_UsedVar() , m_fZero(0) , m_bracketStack() , m_lastTok() , m_cArgSep(',') { MUP_ASSERT(m_pParser != nullptr); SetParent(m_pParser); } /** \brief Create instance of a ParserTokenReader identical with this and return its pointer. This is a factory method the calling function must take care of the object destruction. \return A new ParserTokenReader object. \throw nothrow */ ParserTokenReader* ParserTokenReader::Clone(ParserBase* a_pParent) const { std::unique_ptr ptr(new ParserTokenReader(*this)); ptr->SetParent(a_pParent); return ptr.release(); } ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type& tok) { m_lastTok = tok; return m_lastTok; } void ParserTokenReader::AddValIdent(identfun_type a_pCallback) { // Use push_front is used to give user defined callbacks a higher priority than // the built in ones. Otherwise reading hex numbers would not work // since the "0" in "0xff" would always be read first making parsing of // the rest impossible. // reference: // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956 m_vIdentFun.push_front(a_pCallback); } void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void* pUserData) { m_pFactory = a_pFactory; m_pFactoryData = pUserData; } /** \brief Return the current position of the token reader in the formula string. \return #m_iPos \throw nothrow */ int ParserTokenReader::GetPos() const { return m_iPos; } /** \brief Return a reference to the formula. \return #m_strFormula \throw nothrow */ const string_type& ParserTokenReader::GetExpr() const { return m_strFormula; } /** \brief Return a map containing the used variables only. */ varmap_type& ParserTokenReader::GetUsedVar() { return m_UsedVar; } /** \brief Initialize the token Reader. Sets the formula position index to zero and set Syntax flags to default for initial formula parsing. \pre [assert] triggered if a_szFormula==0 */ void ParserTokenReader::SetFormula(const string_type& a_strFormula) { m_strFormula = a_strFormula; ReInit(); } /** \brief Set Flag that controls behaviour in case of undefined variables being found. If true, the parser does not throw an exception if an undefined variable is found. otherwise it does. This variable is used internally only! It suppresses a "undefined variable" exception in GetUsedVar(). Those function should return a complete list of variables including those the are not defined by the time of it's call. */ void ParserTokenReader::IgnoreUndefVar(bool bIgnore) { m_bIgnoreUndefVar = bIgnore; } /** \brief Reset the token reader to the start of the formula. The syntax flags will be reset to a value appropriate for the start of a formula. \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR \throw nothrow \sa ESynCodes */ void ParserTokenReader::ReInit() { m_iPos = 0; m_iSynFlags = sfSTART_OF_LINE; m_bracketStack = std::stack(); m_UsedVar.clear(); m_lastTok = token_type(); } /** \brief Read the next token from the string. */ ParserTokenReader::token_type ParserTokenReader::ReadNextToken() { MUP_ASSERT(m_pParser != nullptr); const char_type* szExpr = m_strFormula.c_str(); token_type tok; // Ignore all non printable characters when reading the expression while (szExpr[m_iPos] > 0 && szExpr[m_iPos] <= 0x20) { // 14-31 are control characters. I donÄt want to have to deal with such strings at all! // (see https://en.cppreference.com/w/cpp/string/byte/isprint) if (szExpr[m_iPos] >= 14 && szExpr[m_iPos] <= 31) Error(ecINVALID_CHARACTERS_FOUND, m_iPos); ++m_iPos; } // Check for end of formula if (IsEOF(tok)) return SaveBeforeReturn(tok); // Check for user defined binary operator if (IsOprt(tok)) return SaveBeforeReturn(tok); // Check for function token if (IsFunTok(tok)) return SaveBeforeReturn(tok); // Check built in operators / tokens if (IsBuiltIn(tok)) return SaveBeforeReturn(tok); // Check for function argument separators if (IsArgSep(tok)) return SaveBeforeReturn(tok); // Check for values / constant tokens if (IsValTok(tok)) return SaveBeforeReturn(tok); // Check for variable tokens if (IsVarTok(tok)) return SaveBeforeReturn(tok); // Check for string variables if (IsStrVarTok(tok)) return SaveBeforeReturn(tok); // Check for String tokens if (IsString(tok)) return SaveBeforeReturn(tok); // Check for unary operators if (IsInfixOpTok(tok)) return SaveBeforeReturn(tok); // Check for unary operators if (IsPostOpTok(tok)) return SaveBeforeReturn(tok); // Check String for undefined variable token. Done only if a // flag is set indicating to ignore undefined variables. // This is a way to conditionally avoid an error if // undefined variables occur. // (The GetUsedVar function must suppress the error for // undefined variables in order to collect all variable // names including the undefined ones.) if ((m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok)) return SaveBeforeReturn(tok); // Check for unknown token // // !!! From this point on there is no exit without an exception possible... // string_type strTok; auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos); if (iEnd != m_iPos) Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos)); return token_type(); // never reached } void ParserTokenReader::SetParent(ParserBase* a_pParent) { m_pParser = a_pParent; m_pFunDef = &a_pParent->m_FunDef; m_pOprtDef = &a_pParent->m_OprtDef; m_pInfixOprtDef = &a_pParent->m_InfixOprtDef; m_pPostOprtDef = &a_pParent->m_PostOprtDef; m_pVarDef = &a_pParent->m_VarDef; m_pStrVarDef = &a_pParent->m_StrVarDef; m_pConstDef = &a_pParent->m_ConstDef; } /** \brief Extract all characters that belong to a certain charset. \param a_szCharSet [in] Const char array of the characters allowed in the token. \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet. \param a_iPos [in] Position in the string from where to start reading. \return The Position of the first character not listed in a_szCharSet. \throw nothrow */ int ParserTokenReader::ExtractToken(const char_type* a_szCharSet, string_type& a_sTok, std::size_t a_iPos) const { auto iEnd = m_strFormula.find_first_not_of(a_szCharSet, a_iPos); if (iEnd == string_type::npos) iEnd = m_strFormula.length(); // Assign token string if there was something found if (a_iPos != iEnd) a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); return static_cast(iEnd); } /** \brief Check Expression for the presence of a binary operator token. Userdefined binary operator "++" gives inconsistent parsing result for the equations "a++b" and "a ++ b" if alphabetic characters are allowed in operator tokens. To avoid this this function checks specifically for operator tokens. */ int ParserTokenReader::ExtractOperatorToken(string_type& a_sTok, std::size_t a_iPos) const { // Changed as per Issue 6: https://code.google.com/p/muparser/issues/detail?id=6 auto iEnd = m_strFormula.find_first_not_of(m_pParser->ValidOprtChars(), a_iPos); if (iEnd == string_type::npos) iEnd = m_strFormula.length(); // Assign token string if there was something found if (a_iPos != iEnd) { a_sTok = string_type(m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); return static_cast(iEnd); } else { // There is still the chance of having to deal with an operator consisting exclusively // of alphabetic characters. return ExtractToken(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), a_sTok, (std::size_t)a_iPos); } } /** \brief Check if a built in operator or other token can be found \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. \return true if an operator token has been found. */ bool ParserTokenReader::IsBuiltIn(token_type& a_Tok) { const char_type** const pOprtDef = m_pParser->GetOprtDef(), * const szFormula = m_strFormula.c_str(); // Compare token with function and operator strings // check string for operator/function for (int i = 0; pOprtDef[i]; i++) { std::size_t len(std::char_traits::length(pOprtDef[i])); if (string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len)) { switch (i) { case cmLAND: case cmLOR: case cmLT: case cmGT: case cmLE: case cmGE: case cmNEQ: case cmEQ: case cmADD: case cmSUB: case cmMUL: case cmDIV: case cmPOW: case cmASSIGN: // The assignment operator need special treatment if (i == cmASSIGN && m_iSynFlags & noASSIGN) Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); if (!m_pParser->HasBuiltInOprt()) continue; if (m_iSynFlags & noOPT) { // Maybe its an infix operator not an operator // Both operator types can share characters in // their identifiers if (IsInfixOpTok(a_Tok)) return true; Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); } m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE | noEND; break; case cmBO: if (m_iSynFlags & noBO) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); if (m_lastTok.GetCode() == cmFUNC) m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; else m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; m_bracketStack.push(cmBO); break; case cmBC: if (m_iSynFlags & noBC) Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; if (!m_bracketStack.empty()) m_bracketStack.pop(); else Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); break; case cmELSE: if (m_iSynFlags & noELSE) Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE | noSTR; break; case cmIF: if (m_iSynFlags & noIF) Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE | noSTR; break; default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... Error(ecINTERNAL_ERROR); } // switch operator id m_iPos += (int)len; a_Tok.Set((ECmdCode)i, pOprtDef[i]); return true; } // if operator string found } // end of for all operator strings return false; } bool ParserTokenReader::IsArgSep(token_type& a_Tok) { const char_type* szFormula = m_strFormula.c_str(); if (szFormula[m_iPos] == m_cArgSep) { // copy the separator into null terminated string char_type szSep[2]; szSep[0] = m_cArgSep; szSep[1] = 0; if (m_iSynFlags & noARG_SEP) Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep); m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN; m_iPos++; a_Tok.Set(cmARG_SEP, szSep); return true; } return false; } /** \brief Check for End of Formula. \return true if an end of formula is found false otherwise. \param a_Tok [out] If an eof is found the corresponding token will be stored there. \throw nothrow \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok */ bool ParserTokenReader::IsEOF(token_type& a_Tok) { const char_type* szFormula = m_strFormula.c_str(); // check for EOF if (!szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/) { if (m_iSynFlags & noEND) Error(ecUNEXPECTED_EOF, m_iPos); if (!m_bracketStack.empty()) Error(ecMISSING_PARENS, m_iPos, _T(")")); m_iSynFlags = 0; a_Tok.Set(cmEND); return true; } return false; } /** \brief Check if a string position contains a unary infix operator. \return true if a function token has been found false otherwise. */ bool ParserTokenReader::IsInfixOpTok(token_type& a_Tok) { string_type sTok; auto iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, (std::size_t)m_iPos); if (iEnd == m_iPos) return false; // iterate over all postfix operator strings funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin(); for (; it != m_pInfixOprtDef->rend(); ++it) { if (sTok.find(it->first) != 0) continue; a_Tok.Set(it->second, it->first); m_iPos += (int)it->first.length(); if (m_iSynFlags & noINFIXOP) Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN | noARG_SEP; return true; } return false; /* a_Tok.Set(item->second, sTok); m_iPos = (int)iEnd; if (m_iSynFlags & noINFIXOP) Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; return true; */ } /** \brief Check whether the token at a given position is a function token. \param a_Tok [out] If a value token is found it will be placed here. \throw ParserException if Syntaxflags do not allow a function at a_iPos \return true if a function token has been found false otherwise. \pre [assert] m_pParser!=0 */ bool ParserTokenReader::IsFunTok(token_type& a_Tok) { string_type strTok; auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos); if (iEnd == m_iPos) return false; funmap_type::const_iterator item = m_pFunDef->find(strTok); if (item == m_pFunDef->end()) return false; // Check if the next sign is an opening bracket const char_type* szFormula = m_strFormula.c_str(); if (szFormula[iEnd] != '(') return false; a_Tok.Set(item->second, strTok); m_iPos = (int)iEnd; if (m_iSynFlags & noFUN) Error(ecUNEXPECTED_FUN, m_iPos - (int)a_Tok.GetAsString().length(), a_Tok.GetAsString()); m_iSynFlags = noANY ^ noBO; return true; } /** \brief Check if a string position contains a binary operator. \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. \return true if an operator token has been found. */ bool ParserTokenReader::IsOprt(token_type& a_Tok) { const char_type* const szExpr = m_strFormula.c_str(); string_type strTok; auto iEnd = ExtractOperatorToken(strTok, (std::size_t)m_iPos); if (iEnd == m_iPos) return false; // Check if the operator is a built in operator, if so ignore it here const char_type** const pOprtDef = m_pParser->GetOprtDef(); for (int i = 0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i) { if (string_type(pOprtDef[i]) == strTok) return false; } // Note: // All tokens in oprt_bin_maptype are have been sorted by their length // Long operators must come first! Otherwise short names (like: "add") that // are part of long token names (like: "add123") will be found instead // of the long ones. // Length sorting is done with ascending length so we use a reverse iterator here. funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin(); for (; it != m_pOprtDef->rend(); ++it) { const string_type& sID = it->first; if (sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length())) { a_Tok.Set(it->second, strTok); // operator was found if (m_iSynFlags & noOPT) { // An operator was found but is not expected to occur at // this position of the formula, maybe it is an infix // operator, not a binary operator. Both operator types // can share characters in their identifiers. if (IsInfixOpTok(a_Tok)) return true; else { // nope, no infix operator return false; //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); } } m_iPos += (int)sID.length(); m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noASSIGN; return true; } } return false; } /** \brief Check if a string position contains a unary post value operator. */ bool ParserTokenReader::IsPostOpTok(token_type& a_Tok) { // Do not check for postfix operators if they are not allowed at // the current expression index. // // This will fix the bug reported here: // // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979 // if (m_iSynFlags & noPOSTOP) return false; // // Tricky problem with equations like "3m+5": // m is a postfix operator, + is a valid sign for postfix operators and // for binary operators parser detects "m+" as operator string and // finds no matching postfix operator. // // This is a special case so this routine slightly differs from the other // token readers. // Test if there could be a postfix operator string_type sTok; auto iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, (std::size_t)m_iPos); if (iEnd == m_iPos) return false; // iterate over all postfix operator strings funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin(); for (; it != m_pPostOprtDef->rend(); ++it) { if (sTok.find(it->first) != 0) continue; a_Tok.Set(it->second, sTok); m_iPos += (int)it->first.length(); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; return true; } return false; } /** \brief Check whether the token at a given position is a value token. Value tokens are either values or constants. \param a_Tok [out] If a value token is found it will be placed here. \return true if a value token has been found. */ bool ParserTokenReader::IsValTok(token_type& a_Tok) { MUP_ASSERT(m_pConstDef != nullptr); MUP_ASSERT(m_pParser != nullptr); string_type strTok; value_type fVal(0); // 2.) Check for user defined constant // Read everything that could be a constant name auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos); if (iEnd != m_iPos) { valmap_type::const_iterator item = m_pConstDef->find(strTok); if (item != m_pConstDef->end()) { m_iPos = iEnd; a_Tok.SetVal(item->second, strTok); if (m_iSynFlags & noVAL) Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } } // 3.call the value recognition functions provided by the user // Call user defined value recognition functions std::list::const_iterator item = m_vIdentFun.begin(); for (item = m_vIdentFun.begin(); item != m_vIdentFun.end(); ++item) { int iStart = m_iPos; if ((*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal) == 1) { // 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2 strTok.assign(m_strFormula.c_str(), iStart, (std::size_t)m_iPos - iStart); if (m_iSynFlags & noVAL) Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); a_Tok.SetVal(fVal, strTok); m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } } return false; } /** \brief Check wheter a token at a given position is a variable token. \param a_Tok [out] If a variable token has been found it will be placed here. \return true if a variable token has been found. */ bool ParserTokenReader::IsVarTok(token_type& a_Tok) { if (m_pVarDef->empty()) return false; string_type strTok; auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos); if (iEnd == m_iPos) return false; varmap_type::const_iterator item = m_pVarDef->find(strTok); if (item == m_pVarDef->end()) return false; if (m_iSynFlags & noVAR) Error(ecUNEXPECTED_VAR, m_iPos, strTok); m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd); m_iPos = iEnd; a_Tok.SetVar(item->second, strTok); m_UsedVar[item->first] = item->second; // Add variable to used-var-list m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR; // Zur Info hier die SynFlags von IsVal(): // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; return true; } bool ParserTokenReader::IsStrVarTok(token_type& a_Tok) { if (!m_pStrVarDef || m_pStrVarDef->empty()) return false; string_type strTok; auto iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos); if (iEnd == m_iPos) return false; strmap_type::const_iterator item = m_pStrVarDef->find(strTok); if (item == m_pStrVarDef->end()) return false; if (m_iSynFlags & noSTR) Error(ecUNEXPECTED_VAR, m_iPos, strTok); m_iPos = iEnd; if (!m_pParser->m_vStringVarBuf.size()) Error(ecINTERNAL_ERROR); a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size()); m_iSynFlags = noANY ^ (noBC | noOPT | noEND | noARG_SEP); return true; } /** \brief Check wheter a token at a given position is an undefined variable. \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here. \return true if a variable token has been found. \throw nothrow */ bool ParserTokenReader::IsUndefVarTok(token_type& a_Tok) { string_type strTok; auto iEnd(ExtractToken(m_pParser->ValidNameChars(), strTok, (std::size_t)m_iPos)); if (iEnd == m_iPos) return false; if (m_iSynFlags & noVAR) { // 20061021 added token string strTok instead of a_Tok.GetAsString() as the // token identifier. // related bug report: // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok); } // If a factory is available implicitely create new variables if (m_pFactory) { value_type* fVar = m_pFactory(strTok.c_str(), m_pFactoryData); a_Tok.SetVar(fVar, strTok); // Do not use m_pParser->DefineVar( strTok, fVar ); // in order to define the new variable, it will clear the // m_UsedVar array which will kill previously defined variables // from the list // This is safe because the new variable can never override an existing one // because they are checked first! (*m_pVarDef)[strTok] = fVar; m_UsedVar[strTok] = fVar; // Add variable to used-var-list } else { a_Tok.SetVar((value_type*)&m_fZero, strTok); m_UsedVar[strTok] = 0; // Add variable to used-var-list } m_iPos = iEnd; // Call the variable factory in order to let it define a new parser variable m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; return true; } /** \brief Check wheter a token at a given position is a string. \param a_Tok [out] If a variable token has been found it will be placed here. \return true if a string token has been found. \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok \throw nothrow */ bool ParserTokenReader::IsString(token_type& a_Tok) { if (m_strFormula[m_iPos] != '"') return false; string_type strBuf(&m_strFormula[(std::size_t)m_iPos + 1]); std::size_t iEnd(0), iSkip(0); // parser over escaped '\"' end replace them with '"' for (iEnd = (int)strBuf.find(_T('\"')); iEnd != 0 && iEnd != string_type::npos; iEnd = (int)strBuf.find(_T('\"'), iEnd)) { if (strBuf[iEnd - 1] != '\\') break; strBuf.replace(iEnd - 1, 2, _T("\"")); iSkip++; } if (iEnd == string_type::npos) Error(ecUNTERMINATED_STRING, m_iPos, _T("\"")); string_type strTok(strBuf.begin(), strBuf.begin() + iEnd); if (m_iSynFlags & noSTR) Error(ecUNEXPECTED_STR, m_iPos, strTok); m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size()); m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 for quotes; +iSkip for escape characters m_iSynFlags = noANY ^ (noARG_SEP | noBC | noOPT | noEND); return true; } /** \brief Create an error containing the parse error position. This function will create an Parser Exception object containing the error text and its position. \param a_iErrc [in] The error code of type #EErrorCodes. \param a_iPos [in] The position where the error was detected. \param a_strTok [in] The token string representation associated with the error. \throw ParserException always throws thats the only purpose of this function. */ void ParserTokenReader::Error(EErrorCodes a_iErrc, int a_iPos, const string_type& a_sTok) const { m_pParser->Error(a_iErrc, a_iPos, a_sTok); } void ParserTokenReader::SetArgSep(char_type cArgSep) { m_cArgSep = cArgSep; } char_type ParserTokenReader::GetArgSep() const { return m_cArgSep; } } // namespace mu #if defined(_MSC_VER) #pragma warning(pop) #endif beltoforion-muparser-59e0ce1/test/000077500000000000000000000000001433271236700172745ustar00rootroot00000000000000beltoforion-muparser-59e0ce1/test/t_ParserTest.cpp000066400000000000000000000001761433271236700224230ustar00rootroot00000000000000#include "muParserTest.h" using namespace mu::Test; int main(int, char**) { ParserTester tester; return tester.Run(); }