diff --git a/muparser-2.2.5_GR/Changes.txt b/muparser-2.2.5_GR/Changes.txt new file mode 100755 index 0000000..abe9697 --- /dev/null +++ b/muparser-2.2.5_GR/Changes.txt @@ -0,0 +1,557 @@ +####################################################################### +# # +# # +# __________ # +# _____ __ __\______ \_____ _______ ______ ____ _______ # +# / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ # +# | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ # +# |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| # +# \/ \/ \/ \/ # +# Fast math parser Library # +# # +# Copyright (C) 2015 Ingo Berg # +# # +# Web: muparser.beltoforion.de # +# e-mail: muparser@beltoforion.de # +# # +# # +####################################################################### + + +History: +-------- + +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) + * Seperator 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 (Maintainance 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 cant 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 Assignement operator. + + Functionality + * New built in operator: xor; Logical xor. + * New built in operator: Assignement 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 assignement. + * 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 seperate 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 diff --git a/muparser-2.2.5_GR/License.txt b/muparser-2.2.5_GR/License.txt new file mode 100755 index 0000000..c4c0d2b --- /dev/null +++ b/muparser-2.2.5_GR/License.txt @@ -0,0 +1,35 @@ +####################################################################### +# # +# # +# __________ # +# _____ __ __\______ \_____ _______ ______ ____ _______ # +# / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ # +# | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ # +# |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| # +# \/ \/ \/ \/ # +# Fast math parser Library # +# # +# Copyright (C) 2011 Ingo Berg # +# # +# Web: muparser.beltoforion.de # +# e-mail: muparser@beltoforion.de # +# # +# # +####################################################################### + + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/muparser-2.2.5_GR/include/muParser.h b/muparser-2.2.5_GR/include/muParser.h new file mode 100755 index 0000000..39fe137 --- /dev/null +++ b/muparser-2.2.5_GR/include/muParser.h @@ -0,0 +1,115 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef MU_PARSER_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. + + + (C) 2011 Ingo Berg
+ muparser(at)beltoforion.de +
+ */ + /* final */ class Parser : public ParserBase + { + public: + + Parser(); + + virtual void InitCharSets(); + virtual void InitFun(); + virtual void InitConst(); + virtual void InitOprt(); + virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd); + + value_type Diff(value_type *a_Var, + value_type a_fPos, + value_type a_fEpsilon = 0) const; + + protected: + + // Trigonometric functions + static value_type Sin(value_type); + static value_type Cos(value_type); + static value_type Tan(value_type); + static value_type Tan2(value_type, value_type); + // arcus functions + static value_type ASin(value_type); + static value_type ACos(value_type); + static value_type ATan(value_type); + static value_type ATan2(value_type, value_type); + + // hyperbolic functions + static value_type Sinh(value_type); + static value_type Cosh(value_type); + static value_type Tanh(value_type); + // arcus hyperbolic functions + static value_type ASinh(value_type); + static value_type ACosh(value_type); + static value_type ATanh(value_type); + // Logarithm functions + static value_type Log2(value_type); // Logarithm Base 2 + static value_type Log10(value_type); // Logarithm Base 10 + static value_type Ln(value_type); // Logarithm Base e (natural logarithm) + // misc + static value_type Exp(value_type); + static value_type Abs(value_type); + static value_type Sqrt(value_type); + static value_type Rint(value_type); + static value_type Sign(value_type); + + // Prefix operators + // !!! Unary Minus is a MUST if you want to use negative signs !!! + static value_type UnaryMinus(value_type); + static value_type UnaryPlus(value_type); + + // Functions with variable number of arguments + static value_type Sum(const value_type*, int); // sum + static value_type Avg(const value_type*, int); // mean value + static value_type Min(const value_type*, int); // minimum + static value_type Max(const value_type*, int); // maximum + + static int IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal); + }; +} // namespace mu + +#endif + diff --git a/muparser-2.2.5_GR/include/muParserBase.h b/muparser-2.2.5_GR/include/muParserBase.h new file mode 100755 index 0000000..beb15bb --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserBase.h @@ -0,0 +1,317 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef MU_PARSER_BASE_H +#define MU_PARSER_BASE_H + +//--- Standard includes ------------------------------------------------------------------------ +#include +#include +#include +#include +#include +#include +#include + +//--- Parser includes -------------------------------------------------------------------------- +#include "muParserDef.h" +#include "muParserStack.h" +#include "muParserTokenReader.h" +#include "muParserBytecode.h" +#include "muParserError.h" + + +namespace mu +{ +/** \file + \brief This file contains the class definition of the muparser engine. +*/ + +//-------------------------------------------------------------------------------------------------- +/** \brief Mathematical expressions parser (base parser engine). + \author (C) 2013 Ingo Berg + + This is the implementation of a bytecode based mathematical expressions parser. + The formula will be parsed from string and converted into a bytecode. + 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 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 = 16; + + 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 = NULL); + + void SetDecSep(char_type cDecSep); + void SetThousandsSep(char_type cThousandsSep = 0); + void ResetLocale(); + + void EnableOptimizer(bool a_bIsOn=true); + void EnableBuiltInOprt(bool a_bIsOn=true); + + 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() ); + } + + 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 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; + + void Error(EErrorCodes a_iErrc, + int a_iPos = (int)mu::string_type::npos, + const string_type &a_strTok = string_type() ) const; + + protected: + + void Init(); + + virtual void InitCharSets() = 0; + virtual void InitFun() = 0; + virtual void InitConst() = 0; + virtual void InitOprt() = 0; + + virtual void 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: + + 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; + }; + + 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(ParserStack &a_stOpt, + ParserStack &a_stVal) const; + void ApplyBinOprt(ParserStack &a_stOpt, + ParserStack &a_stVal) const; + + void ApplyIfElse(ParserStack &a_stOpt, + ParserStack &a_stVal) const; + + void ApplyFunc(ParserStack &a_stOpt, + ParserStack &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 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 ParserStack &a_stVal, + const ParserStack &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::auto_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 + + mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses + + // 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 + +#endif + diff --git a/muparser-2.2.5_GR/include/muParserBytecode.h b/muparser-2.2.5_GR/include/muParserBytecode.h new file mode 100755 index 0000000..39ab39d --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserBytecode.h @@ -0,0 +1,141 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef MU_PARSER_BYTECODE_H +#define MU_PARSER_BYTECODE_H + +#include +#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; + int StackPos; + + union + { + struct //SValData + { + value_type *ptr; + value_type data; + value_type data2; + } Val; + + struct //SFunData + { + // Note: generic_fun_type is merely a placeholder. The real type could be + // anything between gun_type1 and fun_type9. I can't use a void + // pointer due to constraints in the ANSI standard which allows + // data pointers and function pointers to differ in size. + generic_fun_type ptr; + int argc; + int idx; + } Fun; + + struct //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. + + \author (C) 2004-2013 Ingo Berg +*/ +class ParserByteCode +{ +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_fun_type a_pFun, int a_iArgc); + void AddBulkFun(generic_fun_type a_pFun, int a_iArgc); + void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx); + + void EnableOptimizer(bool bStat); + + void Finalize(); + void clear(); + std::size_t GetMaxStackSize() const; + std::size_t GetSize() const; + + const SToken* GetBase() const; + void AsciiDump(); +}; + +} // namespace mu + +#endif + + diff --git a/muparser-2.2.5_GR/include/muParserCallback.h b/muparser-2.2.5_GR/include/muParserCallback.h new file mode 100755 index 0000000..ef32b49 --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserCallback.h @@ -0,0 +1,118 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_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. + + \author (C) 2004-2011 Ingo Berg +*/ +class ParserCallback +{ +public: + ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC); + ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity); + ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti); + ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti); + + 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(); + ParserCallback(const ParserCallback &a_Fun); + + ParserCallback* Clone() const; + + bool IsOptimizable() const; + void* GetAddr() const; + ECmdCode GetCode() const; + ETypeCode GetType() const; + int GetPri() const; + EOprtAssociativity GetAssociativity() const; + int GetArgc() const; + +private: + void *m_pFun; ///< Pointer to the callback function, casted to void + + /** \brief Number of numeric function arguments + + This number is negative for functions with variable number of arguments. in this cases + they represent the actual number of arguments found. + */ + int m_iArgc; + int m_iPri; ///< Valid only for binary and infix operators; Operator precedence. + EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators + ECmdCode m_iCode; + ETypeCode m_iType; + bool m_bAllowOpti; ///< Flag indication optimizeability +}; + +//------------------------------------------------------------------------------ +/** \brief Container for Callback objects. */ +typedef std::map funmap_type; + +} // namespace mu + +#endif + diff --git a/muparser-2.2.5_GR/include/muParserDLL.h b/muparser-2.2.5_GR/include/muParserDLL.h new file mode 100755 index 0000000..155ef8a --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserDLL.h @@ -0,0 +1,241 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef MU_PARSER_DLL_H +#define MU_PARSER_DLL_H + +#if defined(WIN32) || defined(_WIN32) + #ifdef MUPARSERLIB_EXPORTS + #define API_EXPORT(TYPE) __declspec(dllexport) TYPE __cdecl + #else + #define API_EXPORT(TYPE) __declspec(dllimport) TYPE __cdecl + #endif +#else + #define API_EXPORT(TYPE) TYPE +#endif + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** \file + \brief This file contains the DLL interface of muparser. +*/ + +// Basic types +typedef void* muParserHandle_t; // parser handle + +#ifndef _UNICODE + typedef char muChar_t; // character type +#else + typedef wchar_t muChar_t; // character type +#endif + +typedef int muBool_t; // boolean type +typedef int muInt_t; // integer type +typedef double muFloat_t; // floating point type + +// function types for calculation +typedef muFloat_t (*muFun0_t )(); +typedef muFloat_t (*muFun1_t )(muFloat_t); +typedef muFloat_t (*muFun2_t )(muFloat_t, muFloat_t); +typedef muFloat_t (*muFun3_t )(muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muFun4_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muFun5_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muFun6_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muFun7_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muFun8_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muFun9_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muFun10_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + +// Function prototypes for bulkmode functions +typedef muFloat_t (*muBulkFun0_t )(int, int); +typedef muFloat_t (*muBulkFun1_t )(int, int, muFloat_t); +typedef muFloat_t (*muBulkFun2_t )(int, int, muFloat_t, muFloat_t); +typedef muFloat_t (*muBulkFun3_t )(int, int, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muBulkFun4_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muBulkFun5_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muBulkFun6_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muBulkFun7_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muBulkFun8_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muBulkFun9_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); +typedef muFloat_t (*muBulkFun10_t)(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); + +typedef muFloat_t (*muMultFun_t)(const muFloat_t*, muInt_t); +typedef muFloat_t (*muStrFun1_t)(const muChar_t*); +typedef muFloat_t (*muStrFun2_t)(const muChar_t*, muFloat_t); +typedef muFloat_t (*muStrFun3_t)(const muChar_t*, muFloat_t, muFloat_t); + +// Functions for parser management +typedef void (*muErrorHandler_t)(muParserHandle_t a_hParser); // [optional] callback to an error handler +typedef muFloat_t* (*muFacFun_t)(const muChar_t*, void*); // [optional] callback for creating new variables +typedef muInt_t (*muIdentFun_t)(const muChar_t*, muInt_t*, muFloat_t*); // [optional] value identification callbacks + +//----------------------------------------------------------------------------------------------------- +// Constants +static const int muOPRT_ASCT_LEFT = 0; +static const int muOPRT_ASCT_RIGHT = 1; + +static const int muBASETYPE_FLOAT = 0; +static const int muBASETYPE_INT = 1; + +//----------------------------------------------------------------------------------------------------- +// +// +// muParser C compatible bindings +// +// +//----------------------------------------------------------------------------------------------------- + + +// Basic operations / initialization +API_EXPORT(muParserHandle_t) mupCreate(int nBaseType); +API_EXPORT(void) mupRelease(muParserHandle_t a_hParser); +API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser); +API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t *a_szExpr); +API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void* pUserData); +API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser); +API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser); +API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int *nNum); +API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t *a_fResult, int nSize); + +// Defining callbacks / variables / constants +API_EXPORT(void) mupDefineFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun0_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun1_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun2_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun3_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun4_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun5_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun6_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun7_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun8_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun9_t a_pFun, muBool_t a_bOptimize); +API_EXPORT(void) mupDefineFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun10_t a_pFun, muBool_t a_bOptimize); + +// Defining bulkmode functions +API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun0_t a_pFun); +API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun1_t a_pFun); +API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun2_t a_pFun); +API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun3_t a_pFun); +API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun4_t a_pFun); +API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun5_t a_pFun); +API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun6_t a_pFun); +API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun7_t a_pFun); +API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun8_t a_pFun); +API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun9_t a_pFun); +API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun10_t a_pFun); + +// string functions +API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun1_t a_pFun); +API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun2_t a_pFun); +API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun3_t a_pFun); + +API_EXPORT(void) mupDefineMultFun( muParserHandle_t a_hParser, + const muChar_t* a_szName, + muMultFun_t a_pFun, + muBool_t a_bOptimize); + +API_EXPORT(void) mupDefineOprt( muParserHandle_t a_hParser, + const muChar_t* a_szName, + muFun2_t a_pFun, + muInt_t a_nPrec, + muInt_t a_nOprtAsct, + muBool_t a_bOptimize); + +API_EXPORT(void) mupDefineConst( muParserHandle_t a_hParser, + const muChar_t* a_szName, + muFloat_t a_fVal ); + +API_EXPORT(void) mupDefineStrConst( muParserHandle_t a_hParser, + const muChar_t* a_szName, + const muChar_t *a_sVal ); + +API_EXPORT(void) mupDefineVar( muParserHandle_t a_hParser, + const muChar_t* a_szName, + muFloat_t *a_fVar); + +API_EXPORT(void) mupDefineBulkVar( muParserHandle_t a_hParser, + const muChar_t* a_szName, + muFloat_t *a_fVar); + +API_EXPORT(void) mupDefinePostfixOprt( muParserHandle_t a_hParser, + const muChar_t* a_szName, + muFun1_t a_pOprt, + muBool_t a_bOptimize); + + +API_EXPORT(void) mupDefineInfixOprt( muParserHandle_t a_hParser, + const muChar_t* a_szName, + muFun1_t a_pOprt, + muBool_t a_bOptimize); + +// Define character sets for identifiers +API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); +API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); +API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset); + +// Remove all / single variables +API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName); +API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser); +API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser); +API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser); +API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser); + +// Querying variables / expression variables / constants +API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser); +API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser); +API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser); +API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar); +API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar); +API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t* a_pVar); +API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep); +API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cArgSep); +API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cArgSep); +API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser); + +// Add value recognition callbacks +API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, muIdentFun_t); + +// Error handling +API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser); +API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser); +API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t a_pErrHandler); +API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser); +API_EXPORT(muInt_t) mupGetErrorCode(muParserHandle_t a_hParser); +API_EXPORT(muInt_t) mupGetErrorPos(muParserHandle_t a_hParser); +API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser); +//API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser); + +// This is used for .NET only. It creates a new variable allowing the dll to +// manage the variable rather than the .NET garbage collector. +API_EXPORT(muFloat_t*) mupCreateVar(); +API_EXPORT(void) mupReleaseVar(muFloat_t*); + +#ifdef __cplusplus +} +#endif + +#endif // include guard diff --git a/muparser-2.2.5_GR/include/muParserDef.h b/muparser-2.2.5_GR/include/muParserDef.h new file mode 100755 index 0000000..437f2ea --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserDef.h @@ -0,0 +1,368 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2014 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef 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. +*/ + +#define MUP_VERSION _T("2.2.5") +#define MUP_VERSION_DATE _T("20150427; GC") + +#define MUP_CHARS _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +/** \brief If this macro is defined mathematical exceptions (div by zero) will be thrown as exceptions. */ +//#define MUP_MATH_EXCEPTIONS + +/** \brief Define the base datatype for values. + + 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. +*/ +//#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 + +#if defined(_DEBUG) + /** \brief Debug macro to force an abortion of the programm with a certain message. + */ + #define MUP_FAIL(MSG) \ + { \ + bool MSG=false; \ + assert(MSG); \ + } + + /** \brief An assertion that does not kill the program. + + This macro is neutralised in UNICODE builds. It's + too difficult to translate. + */ + #define MUP_ASSERT(COND) \ + if (!(COND)) \ + { \ + stringstream_type ss; \ + ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") \ + << __FILE__ << _T(" line ") \ + << __LINE__ << _T("."); \ + throw ParserError( ss.str() ); \ + } +#else + #define MUP_FAIL(MSG) + #define MUP_ASSERT(COND) +#endif + + +namespace mu +{ +#if defined(_UNICODE) + + //------------------------------------------------------------------------------ + /** \brief Encapsulate wcout. */ + inline std::wostream& console() + { + return std::wcout; + } + + /** \brief Encapsulate cin. */ + inline std::wistream& console_in() + { + return std::wcin; + } + +#else + + /** \brief Encapsulate cout. + + Used for supporting UNICODE more easily. + */ + inline std::ostream& console() + { + return std::cout; + } + + /** \brief Encapsulate cin. + + Used for supporting UNICODE more easily. + */ + inline std::istream& console_in() + { + return std::cin; + } + +#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, + cmVARPOW3, + cmVARPOW4, + cmVARMUL, + cmPOW2, + + // operators and functions + cmFUNC, ///< Code for a generic function item + cmFUNC_STR, ///< Code for a function with a string parameter + cmFUNC_BULK, ///< Special callbacks for Bulk mode with an additional parameter for the bulk index + cmSTRING, ///< Code for a string token + cmOPRT_BIN, ///< user defined binary operator + cmOPRT_POSTFIX, ///< code for postfix operators + cmOPRT_INFIX, ///< code for infix operators + cmEND, ///< end of formula + cmUNKNOWN ///< uninitialized item + }; + + //------------------------------------------------------------------------------ + /** \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) + }; + + //------------------------------------------------------------------------------ + // 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 wether UNICODE is used or not. + */ + typedef MUP_STRING_TYPE string_type; + + /** \brief The character type used by the parser. + + Depends on wether 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 Callback type used for functions without arguments. */ + typedef value_type (*generic_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 five 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 five 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 five 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 five arguments. */ + typedef value_type (*fun_type9)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + + /** \brief Callback type used for functions with five arguments. */ + typedef value_type (*fun_type10)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + + /** \brief Callback type used for functions without arguments. */ + typedef value_type (*bulkfun_type0)(int, int); + + /** \brief Callback type used for functions with a single arguments. */ + typedef value_type (*bulkfun_type1)(int, int, value_type); + + /** \brief Callback type used for functions with two arguments. */ + typedef value_type (*bulkfun_type2)(int, int, value_type, value_type); + + /** \brief Callback type used for functions with three arguments. */ + typedef value_type (*bulkfun_type3)(int, int, value_type, value_type, value_type); + + /** \brief Callback type used for functions with four arguments. */ + typedef value_type (*bulkfun_type4)(int, int, value_type, value_type, value_type, value_type); + + /** \brief Callback type used for functions with five arguments. */ + typedef value_type (*bulkfun_type5)(int, int, value_type, value_type, value_type, value_type, value_type); + + /** \brief Callback type used for functions with five arguments. */ + typedef value_type (*bulkfun_type6)(int, int, value_type, value_type, value_type, value_type, value_type, value_type); + + /** \brief Callback type used for functions with five arguments. */ + typedef value_type (*bulkfun_type7)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + + /** \brief Callback type used for functions with five arguments. */ + typedef value_type (*bulkfun_type8)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + + /** \brief Callback type used for functions with five arguments. */ + typedef value_type (*bulkfun_type9)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + + /** \brief Callback type used for functions with five arguments. */ + typedef value_type (*bulkfun_type10)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); + + /** \brief Callback type used for functions with a variable argument list. */ + typedef value_type (*multfun_type)(const value_type*, int); + + /** \brief Callback type used for functions taking a string as an argument. */ + typedef value_type (*strfun_type1)(const char_type*); + + /** \brief Callback type used for functions taking a string and a value as arguments. */ + typedef value_type (*strfun_type2)(const char_type*, value_type); + + /** \brief Callback type used for functions taking a string and two values as arguments. */ + typedef value_type (*strfun_type3)(const char_type*, value_type, value_type); + + /** \brief Callback used for functions that identify values in a string. */ + typedef int (*identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal); + + /** \brief Callback used for variable creation factory functions. */ + typedef value_type* (*facfun_type)(const char_type*, void*); +} // end of namespace + +#endif + diff --git a/muparser-2.2.5_GR/include/muParserError.h b/muparser-2.2.5_GR/include/muParserError.h new file mode 100755 index 0000000..7f88e99 --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserError.h @@ -0,0 +1,176 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_ERROR_H +#define MU_PARSER_ERROR_H + +#include +#include +#include +#include +#include +#include + +#include "muParserDef.h" + +/** \file + \brief This file defines the error class used by the parser. +*/ + +namespace mu +{ + +/** \brief Error codes. */ +enum EErrorCodes +{ + // Formula syntax errors + ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found + ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified. + ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(") + ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23") + ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found + ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found + ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found + ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing + ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position + ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument + ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument + ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3") + ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)") + ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)") + ecTOO_MANY_PARAMS = 14, ///< Too many function parameters + ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)") + ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type + ecSTR_RESULT = 17, ///< result is a string + + // Invalid Parser input Parameters + ecINVALID_NAME = 18, ///< Invalid function, variable or constant name. + ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier + ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name. + ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name. + + ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator + ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer + ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer + ecEMPTY_EXPRESSION = 25, ///< The Expression is empty + ecNAME_CONFLICT = 26, ///< Name conflict + ecOPT_PRI = 27, ///< Invalid operator priority + // + ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused) + ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused) + ecGENERIC = 30, ///< Generic error + ecLOCALE = 31, ///< Conflict with current locale + + ecUNEXPECTED_CONDITIONAL = 32, + ecMISSING_ELSE_CLAUSE = 33, + ecMISPLACED_COLON = 34, + + ecUNREASONABLE_NUMBER_OF_COMPUTATIONS = 35, + + // internal errors + ecINTERNAL_ERROR = 36, ///< Internal error of any kind. + + // The last two are special entries + ecCOUNT, ///< This is no error code, It just stores just the total number of error codes + ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages +}; + +//--------------------------------------------------------------------------- +/** \brief A class that handles the error messages. +*/ +class ParserErrorMsg +{ +public: + typedef ParserErrorMsg self_type; + + ParserErrorMsg& operator=(const ParserErrorMsg &); + ParserErrorMsg(const ParserErrorMsg&); + ParserErrorMsg(); + + ~ParserErrorMsg(); + + static const ParserErrorMsg& Instance(); + string_type operator[](unsigned a_iIdx) const; + +private: + std::vector m_vErrMsg; ///< A vector with the predefined error messages + static const self_type m_Instance; ///< The instance pointer +}; + +//--------------------------------------------------------------------------- +/** \brief Error class of the parser. + \author Ingo Berg + + Part of the math parser package. +*/ +class ParserError +{ +private: + + /** \brief Replace all ocuurences of a substring with another string. */ + void ReplaceSubString( string_type &strSource, + const string_type &strFind, + const string_type &strReplaceWith); + void Reset(); + +public: + + ParserError(); + explicit ParserError(EErrorCodes a_iErrc); + explicit ParserError(const string_type &sMsg); + ParserError( EErrorCodes a_iErrc, + const string_type &sTok, + const string_type &sFormula = string_type(), + int a_iPos = -1); + ParserError( EErrorCodes a_iErrc, + int a_iPos, + const string_type &sTok); + ParserError( const char_type *a_szMsg, + int a_iPos = -1, + const string_type &sTok = string_type()); + ParserError(const ParserError &a_Obj); + ParserError& operator=(const ParserError &a_Obj); + ~ParserError(); + + void SetFormula(const string_type &a_strFormula); + const string_type& GetExpr() const; + const string_type& GetMsg() const; + int GetPos() const; + const string_type& GetToken() const; + EErrorCodes GetCode() const; + +private: + string_type m_strMsg; ///< The message string + string_type m_strFormula; ///< Formula string + string_type m_strTok; ///< Token related with the error + int m_iPos; ///< Formula position related to the error + EErrorCodes m_iErrc; ///< Error code + const ParserErrorMsg &m_ErrMsg; +}; + +} // namespace mu + +#endif + diff --git a/muparser-2.2.5_GR/include/muParserFixes.h b/muparser-2.2.5_GR/include/muParserFixes.h new file mode 100755 index 0000000..1cd15e0 --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserFixes.h @@ -0,0 +1,62 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_FIXES_H +#define MU_PARSER_FIXES_H + +/** \file + \brief This file contains compatibility fixes for some platforms. +*/ + +// +// Compatibility fixes +// + +//--------------------------------------------------------------------------- +// +// Intel Compiler +// +//--------------------------------------------------------------------------- + +#ifdef __INTEL_COMPILER + +// remark #981: operands are evaluated in unspecified order +// disabled -> completely pointless if the functions do not have side effects +// +#pragma warning(disable:981) + +// remark #383: value copied to temporary, reference to temporary used +#pragma warning(disable:383) + +// remark #1572: floating-point equality and inequality comparisons are unreliable +// disabled -> everyone knows it, the parser passes this problem +// deliberately to the user +#pragma warning(disable:1572) + +#endif + +#endif // include guard + + diff --git a/muparser-2.2.5_GR/include/muParserInt.h b/muparser-2.2.5_GR/include/muParserInt.h new file mode 100755 index 0000000..136de33 --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserInt.h @@ -0,0 +1,140 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_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 cant use negative signs !! + static value_type UnaryMinus(value_type); + // Functions with variable number of arguments + static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum + static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum + static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum + // binary operator callbacks + static value_type Add(value_type v1, value_type v2); + static value_type Sub(value_type v1, value_type v2); + static value_type Mul(value_type v1, value_type v2); + static value_type Div(value_type v1, value_type v2); + static value_type Mod(value_type v1, value_type v2); + static value_type Pow(value_type v1, value_type v2); + static value_type Shr(value_type v1, value_type v2); + static value_type Shl(value_type v1, value_type v2); + static value_type LogAnd(value_type v1, value_type v2); + static value_type LogOr(value_type v1, value_type v2); + static value_type And(value_type v1, value_type v2); + static value_type Or(value_type v1, value_type v2); + static value_type Xor(value_type v1, value_type v2); + static value_type Less(value_type v1, value_type v2); + static value_type Greater(value_type v1, value_type v2); + static value_type LessEq(value_type v1, value_type v2); + static value_type GreaterEq(value_type v1, value_type v2); + static value_type Equal(value_type v1, value_type v2); + static value_type NotEqual(value_type v1, value_type v2); + static value_type Not(value_type v1); + + 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(); + + virtual void InitFun(); + virtual void InitOprt(); + virtual void InitConst(); + virtual void InitCharSets(); +}; + +} // namespace mu + +#endif + diff --git a/muparser-2.2.5_GR/include/muParserStack.h b/muparser-2.2.5_GR/include/muParserStack.h new file mode 100755 index 0000000..f8437e3 --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserStack.h @@ -0,0 +1,125 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_STACK_H +#define MU_PARSER_STACK_H + +#include +#include +#include +#include + +#include "muParserError.h" +#include "muParserToken.h" + +/** \file + \brief This file defines the stack used by muparser. +*/ + +namespace mu +{ + + /** \brief Parser stack implementation. + + Stack implementation based on a std::stack. The behaviour of pop() had been + slightly changed in order to get an error code if the stack is empty. + The stack is used within the Parser both as a value stack and as an operator stack. + + \author (C) 2004-2011 Ingo Berg + */ + template + class ParserStack + { + private: + + /** \brief Type of the underlying stack implementation. */ + typedef std::stack > impl_type; + + impl_type m_Stack; ///< This is the actual stack. + + public: + + //--------------------------------------------------------------------------- + ParserStack() + :m_Stack() + {} + + //--------------------------------------------------------------------------- + virtual ~ParserStack() + {} + + //--------------------------------------------------------------------------- + /** \brief Pop a value from the stack. + + Unlike the standard implementation this function will return the value that + is going to be taken from the stack. + + \throw ParserException in case the stack is empty. + \sa pop(int &a_iErrc) + */ + TValueType pop() + { + if (empty()) + throw ParserError( _T("stack is empty.") ); + + TValueType el = top(); + m_Stack.pop(); + return el; + } + + /** \brief Push an object into the stack. + + \param a_Val object to push into the stack. + \throw nothrow + */ + void push(const TValueType& a_Val) + { + m_Stack.push(a_Val); + } + + /** \brief Return the number of stored elements. */ + unsigned size() const + { + return (unsigned)m_Stack.size(); + } + + /** \brief Returns true if stack is empty false otherwise. */ + bool empty() const + { + return m_Stack.empty(); + } + + /** \brief Return reference to the top object in the stack. + + The top object is the one pushed most recently. + */ + TValueType& top() + { + return m_Stack.top(); + } + }; +} // namespace MathUtils + +#endif diff --git a/muparser-2.2.5_GR/include/muParserTemplateMagic.h b/muparser-2.2.5_GR/include/muParserTemplateMagic.h new file mode 100755 index 0000000..1626cae --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserTemplateMagic.h @@ -0,0 +1,113 @@ +#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); } + }; +} + +#endif diff --git a/muparser-2.2.5_GR/include/muParserTest.h b/muparser-2.2.5_GR/include/muParserTest.h new file mode 100755 index 0000000..c02b021 --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserTest.h @@ -0,0 +1,214 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_TEST_H +#define MU_PARSER_TEST_H + +#include +#include +#include // for accumulate +#include "muParser.h" +#include "muParserInt.h" + +/** \file + \brief This file contains the parser test class. +*/ + +namespace mu +{ + /** \brief Namespace for test cases. */ + namespace Test + { + //------------------------------------------------------------------------------ + /** \brief Test cases for unit testing. + + (C) 2004-2011 Ingo Berg + */ + class ParserTester // final + { + private: + static int c_iCount; + + // 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_fVal1a_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> 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 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); + + int TestNames(); + int TestSyntax(); + int TestMultiArg(); + int TestPostFix(); + int TestExpression(); + int TestInfixOprt(); + int TestBinOprt(); + int TestVarConst(); + int TestInterface(); + int TestException(); + int TestStrArg(); + int TestIfThenElse(); + int TestBulkMode(); + + void Abort() const; + + public: + typedef int (ParserTester::*testfun_type)(); + + ParserTester(); + void 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 + +#endif + + diff --git a/muparser-2.2.5_GR/include/muParserToken.h b/muparser-2.2.5_GR/include/muParserToken.h new file mode 100755 index 0000000..fc91d78 --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserToken.h @@ -0,0 +1,401 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_TOKEN_H +#define MU_PARSER_TOKEN_H + +#include +#include +#include +#include +#include + +#include "muParserError.h" +#include "muParserCallback.h" + +/** \file + \brief This file contains the parser token definition. +*/ + +namespace mu +{ + /** \brief Encapsulation of the data for a single formula token. + + 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
  • +
+ + \author (C) 2004-2013 Ingo Berg + */ + template + class ParserToken + { + private: + + ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. + ETypeCode m_iType; + void *m_pTok; ///< Stores Token pointer; not applicable for all tokens + int m_iIdx; ///< An otional index to an external buffer storing the token data + TString m_strTok; ///< Token string + TString m_strVal; ///< Value for string variables + value_type m_fVal; ///< the value + std::auto_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 Assignement 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 seperate set functions. + + \pre [assert] a_iType!=cmVAR + \pre [assert] a_iType!=cmVAL + \pre [assert] a_iType!=cmFUNC + \post m_fVal = 0 + \post m_pTok = 0 + */ + ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString()) + { + // The following types cant be set this way, they have special Set functions + assert(a_iType!=cmVAR); + assert(a_iType!=cmVAL); + assert(a_iType!=cmFUNC); + + 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) + { + assert(a_pCallback.GetAddr()); + + 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()==NULL || 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_fun_type GetFuncAddr() const + { + return (m_pCallback.get()) ? (generic_fun_type)m_pCallback->GetAddr() : 0; + } + + //------------------------------------------------------------------------------ + /** \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 + { + assert(m_pCallback.get()); + + if (!m_pCallback->GetAddr()) + throw ParserError(ecINTERNAL_ERROR); + + return m_pCallback->GetArgc(); + } + + //------------------------------------------------------------------------------ + /** \brief Return the token identifier. + + If #m_iType is cmSTRING the token identifier is the value of the string argument + for a string function. + \return #m_strTok + \throw nothrow + \sa m_strTok + */ + const TString& GetAsString() const + { + return m_strTok; + } + }; +} // namespace mu + +#endif diff --git a/muparser-2.2.5_GR/include/muParserTokenReader.h b/muparser-2.2.5_GR/include/muParserTokenReader.h new file mode 100755 index 0000000..9d96225 --- /dev/null +++ b/muparser-2.2.5_GR/include/muParserTokenReader.h @@ -0,0 +1,161 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MU_PARSER_TOKEN_READER_H +#define MU_PARSER_TOKEN_READER_H + +#include +#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 + { + 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 assignement to constant i.e. "4=7" + noIF = 1 << 12, + noELSE = 1 << 13, + sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP, + noANY = ~0 ///< All of he above flags set + }; + + 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, + int a_iPos) const; + int ExtractOperatorToken(string_type &a_sTok, int a_iPos) const; + + bool IsBuiltIn(token_type &a_Tok); + bool IsArgSep(token_type &a_Tok); + bool IsEOF(token_type &a_Tok); + bool IsInfixOpTok(token_type &a_Tok); + bool IsFunTok(token_type &a_Tok); + bool IsPostOpTok(token_type &a_Tok); + bool IsOprt(token_type &a_Tok); + bool IsValTok(token_type &a_Tok); + bool IsVarTok(token_type &a_Tok); + bool IsStrVarTok(token_type &a_Tok); + bool IsUndefVarTok(token_type &a_Tok); + bool IsString(token_type &a_Tok); + void Error(EErrorCodes a_iErrc, + int a_iPos = -1, + const string_type &a_sTok = string_type() ) const; + + 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 + int m_iBrackets; + token_type m_lastTok; + char_type m_cArgSep; ///< The character used for separating function arguments + }; +} // namespace mu + +#endif + + diff --git a/muparser-2.2.5_GR/src/muParser.cc b/muparser-2.2.5_GR/src/muParser.cc new file mode 100755 index 0000000..39ea861 --- /dev/null +++ b/muparser-2.2.5_GR/src/muParser.cc @@ -0,0 +1,397 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + + Copyright (C) 2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "muParser.h" +#include "muParserTemplateMagic.h" + +//--- Standard includes ------------------------------------------------------------------------ +#include +#include +#include + +/** \brief Pi (what else?). */ +#define PARSER_CONST_PI 3.141592653589793238462643 + +/** \brief The Eulerian number. */ +#define PARSER_CONST_E 2.718281828459045235360287 + +using namespace std; + +/** \file + \brief Implementation of the standard floating point parser. +*/ + + + +/** \brief Namespace for mathematical applications. */ +namespace mu +{ + + + //--------------------------------------------------------------------------- + // Trigonometric function + value_type Parser::Sin(value_type v) { return MathImpl::Sin(v); } + value_type Parser::Cos(value_type v) { return MathImpl::Cos(v); } + value_type Parser::Tan(value_type v) { return MathImpl::Tan(v); } + value_type Parser::ASin(value_type v) { return MathImpl::ASin(v); } + value_type Parser::ACos(value_type v) { return MathImpl::ACos(v); } + value_type Parser::ATan(value_type v) { return MathImpl::ATan(v); } + value_type Parser::ATan2(value_type v1, value_type v2) { return MathImpl::ATan2(v1, v2); } + value_type Parser::Sinh(value_type v) { return MathImpl::Sinh(v); } + value_type Parser::Cosh(value_type v) { return MathImpl::Cosh(v); } + value_type Parser::Tanh(value_type v) { return MathImpl::Tanh(v); } + value_type Parser::ASinh(value_type v) { return MathImpl::ASinh(v); } + value_type Parser::ACosh(value_type v) { return MathImpl::ACosh(v); } + value_type Parser::ATanh(value_type v) { return MathImpl::ATanh(v); } + + //--------------------------------------------------------------------------- + // Logarithm functions + + // Logarithm base 2 + value_type Parser::Log2(value_type v) + { + #ifdef MUP_MATH_EXCEPTIONS + if (v<=0) + throw ParserError(ecDOMAIN_ERROR, _T("Log2")); + #endif + + return MathImpl::Log2(v); + } + + // Logarithm base 10 + value_type Parser::Log10(value_type v) + { + #ifdef MUP_MATH_EXCEPTIONS + if (v<=0) + throw ParserError(ecDOMAIN_ERROR, _T("Log10")); + #endif + + return MathImpl::Log10(v); + } + +// Logarithm base e (natural logarithm) + value_type Parser::Ln(value_type v) + { + #ifdef MUP_MATH_EXCEPTIONS + if (v<=0) + throw ParserError(ecDOMAIN_ERROR, _T("Ln")); + #endif + + return MathImpl::Log(v); + } + + //--------------------------------------------------------------------------- + // misc + value_type Parser::Exp(value_type v) { return MathImpl::Exp(v); } + value_type Parser::Abs(value_type v) { return MathImpl::Abs(v); } + value_type Parser::Sqrt(value_type v) + { + #ifdef MUP_MATH_EXCEPTIONS + if (v<0) + throw ParserError(ecDOMAIN_ERROR, _T("sqrt")); + #endif + + return MathImpl::Sqrt(v); + } + value_type Parser::Rint(value_type v) { return MathImpl::Rint(v); } + value_type Parser::Sign(value_type v) { return MathImpl::Sign(v); } + + //--------------------------------------------------------------------------- + /** \brief Callback for the unary minus operator. + \param v The value to negate + \return -v + */ + value_type Parser::UnaryMinus(value_type v) + { + return -v; + } + + //--------------------------------------------------------------------------- + /** \brief Callback for the unary minus operator. + \param v The value to negate + \return -v + */ + value_type Parser::UnaryPlus(value_type v) + { + return v; + } + + //--------------------------------------------------------------------------- + /** \brief Callback for adding multiple values. + \param [in] a_afArg Vector with the function arguments + \param [in] a_iArgc The size of a_afArg + */ + value_type Parser::Sum(const value_type *a_afArg, int a_iArgc) + { + if (!a_iArgc) + throw exception_type(_T("too few arguments for function sum.")); + + value_type fRes=0; + for (int i=0; i> 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"), Sin); + DefineFun(_T("cos"), Cos); + DefineFun(_T("tan"), Tan); + // arcus functions + DefineFun(_T("asin"), ASin); + DefineFun(_T("acos"), ACos); + DefineFun(_T("atan"), ATan); + DefineFun(_T("atan2"), ATan2); + // hyperbolic functions + DefineFun(_T("sinh"), Sinh); + DefineFun(_T("cosh"), Cosh); + DefineFun(_T("tanh"), Tanh); + // arcus hyperbolic functions + DefineFun(_T("asinh"), ASinh); + DefineFun(_T("acosh"), ACosh); + DefineFun(_T("atanh"), ATanh); + // Logarithm functions + DefineFun(_T("log2"), Log2); + DefineFun(_T("log10"), Log10); + DefineFun(_T("log"), Ln); + DefineFun(_T("ln"), Ln); + // misc + DefineFun(_T("exp"), Exp); + DefineFun(_T("sqrt"), Sqrt); + DefineFun(_T("sign"), Sign); + DefineFun(_T("rint"), Rint); + DefineFun(_T("abs"), Abs); + // Functions with variable number of arguments + DefineFun(_T("sum"), Sum); + DefineFun(_T("avg"), Avg); + DefineFun(_T("min"), Min); + DefineFun(_T("max"), Max); + } + } + + //--------------------------------------------------------------------------- + /** \brief Initialize constants. + + By default the parser recognizes two constants. Pi ("pi") and the Eulerian + number ("_e"). + */ + void Parser::InitConst() + { + DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI); + DefineConst(_T("_e"), (value_type)PARSER_CONST_E); + } + + //--------------------------------------------------------------------------- + /** \brief Initialize operators. + + By default only the unary minus operator is added. + */ + void Parser::InitOprt() + { + DefineInfixOprt(_T("-"), UnaryMinus); + DefineInfixOprt(_T("+"), 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) as suggested in the muparser + forum: + + http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843 + */ + value_type Parser::Diff(value_type *a_Var, + value_type a_fPos, + value_type a_fEpsilon) const + { + value_type fRes(0), + fBuf(*a_Var), + f[4] = {0,0,0,0}, + fEpsilon(a_fEpsilon); + + // Backwards compatible calculation of epsilon inc case the user doesn't provide + // his own epsilon + if (fEpsilon==0) + fEpsilon = (a_fPos==0) ? (value_type)1e-10 : (value_type)1e-7 * a_fPos; + + *a_Var = a_fPos+2 * fEpsilon; f[0] = Eval(); + *a_Var = a_fPos+1 * fEpsilon; f[1] = Eval(); + *a_Var = a_fPos-1 * fEpsilon; f[2] = Eval(); + *a_Var = a_fPos-2 * fEpsilon; f[3] = Eval(); + *a_Var = fBuf; // restore variable + + fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon); + return fRes; + } +} // namespace mu diff --git a/muparser-2.2.5_GR/src/muParserBase.cc b/muparser-2.2.5_GR/src/muParserBase.cc new file mode 100755 index 0000000..ea3699a --- /dev/null +++ b/muparser-2.2.5_GR/src/muParserBase.cc @@ -0,0 +1,1778 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "muParserBase.h" +#include "muParserTemplateMagic.h" + +//--- Standard includes ------------------------------------------------------------------------ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MUP_USE_OPENMP + #include +#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 + }; + + //------------------------------------------------------------------------------ + /** \brief Constructor. + \param a_szFormula the formula to interpret. + \throw ParserException if a_szFormula is null. + */ + 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_nIfElseCounter(0) + ,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_nIfElseCounter(0) + { + 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_nIfElseCounter = a_Parser.m_nIfElseCounter; + 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(); + m_nIfElseCounter = 0; + } + + //--------------------------------------------------------------------------- + void ParserBase::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/) + {} + + //--------------------------------------------------------------------------- + /** \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 << MUP_VERSION; + + if (eInfo==pviFULL) + { + ss << _T(" (") << MUP_VERSION_DATE; + 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"); +//#else +// ss << _T("; NO_OPENMP"); +#endif + +#if defined(MUP_MATH_EXCEPTIONS) + ss << _T("; MATHEXC"); +//#else +// ss << _T("; NO_MATHEXC"); +#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.GetAddr()==0) + 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); + case cmOPRT_INFIX: Error(ecINVALID_INFIX_IDENT, -1, a_sName); + 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 + std::locale loc; + if (m_pTokenReader->GetArgSep()==std::use_facet >(loc).decimal_point()) + Error(ecLOCALE); + + // 20060222: Bugfix for Borland-Kylix: + // adding a space to the expression will keep Borlands KYLIX from going wild + // when calling tellg on a stringstream created from the expression after + // reading a value at the end of an expression. (mu::Parser::IsVal function) + // (tellg returns -1 otherwise causing the parser to ignore the value) + string_type sBuf(a_sExpr + _T(" ") ); + m_pTokenReader->SetFormula(sBuf); + 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 + { + 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 + { + 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 + { + 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) + { + 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) + { + 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 ) + { + // Check for conflicts with built in operator names + for (int i=0; m_bBuiltInOp && iIgnoreUndefVar(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, dont 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_fun_type pFunc = a_FunTok.GetFuncAddr(); + 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; + 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( ParserStack &a_stOpt, + ParserStack &a_stVal, + int a_iArgCount) const + { + 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.pop(); + assert(funTok.GetFuncAddr()); + + // 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); + + // Thats 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 && iArgCountGetPos()-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; iGetPos(), funTok.GetAsString()); + } + + switch(funTok.GetCode()) + { + case cmFUNC_STR: + stArg.push_back(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); + break; + } + + // Push dummy value representing the function result to the stack + token_type token; + token.SetVal(1); + a_stVal.push(token); + } + + //--------------------------------------------------------------------------- + void ParserBase::ApplyIfElse(ParserStack &a_stOpt, + ParserStack &a_stVal) const + { + // Check if there is an if Else clause to be calculated + while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE) + { + token_type opElse = a_stOpt.pop(); + MUP_ASSERT(a_stOpt.size()>0); + + // Take the value associated with the else branch from the value stack + token_type vVal2 = a_stVal.pop(); + + MUP_ASSERT(a_stOpt.size()>0); + MUP_ASSERT(a_stVal.size()>=2); + + // it then else is a ternary operator Pop all three values from the value s + // tack and just return the right value + token_type vVal1 = a_stVal.pop(); + token_type vExpr = a_stVal.pop(); + + a_stVal.push( (vExpr.GetVal()!=0) ? vVal1 : vVal2); + + token_type opIf = a_stOpt.pop(); + MUP_ASSERT(opElse.GetCode()==cmELSE); + MUP_ASSERT(opIf.GetCode()==cmIF); + + 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(ParserStack &a_stOpt, + ParserStack &a_stVal) const + { + // is it a user defined binary operator? + if (a_stOpt.top().GetCode()==cmOPRT_BIN) + { + ApplyFunc(a_stOpt, a_stVal, 2); + } + else + { + MUP_ASSERT(a_stVal.size()>=2); + token_type valTok1 = a_stVal.pop(), + valTok2 = a_stVal.pop(), + optTok = a_stOpt.pop(), + 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(ParserStack &stOpt, + ParserStack &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); + } + + //--------------------------------------------------------------------------- + /** \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; + + #if defined(MUP_MATH_EXCEPTIONS) + if (Stack[1+sidx]==0) + Error(ecDIV_BY_ZERO); + #endif + 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 cmBO: // unused, listed for compiler optimization purposes + //case cmBC: + // MUP_FAIL(INVALID_CODE_IN_BYTECODE); + // continue; + + case cmIF: + if (Stack[sidx--]==0) + pTok += pTok->Oprt.offset; + continue; + + case cmELSE: + pTok += pTok->Oprt.offset; + continue; + + case cmENDIF: + continue; + + //case cmARG_SEP: + // MUP_FAIL(INVALID_CODE_IN_BYTECODE); + // 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] = (*(fun_type0)pTok->Fun.ptr)(); continue; + case 1: Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]); continue; + case 2: sidx -= 1; Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1]); continue; + case 3: sidx -= 2; Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; + case 4: sidx -= 3; Stack[sidx] = (*(fun_type4)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; + case 5: sidx -= 4; Stack[sidx] = (*(fun_type5)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; + case 6: sidx -= 5; Stack[sidx] = (*(fun_type6)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue; + case 7: sidx -= 6; Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(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] = (*(fun_type8)pTok->Fun.ptr)(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] = (*(fun_type9)pTok->Fun.ptr)(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] = (*(fun_type10)pTok->Fun.ptr)(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: + if (iArgCount>0) // function with variable arguments store the number as a negative value + Error(ecINTERNAL_ERROR, 1); + + sidx -= -iArgCount - 1; + Stack[sidx] =(*(multfun_type)pTok->Fun.ptr)(&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; + MUP_ASSERT( iIdxStack>=0 && iIdxStack<(int)m_vStringBuf.size() ); + + switch(pTok->Fun.argc) // switch according to argument count + { + case 0: Stack[sidx] = (*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str()); continue; + case 1: Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx]); continue; + case 2: Stack[sidx] = (*(strfun_type3)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx+1]); continue; + } + + continue; + } + + case cmFUNC_BULK: + { + int iArgCount = pTok->Fun.argc; + + // switch according to argument count + switch(iArgCount) + { + case 0: sidx += 1; Stack[sidx] = (*(bulkfun_type0 )pTok->Fun.ptr)(nOffset, nThreadID); continue; + case 1: Stack[sidx] = (*(bulkfun_type1 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx]); continue; + case 2: sidx -= 1; Stack[sidx] = (*(bulkfun_type2 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1]); continue; + case 3: sidx -= 2; Stack[sidx] = (*(bulkfun_type3 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; + case 4: sidx -= 3; Stack[sidx] = (*(bulkfun_type4 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; + case 5: sidx -= 4; Stack[sidx] = (*(bulkfun_type5 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; + case 6: sidx -= 5; Stack[sidx] = (*(bulkfun_type6 )pTok->Fun.ptr)(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] = (*(bulkfun_type7 )pTok->Fun.ptr)(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] = (*(bulkfun_type8 )pTok->Fun.ptr)(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] = (*(bulkfun_type9 )pTok->Fun.ptr)(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] = (*(bulkfun_type10)pTok->Fun.ptr)(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: + Error(ecINTERNAL_ERROR, 2); + continue; + } + } + + default: + Error(ecINTERNAL_ERROR, 3); + return 0; + } // switch CmdCode + } // for all bytecode tokens + + return Stack[m_nFinalResultIdx]; + } + + //--------------------------------------------------------------------------- + void ParserBase::CreateRPN() const + { + if (!m_pTokenReader->GetExpr().length()) + Error(ecUNEXPECTED_EOF, 0); + + ParserStack stOpt, stVal; + ParserStack stArgCount; + token_type opta, opt; // for storing operators + token_type val, tval; // for storing value + + 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: + 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: + m_nIfElseCounter--; + if (m_nIfElseCounter<0) + Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); + + ApplyRemainingOprt(stOpt, stVal); + m_vRPN.AddIfElse(cmELSE); + stOpt.push(opt); + break; + + + case cmARG_SEP: + if (stArgCount.empty()) + Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); + + ++stArgCount.top(); + // fallthrough 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 + assert(stArgCount.size()); + int iArgCount = 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 cmAND: // built in binary operators + //case cmOR: + //case cmXOR: + case cmIF: + m_nIfElseCounter++; + // fallthrough 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(); + } + } // while (true) + + if (ParserBase::g_DbgDumpCmdCode) + m_vRPN.AsciiDump(); + + if (m_nIfElseCounter>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); + + if (stVal.top().GetType()!=tpDBL) + Error(ecSTR_RESULT); + + 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(); + 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 thats 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 ParserStack &a_stVal, + const ParserStack &a_stOprt) const + { + ParserStack stOprt(a_stOprt), + stVal(a_stVal); + + mu::console() << _T("\nValue stack:\n"); + while ( !stVal.empty() ) + { + token_type val = 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 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 + { + (this->*m_pParseFormula)(); + 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; + } + + //--------------------------------------------------------------------------- + /** \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)(); + } + + //--------------------------------------------------------------------------- + void ParserBase::Eval(value_type *results, int nBulkSize) + { +/* Commented because it is making a unit test impossible + + // Parallelization does not make sense for fewer than 10000 computations + // due to thread creation overhead. If the bulk size is below 2000 + // computation is refused. + if (nBulkSize<2000) + { + throw ParserError(ecUNREASONABLE_NUMBER_OF_COMPUTATIONS); + } +*/ + 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, ct = 0; + omp_set_num_threads(nMaxThreads); + + #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID) + for (i=0; i \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "muParserBytecode.h" + +#include +#include +#include +#include +#include +#include + +#include "muParserDef.h" +#include "muParserError.h" +#include "muParserToken.h" +#include "muParserStack.h" +#include "muParserTemplateMagic.h" + + +namespace mu +{ + //--------------------------------------------------------------------------- + /** \brief Bytecode default constructor. */ + ParserByteCode::ParserByteCode() + :m_iStackPos(0) + ,m_iMaxStackSize(0) + ,m_vRPN() + ,m_bEnableOptimizer(true) + { + 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 = NULL; + 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, + &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: + +#if defined(MUP_MATH_EXCEPTIONS) + if (y==0) + throw ParserError(ecDIV_BY_ZERO, _T("0")); +#endif + + 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==2) + m_vRPN[sz-2].Cmd = cmVARPOW2; + else if (m_vRPN[sz-1].Val.data2==3) + m_vRPN[sz-2].Cmd = cmVARPOW3; + else if (m_vRPN[sz-1].Val.data2==4) + m_vRPN[sz-2].Cmd = cmVARPOW4; + else + break; + + m_vRPN.pop_back(); + bOptimized = true; + } + break; + + case cmSUB: + case cmADD: + // Simple optimization based on pattern recognition for a shitload of different + // bytecode combinations of addition/subtraction + if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || + (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) || + (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || + (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) || + (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || + (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || + (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || + (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ) + { + assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) || + (m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) || + (m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ); + + m_vRPN[sz-2].Cmd = cmVARMUL; + m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); // variable + m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset + m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplicand + m_vRPN.pop_back(); + bOptimized = true; + } + break; + + case cmMUL: + if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || + (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ) + { + m_vRPN[sz-2].Cmd = cmVARMUL; + m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); + m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2; + m_vRPN[sz-2].Val.data2 = 0; + m_vRPN.pop_back(); + bOptimized = true; + } + else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || + (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ) + { + // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2 + m_vRPN[sz-2].Cmd = cmVARMUL; + m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); + if (m_vRPN[sz-1].Cmd == cmVAL) + { + m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2; + m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2; + } + else + { + m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2; + m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2; + } + m_vRPN.pop_back(); + bOptimized = true; + } + else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && + m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr) + { + // Optimization: a*a -> a^2 + m_vRPN[sz-2].Cmd = cmVARPOW2; + m_vRPN.pop_back(); + bOptimized = true; + } + break; + + case cmDIV: + if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-1].Val.data2!=0) + { + // Optimization: 4*a/2 -> 2*a + m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2; + m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2; + m_vRPN.pop_back(); + bOptimized = true; + } + break; + + } // switch a_Oprt + } + } + + // If optimization can't be applied just write the value + if (!bOptimized) + { + --m_iStackPos; + SToken tok; + tok.Cmd = a_Oprt; + m_vRPN.push_back(tok); + } + } + + //--------------------------------------------------------------------------- + void ParserByteCode::AddIfElse(ECmdCode a_Oprt) + { + 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_fun_type a_pFun, int a_iArgc) + { + if (a_iArgc>=0) + { + m_iStackPos = m_iStackPos - a_iArgc + 1; + } + else + { + // function with unlimited number of arguments + m_iStackPos = m_iStackPos + a_iArgc + 1; + } + m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); + + SToken tok; + tok.Cmd = cmFUNC; + tok.Fun.argc = a_iArgc; + tok.Fun.ptr = a_pFun; + m_vRPN.push_back(tok); + } + + //--------------------------------------------------------------------------- + /** \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_fun_type a_pFun, int a_iArgc) + { + m_iStackPos = m_iStackPos - a_iArgc + 1; + m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); + + SToken tok; + tok.Cmd = cmFUNC_BULK; + tok.Fun.argc = a_iArgc; + tok.Fun.ptr = a_pFun; + m_vRPN.push_back(tok); + } + + //--------------------------------------------------------------------------- + /** \brief Add Strung function entry to the parser bytecode. + \throw nothrow + + A string function entry consists of the stack position of the return value, + followed by a cmSTRFUNC code, the function pointer and an index into the + string buffer maintained by the parser. + */ + void ParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx) + { + 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.ptr = 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 + ParserStack 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.pop(); + m_vRPN[idx].Oprt.offset = i - idx; + break; + + case cmENDIF: + idx = stElse.pop(); + m_vRPN[idx].Oprt.offset = i - idx; + break; + + default: + break; + } + } + } + + //--------------------------------------------------------------------------- + const SToken* ParserByteCode::GetBase() const + { + if (m_vRPN.size()==0) + throw ParserError(ecINTERNAL_ERROR); + else + return &m_vRPN[0]; + } + + //--------------------------------------------------------------------------- + std::size_t ParserByteCode::GetMaxStackSize() const + { + return m_iMaxStackSize+1; + } + + //--------------------------------------------------------------------------- + /** \brief Returns the number of entries in the bytecode. */ + std::size_t ParserByteCode::GetSize() const + { + return m_vRPN.size(); + } + + //--------------------------------------------------------------------------- + /** \brief 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 \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "muParserCallback.h" + +/** \file + \brief Implementation of the parser callback class. +*/ + + +namespace mu +{ + //--------------------------------------------------------------------------- + ParserCallback::ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(0) + ,m_iPri(-1) + ,m_eOprtAsct(oaNONE) + ,m_iCode(cmFUNC) + ,m_iType(tpDBL) + ,m_bAllowOpti(a_bAllowOpti) + {} + + //--------------------------------------------------------------------------- + ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode) + :m_pFun((void*)a_pFun) + ,m_iArgc(1) + ,m_iPri(a_iPrec) + ,m_eOprtAsct(oaNONE) + ,m_iCode(a_iCode) + ,m_iType(tpDBL) + ,m_bAllowOpti(a_bAllowOpti) + {} + + + //--------------------------------------------------------------------------- + /** \brief Constructor for constructing function callbacks taking two arguments. + \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(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(multfun_type a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(-1) + ,m_iPri(-1) + ,m_eOprtAsct(oaNONE) + ,m_iCode(cmFUNC) + ,m_iType(tpDBL) + ,m_bAllowOpti(a_bAllowOpti) + {} + + + //--------------------------------------------------------------------------- + ParserCallback::ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(0) + ,m_iPri(-1) + ,m_eOprtAsct(oaNONE) + ,m_iCode(cmFUNC_STR) + ,m_iType(tpSTR) + ,m_bAllowOpti(a_bAllowOpti) + {} + + + //--------------------------------------------------------------------------- + ParserCallback::ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(1) + ,m_iPri(-1) + ,m_eOprtAsct(oaNONE) + ,m_iCode(cmFUNC_STR) + ,m_iType(tpSTR) + ,m_bAllowOpti(a_bAllowOpti) + {} + + + //--------------------------------------------------------------------------- + ParserCallback::ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti) + :m_pFun((void*)a_pFun) + ,m_iArgc(2) + ,m_iPri(-1) + ,m_eOprtAsct(oaNONE) + ,m_iCode(cmFUNC_STR) + ,m_iType(tpSTR) + ,m_bAllowOpti(a_bAllowOpti) + {} + + + //--------------------------------------------------------------------------- + /** \brief Default constructor. + \throw nothrow + */ + ParserCallback::ParserCallback() + :m_pFun(0) + ,m_iArgc(0) + ,m_iPri(-1) + ,m_eOprtAsct(oaNONE) + ,m_iCode(cmUNKNOWN) + ,m_iType(tpVOID) + ,m_bAllowOpti(0) + {} + + + //--------------------------------------------------------------------------- + /** \brief Copy constructor. + \throw nothrow + */ + ParserCallback::ParserCallback(const ParserCallback &ref) + { + m_pFun = ref.m_pFun; + m_iArgc = ref.m_iArgc; + m_bAllowOpti = ref.m_bAllowOpti; + m_iCode = ref.m_iCode; + m_iType = ref.m_iType; + m_iPri = ref.m_iPri; + m_eOprtAsct = ref.m_eOprtAsct; + } + + //--------------------------------------------------------------------------- + /** \brief Clone this instance and return a pointer to the new instance. */ + ParserCallback* ParserCallback::Clone() const + { + return new ParserCallback(*this); + } + + //--------------------------------------------------------------------------- + /** \brief Return tru if the function is conservative. + + Conservative functions return always the same result for the same argument. + \throw nothrow + */ + bool ParserCallback::IsOptimizable() const + { + return m_bAllowOpti; + } + + //--------------------------------------------------------------------------- + /** \brief Get the callback address for the parser function. + + The type of the address is void. It needs to be recasted according to the + argument number to the right type. + + \throw nothrow + \return #pFun + */ + void* ParserCallback::GetAddr() const + { + return m_pFun; + } + + //--------------------------------------------------------------------------- + /** \brief Return the callback code. */ + ECmdCode ParserCallback::GetCode() const + { + return m_iCode; + } + + //--------------------------------------------------------------------------- + ETypeCode ParserCallback::GetType() const + { + return m_iType; + } + + + //--------------------------------------------------------------------------- + /** \brief Return the operator precedence. + \throw nothrown + + Only valid if the callback token is an operator token (binary or infix). + */ + int ParserCallback::GetPri() const + { + return m_iPri; + } + + //--------------------------------------------------------------------------- + /** \brief Return the operators associativity. + \throw nothrown + + Only valid if the callback token is a binary operator token. + */ + EOprtAssociativity ParserCallback::GetAssociativity() const + { + return m_eOprtAsct; + } + + //--------------------------------------------------------------------------- + /** \brief Returns the number of function Arguments. */ + int ParserCallback::GetArgc() const + { + return m_iArgc; + } +} // namespace mu diff --git a/muparser-2.2.5_GR/src/muParserDLL.cc b/muparser-2.2.5_GR/src/muParserDLL.cc new file mode 100755 index 0000000..15c8800 --- /dev/null +++ b/muparser-2.2.5_GR/src/muParserDLL.cc @@ -0,0 +1,1096 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2004-2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#if defined(MUPARSER_DLL) + +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "muParserDLL.h" +#include "muParser.h" +#include "muParserInt.h" +#include "muParserError.h" + + +#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. + */ + +//--------------------------------------------------------------------------- +// private types +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() : NULL) + , exc() + , errHandler(NULL) + , 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]; + +//--------------------------------------------------------------------------- +// +// +// unexported functions +// +// +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +muParser_t* AsParser(muParserHandle_t a_hParser) +{ + return static_cast(a_hParser)->pParser; +} + +//--------------------------------------------------------------------------- +ParserTag* AsParserTag(muParserHandle_t a_hParser) +{ + return static_cast(a_hParser); +} + +//--------------------------------------------------------------------------- +#if defined(_WIN32) +#define _CRT_SECURE_NO_DEPRECATE + +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 NULL; + } +} + +//--------------------------------------------------------------------------- +/** \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 + sprintf(s_tmpOutBuf, "%s", p->GetVersion().c_str()); +#else + wsprintf(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 + assert(nNum != 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) 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) 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) 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) 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 + sprintf(s_tmpOutBuf, "%s", p->GetExpr().c_str()); +#else + wsprintf(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 cant 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(), sizeof(szName)); +#else + wcsncpy(szName, item->first.c_str(), sizeof(szName)); +#endif + + szName[sizeof(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 cant 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(), sizeof(szName)); +#else + wcsncpy(szName, item->first.c_str(), sizeof(szName)); +#endif + + szName[sizeof(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 cant 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(), sizeof(szName)); +#else + wcsncpy(szName, item->first.c_str(), sizeof(szName)); +#endif + + szName[sizeof(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 + sprintf(s_tmpOutBuf, "%s", pMsg); +#else + wsprintf(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 + sprintf(s_tmpOutBuf, "%s", pToken); +#else + wsprintf(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(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser) +//{ +// return AsParserTag(a_hParser)->exc.GetExpr().c_str(); +//} + +//----------------------------------------------------------------------------------------------------- +API_EXPORT(muFloat_t*) mupCreateVar() +{ + return new muFloat_t(0); +} + +//----------------------------------------------------------------------------------------------------- +API_EXPORT(void) mupReleaseVar(muFloat_t *ptr) +{ + delete ptr; +} + +#endif // MUPARSER_DLL diff --git a/muparser-2.2.5_GR/src/muParserError.cc b/muparser-2.2.5_GR/src/muParserError.cc new file mode 100755 index 0000000..6fe4e1d --- /dev/null +++ b/muparser-2.2.5_GR/src/muParserError.cc @@ -0,0 +1,337 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "muParserError.h" + + +namespace mu +{ + const ParserErrorMsg ParserErrorMsg::m_Instance; + + //------------------------------------------------------------------------------ + const ParserErrorMsg& ParserErrorMsg::Instance() + { + return m_Instance; + } + + //------------------------------------------------------------------------------ + string_type ParserErrorMsg::operator[](unsigned a_iIdx) const + { + return (a_iIdx \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2011 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#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)); +} + +//--------------------------------------------------------------------------- +// Unary operator Callbacks: Infix operators +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> 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) ); + *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 wont 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 diff --git a/muparser-2.2.5_GR/src/muParserTest.cc b/muparser-2.2.5_GR/src/muParserTest.cc new file mode 100755 index 0000000..4006b27 --- /dev/null +++ b/muparser-2.2.5_GR/src/muParserTest.cc @@ -0,0 +1,1552 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "muParserTest.h" + +#include +#include +#include +#include + +#define PARSER_CONST_PI 3.141592653589793238462643 +#define PARSER_CONST_E 2.718281828459045235360287 + +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); + + 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::TestStrArg() + { + int iStat = 0; + mu::console() << _T("testing string arguments..."); + + 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); + // string constants + iStat += EqnTest(_T("atof(str1)+atof(str2)"), 3.33, 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("+"), 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..."); + + // 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); + + 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"), -PARSER_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"), 123+2, true); + iStat += EqnTest( _T("~~ 123"), 123+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; + + // 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..."); + + // Test error detection + iStat += ThrowTest(_T(":3"), ecUNEXPECTED_CONDITIONAL); + iStat += ThrowTest(_T("? 1 : 2"), ecUNEXPECTED_CONDITIONAL); + iStat += ThrowTest(_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); + } + + //--------------------------------------------------------------------------- + void 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; + } + + + //--------------------------------------------------------------------------- + int ParserTester::ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail) + { + 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.SetExpr(a_str); + p.Eval(); + } + catch(ParserError &e) + { + // output the formula in case of an failed test + if (a_bFail==false || (a_bFail==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_bFail==false no exception is expected + bool bRet((a_bFail==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[5] = {-999, -998, -997, -996, -995}; // initially should be different + + try + { + std::auto_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"), (value_type)PARSER_CONST_PI); + p1->DefineConst( _T("e"), (value_type)PARSER_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("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("lastArg"), LastArg); + p1->DefineFun( _T("firstArg"), FirstArg); + p1->DefineFun( _T("order"), FirstArg); + + // 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 p2 = vParser[0]; // take parser from vector + + // destroy the originals from p2 + vParser.clear(); // delete the vector + p1.reset(0); + + fVal[2] = p2.Eval(); + + // Test assignment operator + // additionally disable Optimizer this time + mu::Parser p3; + p3 = p2; + p3.EnableOptimizer(false); + fVal[3] = p3.Eval(); + + // Test Eval function for multiple return values + // use p2 since it has the optimizer enabled! + int nNum; + value_type *v = p2.Eval(nNum); + fVal[4] = 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::has_infinity) + #pragma warning(pop) + { + 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(")."); + } + } + 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 diff --git a/muparser-2.2.5_GR/src/muParserTokenReader.cc b/muparser-2.2.5_GR/src/muParserTokenReader.cc new file mode 100755 index 0000000..8da1e40 --- /dev/null +++ b/muparser-2.2.5_GR/src/muParserTokenReader.cc @@ -0,0 +1,958 @@ +/* + __________ + _____ __ __\______ \_____ _______ ______ ____ _______ + / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ + | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ + |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| + \/ \/ \/ \/ + Copyright (C) 2013 Ingo Berg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include +#include +#include +#include +#include +#include + +#include "muParserTokenReader.h" +#include "muParserBase.h" + +/** \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_iBrackets = a_Reader.m_iBrackets; + 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(NULL) + ,m_pPostOprtDef(NULL) + ,m_pInfixOprtDef(NULL) + ,m_pOprtDef(NULL) + ,m_pConstDef(NULL) + ,m_pStrVarDef(NULL) + ,m_pVarDef(NULL) + ,m_pFactory(NULL) + ,m_pFactoryData(NULL) + ,m_vIdentFun() + ,m_UsedVar() + ,m_fZero(0) + ,m_iBrackets(0) + ,m_lastTok() + ,m_cArgSep(',') + { + assert(m_pParser); + 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::auto_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_iBrackets = 0; + m_UsedVar.clear(); + m_lastTok = token_type(); + } + + //--------------------------------------------------------------------------- + /** \brief Read the next token from the string. */ + ParserTokenReader::token_type ParserTokenReader::ReadNextToken() + { + assert(m_pParser); + + const char_type *szFormula = m_strFormula.c_str(); + token_type tok; + + // Ignore all non printable characters when reading the expression + while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20) + ++m_iPos; + + if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula + if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator + if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token + if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens + if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators + if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens + if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens + if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables + if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens + if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators + if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators + + // 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; + int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, 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, + int a_iPos) const + { + int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos); + + if (iEnd==(int)string_type::npos) + iEnd = (int)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 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, + int a_iPos) const + { + // Changed as per Issue 6: https://code.google.com/p/muparser/issues/detail?id=6 + int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidOprtChars(), a_iPos); + if (iEnd==(int)string_type::npos) + iEnd = (int)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 iEnd; + } + else + { + // There is still the chance of having to deal with an operator consisting exclusively + // of alphabetic characters. + return ExtractToken(MUP_CHARS, a_sTok, 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 cmAND: + //case cmOR: + //case cmXOR: + 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: + //if (len!=sTok.length()) + // continue; + + // 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_iBrackets; + 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_iBrackets<0) + 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; + break; + + case cmIF: + if (m_iSynFlags & noIF) + Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); + + m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; + 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_iBrackets>0) + 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; + int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, 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; + 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; + int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, 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; + + int iEnd = ExtractOperatorToken(strTok, 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; + int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, 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) + { + assert(m_pConstDef); + assert(m_pParser); + + string_type strTok; + value_type fVal(0); + int iEnd(0); + + // 2.) Check for user defined constant + // Read everything that could be a constant name + iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, 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, 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; + int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, 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; + int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, 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; + int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, 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[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 wg Anführungszeichen; +iSkip für entfernte escape zeichen + 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 +