ENDIF()
-IF(FEATURE_FUNCTIONPARSER_BUNDLED_CONFIGURED)
- ADD_SUBDIRECTORY(${FUNCTIONPARSER_FOLDER})
-ENDIF()
+#IF(FEATURE_FUNCTIONPARSER_BUNDLED_CONFIGURED)
+# ADD_SUBDIRECTORY(${FUNCTIONPARSER_FOLDER})
+#ENDIF()
IF(FEATURE_THREADS_BUNDLED_CONFIGURED)
ENDIF()
+IF(FEATURE_MUPARSER_BUNDLED_CONFIGURED)
+ ADD_SUBDIRECTORY(${MUPARSER_FOLDER})
+ENDIF()
+
+
+
MESSAGE(STATUS "Setting up bundled features - Done")
--- /dev/null
+## ---------------------------------------------------------------------
+## $Id: CMakeLists.txt 32392 2014-02-03 16:24:36Z heister $
+##
+## Copyright (C) 2012 - 2013 by the deal.II authors
+##
+## This file is part of the deal.II library.
+##
+## The deal.II library is free software; you can use it, redistribute
+## it, and/or modify it under the terms of the GNU Lesser General
+## Public License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+## The full text of the license can be found in the file LICENSE at
+## the top level of the deal.II distribution.
+##
+## ---------------------------------------------------------------------
+
+#
+# avoid some annoying warnings...
+#
+STRIP_FLAG(DEAL_II_CXX_FLAGS "-Wall")
+STRIP_FLAG(DEAL_II_CXX_FLAGS "-pedantic")
+ENABLE_IF_SUPPORTED(DEAL_II_CXX_FLAGS -Wno-switch)
+
+INCLUDE_DIRECTORIES(
+ include/
+)
+
+DEAL_II_ADD_LIBRARY(obj_muparser OBJECT
+src/muParserBase.cpp
+src/muParserBytecode.cpp
+src/muParserCallback.cpp
+src/muParser.cpp
+src/muParserError.cpp
+src/muParserInt.cpp
+src/muParserTest.cpp
+src/muParserTokenReader.cpp
+ )
+
+#IF(DEAL_II_WITH_THREADS)
+# DEAL_II_ADD_DEFINITIONS(obj_muparser "FP_USE_THREAD_SAFE_EVAL")
+#ENDIF()
--- /dev/null
+#######################################################################\r
+# #\r
+# #\r
+# __________ #\r
+# _____ __ __\______ \_____ _______ ______ ____ _______ #\r
+# / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ #\r
+# | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ #\r
+# |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| #\r
+# \/ \/ \/ \/ #\r
+# Fast math parser Library #\r
+# #\r
+# Copyright (C) 2013 Ingo Berg #\r
+# #\r
+# Web: muparser.beltoforion.de #\r
+# e-mail: muparser@beltoforion.de #\r
+# #\r
+# #\r
+#######################################################################\r
+\r
+\r
+History:\r
+--------\r
+\r
+Rev 2.2.3: 22.12.2012\r
+---------------------\r
+\r
+ Removed features:\r
+ * build files for msvc2005, borland and watcom compiler were removed\r
+\r
+ Bugfixes:\r
+ * Bugfix for Intel Compilers added: The power operator did not work properly \r
+ with Intel C++ composer XE 2011.\r
+ (see https://sourceforge.net/projects/muparser/forums/forum/462843/topic/5117983/index/page/1)\r
+ * Issue 3509860: Callbacks of functions with string parameters called twice\r
+ (see http://sourceforge.net/tracker/?func=detail&aid=3509860&group_id=137191&atid=737979)\r
+ * Issue 3570423: example1 shows slot number in hexadecimal\r
+ (see https://sourceforge.net/tracker/?func=detail&aid=3570423&group_id=137191&atid=737979)\r
+ * Fixes for compiling with the "MUP_MATH_EXCEPTIONS" macro definition:\r
+ - division by zero in constant expressions was reported with the code "ec_GENERIC" \r
+ instead of "ecDIV_BY_ZERO"\r
+ - added throwing of "ecDOMAIN_ERROR" to sqrt and log functions\r
+\r
+\r
+Rev 2.2.2: 18.02.2012\r
+---------------------\r
+ Bugfixes:\r
+ * Optimizer did'nt work properly for division:\r
+ (see https://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825)\r
+\r
+Rev 2.2.1: 22.01.2012\r
+---------------------\r
+ Bugfixes:\r
+ * Optimizer bug in 64 bit systems fixed\r
+ (see https://sourceforge.net/projects/muparser/forums/forum/462843/topic/4977977/index/page/1)\r
+ \r
+Rev 2.2.0: 22.01.2012\r
+---------------------\r
+ Improvements:\r
+ * Optimizer rewritten and improved. In general: more optimizations are \r
+ now applied to the bytecode. The downside is that callback Functions \r
+ can no longer be flagged as non-optimizable. (The flag is still present \r
+ but ignored) This is necessary since the optimizer had to call the \r
+ functions in order to precalculate the result (see Bugfixes). These calls \r
+ posed a problems for callback functions with side effects and if-then-else \r
+ clauses in general since they undermined the shortcut evaluation prinziple.\r
+\r
+ Bugfixes:\r
+ * Infix operators where not properly detected in the presence of a constant \r
+ name starting with an underscore which is a valid character for infix \r
+ operators too (i.e. "-_pi").\r
+ * Issue 3463353: Callback functions are called twice during the first call to eval.\r
+ * Issue 3447007: GetUsedVar unnecessaryly executes callback functions.\r
+\r
+\r
+Rev 2.1.0: 19.11.2011\r
+---------------------\r
+ New feature:\r
+ * Function atan2 added\r
+\r
+ Bugfixes:\r
+ * Issue 3438380: Changed behaviour of tellg with GCC >4.6 led to failures \r
+ in value detection callbacks.\r
+ * Issue 3438715: only "double" is a valid MUP_BASETYPE \r
+ MUP_BASETYPE can now be any of:\r
+ float, \r
+ double, \r
+ long double, \r
+ short, \r
+ unsigned short, \r
+ unsigned int, \r
+ long,\r
+ unsigned long. \r
+ Previousely only floating point types were allowed. \r
+ Using "int" is still not allowed!\r
+ * Compiler issues with GCC 4.6 fixed\r
+ * Custom value recognition callbacks added with AddValIdent had lower\r
+ priority than built in functions. This was causing problems with \r
+ hex value recognition since detection of non hex values had priority\r
+ over the detection of hex values. The "0" in the hex prefix "0x" would \r
+ be read as a separate non-hex number leaving the rest of the expression\r
+ unparseable.\r
+\r
+Rev 2.0.0: 04.09.2011\r
+---------------------\r
+This release introduces a new version numbering scheme in order to make\r
+future changes in the ABI apparent to users of the library. The number is\r
+now based on the SONAME property as used by GNU/Linux. \r
+\r
+ Changes:\r
+ * Beginning with this version all version numbers will be SONAME compliant\r
+ * Project files for MSVC2010 added\r
+ * Project files for MSVC2003 removed\r
+ * Bytecode parsing engine cleaned up and rewritten\r
+ * Retrieving all results of expressions made up of comma separate \r
+ subexpressions is now possible with a new Eval overload.\r
+ * Callback functions with fixed number of arguments can now have up to 10 \r
+ Parameters (previous limit was 5)\r
+\r
+ New features:\r
+ * ternary if-then-else operator added (C++ like; "(...) ? ... : ..." )\r
+ * new intrinsic binary operators: "&&", "||" (logical and, or)\r
+ * A new bulkmode allows submitting large arrays as variables to compute large \r
+ numbers of expressions with a single call. This can drastically improve \r
+ parsing performance when interfacing the library from managed languages like \r
+ C#. (It doesn't bring any performance benefit for C++ users though...)\r
+\r
+ Removed features:\r
+ * intrinsic "and", "or" and "xor" operators have been removed. I'd like to let \r
+ users the freedom of defining them on their own versions (either as logical or bitwise \r
+ operators).\r
+ * Implementation for complex numbers removed. This was merely a hack. If you \r
+ need complex numbers try muParserX which provides native support for them.\r
+ (see: http://beltoforion.de/muparserx/math_expression_parser_en.html)\r
+\r
+ Bugfixes:\r
+ * User defined operators could collide with built in operators that entirely \r
+ contained their identifier. i.e. user defined "&" would not work with the built \r
+ in "&&" operator since the user defined operator was detected with a higher \r
+ priority resulting in a syntax error.\r
+ * Detection of unknown variables did not work properly in case a postfix operator\r
+ was defined which was part of the undefined variable.\r
+ i.e. If a postfix operator "m" was defined expressions like "multi*1.0" did\r
+ not detect "multi" as an undefined variable.\r
+ (Reference: http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979)\r
+ * Postfix operators sharing the first few characters were causing bogus parsing exception.\r
+ (Reference: https://sourceforge.net/tracker/?func=detail&aid=3358571&group_id=137191&atid=737979)\r
+\r
+Rev 1.34: 04.09.2010\r
+--------------------\r
+ Changes:\r
+ * The prefix needed for parsing hex values is now "0x" and no longer "$". \r
+ * AddValIdent reintroduced into the DLL interface\r
+\r
+ New features:\r
+ * The associativity of binary operators can now be changed. The pow operator \r
+ is now right associative. (This is what Mathematica is using) \r
+ * Seperator can now be used outside of functions. This allows compound \r
+ expressions like:\r
+ "a=10,b=20,c=a*b" The last "argument" will be taken as the return value\r
+\r
+ Bugfixes: \r
+ * The copy constructor did not copy binary operator definitions. Those were lost\r
+ in the copied parser instance.\r
+ * Mixing special characters and alphabetic characters in binary operator names \r
+ led to inconsistent parsing behaviour when parsing expressions like "a ++ b" \r
+ and "a++b" when "++" is defined as a binary operator. Binary operators must \r
+ now consist entirely of special characters or of alphabetic ones.\r
+ (original bug report: https://sourceforge.net/projects/muparser/forums/forum/462843/topic/3696881/index/page/1)\r
+ * User defined operators were not exactly handled like built in operators. This \r
+ led to inconsistencies in expression evaluation when using them. The results \r
+ differed due to slightly different precedence rules.\r
+ * Using empty string arguments ("") would cause a crash of muParser\r
+\r
+\r
+Rev 1.32: 29.01.2010 \r
+--------------------\r
+\r
+ Changes:\r
+ * "example3" renamed to "example2"\r
+ * Project/Makefiles files are now provided for:\r
+ - msvc2003 \r
+ - msvc2005 \r
+ - msvc2008\r
+ - watcom (makefile)\r
+ - mingw (makefile)\r
+ - bcc (makefile)\r
+ * Project files for borland cpp builder were removed\r
+\r
+\r
+ New features:\r
+ * Added function returning muparsers version number\r
+ * Added function for resetting the locale\r
+\r
+\r
+ Bugfixes: \r
+ * Changes example1 in order to fix issues with irritating memory leak reports. \r
+ Added conditional code for memory leak detection with MSVC in example1.\r
+ (see: http://www.codeproject.com/KB/recipes/FastMathParser.aspx?msg=3286367#xx3286367xx)\r
+ * Fixed some warnings for gcc\r
+\r
+\r
+\r
+Rev 1.31cp: 15.01.2010 (Maintainance release for CodeProject)\r
+----------------------\r
+\r
+ Changes:\r
+ * Archive structure changed\r
+ * C# wrapper added\r
+ * Fixed issued that prevented compiling with VS2010 Beta2\r
+ \r
+\r
+Rev 1.30: 09.06.2008\r
+--------------------\r
+\r
+ Changes:\r
+ * Epsilon of the numerical differentiation algorithm changed to allow greater accuracy.\r
+\r
+ New features:\r
+ * Setting thousands separator and decimal separator is now possible\r
+\r
+ Bugfixes:\r
+ * The dll interface did not provide a callback for functions without any arguments. \r
+ \r
+\r
+Rev 1.29: Januar 2008\r
+---------------------\r
+\r
+ Unrelease Version available only via SVN.\r
+\r
+\r
+Rev 1.28: 02. July, 2007\r
+---------------------------\r
+ \r
+ Library changes:\r
+ * Interface for the dynamic library changed and extended to create an interface \r
+ using pure C functions only. \r
+ * mupInit() removed\r
+\r
+ Build system:\r
+ * MSVC7 Project files removed in favor of MSVC8\r
+\r
+ Bugfixes:\r
+ * The dynamic library did not build on other systems than linux due to a misplaced \r
+ preprocessor definition. This is fixed now.\r
+\r
+\r
+Rev 1.27:\r
+---------------------------\r
+\r
+ Build system:\r
+ * Modified build\ directory layout introducing some subfolders \r
+ for the various IDE supported\r
+ * Project files for BCB and MSVC7 added\r
+ * Switched to use bakefile 0.2.1 which now correctly creates the \r
+ "make uninstall" target for autoconf's Makefile.in\r
+ * Now the library debug builds are named "muparserd" instead of "muparser"\r
+ to allow multiple mixed release/debug builds to coexist; so e.g. on Windows\r
+ when building with DEBUG=1, you'll get "muparserd.lib" instead of "muparser.lib"\r
+\r
+ New Features:\r
+ * Factory functions can now take a user defined pointer\r
+ * String functions can now be used with up to two additional \r
+ double parameters\r
+ * Support for UNICODE character types added\r
+ * Infix operator priority can now be changed by the user\r
+\r
+ Bugfixes:\r
+ * An internal error was raised when evaluating an empty \r
+ expressions\r
+ * The error message raised in case of name collisions between \r
+ implicitely defined variables and postfix operators did contain\r
+ misleading data.\r
+\r
+\r
+Rev 1.26: (unofficial release)\r
+------------------------------\r
+\r
+ New Features:\r
+ * Unary operator precedence can now be changed by the user.\r
+\r
+\r
+Rev 1.25: 5. February, 2006\r
+---------------------------\r
+\r
+ Build system: (special thanks to Francesco Montorsi for implementing it!)\r
+ * created a bakefile-based build system which adds support for the following win32 compilers:\r
+ -> MS visual C++ (6 and .NET)\r
+ -> BorlandC++ (5 or greater)\r
+ -> Mingw32 (tested with gcc 3.2)\r
+ -> Watcom (not tested)\r
+ and for GCC on Unix (using a standard autoconf's configure script).\r
+\r
+ Compatibility improvements:\r
+ * fixed some small warnings when using -Wall with GCC on Unix\r
+ * added inclusion guards for win32-specific portions of code\r
+ * added fixes that remove compiler warnings on Intel C++ and the Solaris C++ compiler.\r
+\r
+\r
+Rev 1.24: 29. October, 2005\r
+---------------------------\r
+\r
+Changes:\r
+\r
+ Compatibility improvements:\r
+ * parser now works on 64 bit compilers\r
+ * (bytecode base datatype can now be changed freely)\r
+\r
+\r
+Rev 1.23: 19. October, 2005\r
+---------------------------\r
+\r
+Changes:\r
+\r
+ Bugfixes:\r
+ * Variable factory examples in Example1.cpp and Example3.cpp contained a subtle bug.\r
+\r
+ New features:\r
+ * Added a MSVC6 project file and introduced muParserFixes.h in order to make it compile with MSVC6\r
+\r
+\r
+Rev 1.22: October, 2005\r
+-----------------------\r
+\r
+Release notes:\r
+\r
+All features of Version 1.22 are similar to Version 1.21. Version 1.22 fixes a compilation issue with\r
+gcc 4.0. In order to fix this issue I rewrote part of the library to remove some unnecessary templates. \r
+This should make the code cleaner. The Borland Project files were removed. If you want to use it \r
+with Borland either use the dll version or create your own project files. I can't support it since I don't \r
+have this compiler at hand.\r
+\r
+Changes:\r
+\r
+ Project Changes:\r
+ * Borland project files removed\r
+ (The code should still compile with BCB but I cant provide you with project files)\r
+\r
+ Internal Changes:\r
+ * unnecessary template files have been removed:\r
+ - new files: muParserError.cpp, muParserTokenReader.cpp, muParserCallback.cpp\r
+ - removed Files: muIParserTypes.h\r
+\r
+\r
+Rev 1.2 / 1.21: April, 2005\r
+---------------------------\r
+\r
+Release Notes:\r
+First of all the interface has changed so this version is not backwards compatible.\r
+After receiving a couple of questions about it, this version features support for\r
+user defined binary operators. Consequently the built in operators can now be \r
+turned off, thus you can deactivate them and write complete customized parser\r
+subclasses that only contain the functionality you want. Another new feature is \r
+the introduction of callback functions taking string arguments, implicit \r
+generation of variables and the Assignement operator.\r
+\r
+ Functionality\r
+ * New built in operator: xor; Logical xor.\r
+ * New built in operator: Assignement operator; Defining variables in terms of \r
+ other variables/constants\r
+ * New feature: Strings as arguments for callback functions\r
+ * New feature: User defined binary operators\r
+ * New feature: ParserInt a class with a sample implementation for\r
+ integer numbers.\r
+ * New feature: Callbacks to value regognition functions.\r
+\r
+ * Removed: all predefined postfix operators have been removed.\r
+ * New project file: Now comes with a ready to use windows DLL.\r
+ * New project file: Makefile for cygwin now included.\r
+ * New example: Example3 shows usage of the DLL.\r
+\r
+ Interface changes\r
+ * New member function: DefineOprt For adding user defined binary operators.\r
+ * New member function: EnableBuiltInOprt(bool) Enables/Disables built in \r
+ binary operators.\r
+ * New member function: AddValIdent(...) to add callbacks for custom value \r
+ recognition functions.\r
+ * Removed: SetVar(), SetConst().\r
+ * Renamed: Most interface functions have been renamed\r
+ * Changed: The type for multiargument callbacks multfun_type has changed. \r
+ It no longer takes a std::vector as input.\r
+\r
+ Internal changes\r
+ * new class muParserTokenReader.h encapsulates the token identification \r
+ and token assignement.\r
+ * Internal handling of function callbacks unified as a result the performance \r
+ of the bytecode evaluation increased.\r
+\r
+\r
+Rev 1.10 : December 30, 2004\r
+----------------------------\r
+\r
+Release Notes:\r
+This version does not contain major new feature compared to V1.07 but its internal structure has\r
+changed significantly. The String parsing routine is slower than the one of V1.07 but bytecode\r
+parsing is equally fast. On the other hand the error messages of V1.09 are more flexible and you\r
+can change its value datatype. It should work on 64-bit systems. For this reason I supply both\r
+versions for download. If you use V1.07 and are happy with it there is no need for updating\r
+your version.\r
+\r
+ * New example program: Archive now contains two demo programs: One for standard C++ and one for\r
+ managed C++.\r
+ * New member function: RemoveVar(...) can be used for removing a single variable from the internal \r
+ storage.\r
+ * New member function: GetVar() can be used for querying the variable names and pointers of all\r
+ variables defined in the parser.\r
+ * New member function: GetConst() can be used for querying all defined constants and their values.\r
+ * New member function: GetFunDef() can be used for querying all defined functions and the number of\r
+ arguments they expect.\r
+ * Internal structure changed; hanging base datatype at compile time is now possible.\r
+ * Bugfix: Postfix operator parsing could fail in certain cases; This has been fixed now.\r
+ * Bugfix: Variable names must will now be tested if they conflict with constant or function names.\r
+ * Internal change: Removed most dependencies from the C-string libraries.\r
+ * Internal change: Bytecode is now stored in a separate class: ParserByteCode.h\r
+ * Internal change: GetUsedVar() does no longer require that variables are defined at time of call.\r
+ * Internal change: Error treatment changed. ParserException is no longer derived from\r
+ std::runtime_error; Internal treatment of Error messages changed.\r
+ * New functions in Parser interface: ValidNameChars(), ValidOprtChars() and ValidPrefixOprtChars()\r
+ they are used for defining the charset allowed for variable-, operator- and\r
+ function names.\r
+\r
+\r
+Rev 1.09 : November 20, 2004\r
+----------------------------\r
+\r
+ * New member function: RemoveVar(...) can be used for removing a single variable from the internal \r
+ storage.\r
+ * Internal structure changed; changing base datatype at compile time is now possible.\r
+ * Bug fix: Postfix operator parsing could fail in certain cases; This has been fixed now.\r
+ * Internal change: Removed most dependencies from the C-string libraries.\r
+ * Internal change: Bytecode is now stored in a seperate class: ParserByteCode.h.\r
+ * Internal change: GetUsedVar() does no longer require that variables are defined at time of call.\r
+ * Internal change: Error treatment changed. ParserException is no longer derived from \r
+ std::runtime_error; Internal treatment of Error messages changed.\r
+ * New functions in Parser interface; ValidNameChars(), ValidOprtChars() and ValidPrefixOprtChars()\r
+ they are used for defining the charset allowed for variable-, operator- and function names.\r
+\r
+\r
+Rev 1.08 : November, 2004 \r
+-------------------------\r
+\r
+ * unpublished; experimental template version with respect to data type and underlying string\r
+ type (string <-> widestring). The idea was dropped...\r
+\r
+\r
+Rev 1.07 : September 4 2004\r
+---------------------------\r
+\r
+ * Improved portability; Changes to make life for MSVC 6 user easier, there are probably still some\r
+ issues left.\r
+ * Improved portability; Changes in order to allow compiling on BCB.\r
+ * New function; value_type Diff(value_type *a_Var, value_type a_fPos) 4th order Differentiation with\r
+ respect to a certain variable; added in muParser.h.\r
+\r
+\r
+Rev 1.06 : August 20 2004\r
+-------------------------\r
+\r
+ * Volatile functions added; All overloaded AddFun(...) functions can now take a third parameter\r
+ indicating that the function can not be optimized.\r
+ * Internal changes: muParserStack.h simplified; refactorings\r
+ * Parser is now distributed under the MIT License; all comments changed accordingly.\r
+\r
+\r
+Rev 1.05 : August 20 2004\r
+-------------------------\r
+\r
+ * Variable/constant names will now be checked for invalid characters.\r
+ * Querying the names of all variables used in an expression is now possible; new function: GetUsedVar().\r
+ * Disabling bytecode parsing is now possible; new function: EnableByteCode(bool bStat).\r
+ * Predefined functions with variable number of arguments added: sum, avg, min, max.\r
+ * Unary prefix operators added; new functions: AddPrefixOp(...), ClearPrefixOp().\r
+ * Postfix operator interface names changed; new function names: AddPostfixOp(...), ClearPostfixOp().\r
+ * Hardcoded sign operators removed in favor of prefix operators; bytecode format changed accordingly.\r
+ * Internal changes: static array removed in Command code calculation routine; misc. changes.\r
+\r
+\r
+Rev 1.04 : August 16 2004\r
+-------------------------\r
+\r
+ * Support for functions with variable number of arguments added.\r
+ * Internal structure changed; new: ParserBase.h, ParserBase.cpp; removed: ParserException.h;\r
+ changed: Parser.h, Parser.cpp.\r
+ * Bug in the bytecode calculation function fixed (affected the unary minus operator).\r
+ * Optimizer can be deactivated; new function: EnableOptimizer(bool bStat).\r
+\r
+\r
+Rev 1.03 : August 10 2004\r
+-------------------------\r
+\r
+ * Support for user-defined unary postfix operators added; new functions: AddPostOp(), InitPostOp(),\r
+ ClearPostOp().\r
+ * Minor changes to the bytecode parsing routine.\r
+ * User defined functions can now have up to four parameters.\r
+ * Performance optimized: simple formula optimization added; (precalculation of constant parts of the\r
+ expression).\r
+ * Bug fixes: Multi-arg function parameters, constant name lookup and unary minus did not work properly.\r
+\r
+\r
+Rev 1.02 : July 30 2004\r
+-----------------------\r
+\r
+ * Support for user defined constants added; new functions: InitConst(), AddConst(), SetConst(),\r
+ ClearConst().\r
+ * Single variables can now be added using AddVar(); you have now the choice of adding them either\r
+ one by one or all at the same time using SetVar(const varmap_type &a_vVar).\r
+ * Internal handling of variables changed, is now similar to function handling.\r
+ * Virtual destructor added; InitFun(), InitConst() are now virtual too thus making it possible to\r
+ derive new parsers with a modified set of default functions and constants.\r
+ * Support for user defined functions with 2 or 3 parameters added; bytecode format changed to hold\r
+ function parameter count.\r
+\r
+\r
+Rev 1.01 : July 23 2004\r
+-----------------------\r
+\r
+ * Support for user defined functions has been added; new functions: AddFun(), ClearFun(),\r
+ InitFunctions().\r
+ * Built in constants have been removed; the parser contained undocumented built in\r
+ constants pi, e.\r
+ There was the possibility of name conflicts with user defined variables.\r
+ * Setting multiple variables with SetVar can now be done with a map of names and pointers as the only\r
+ argument. For this reason, a new type Parser::varmap_type was added. The old version that took 3\r
+ arguments (array of names, array of pointers, and array length) is now marked as deprecated.\r
+ * The names of logarithm functions have changed. The new names are: log2 for base 2, log10 or log for\r
+ base 10, and ln for base e.\r
+\r
+\r
+Rev 1.00 : July 21 2004\r
+-----------------------\r
+\r
+ * Initial release\r
--- /dev/null
+#######################################################################\r
+# #\r
+# #\r
+# __________ #\r
+# _____ __ __\______ \_____ _______ ______ ____ _______ #\r
+# / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ #\r
+# | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ #\r
+# |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| #\r
+# \/ \/ \/ \/ #\r
+# Fast math parser Library #\r
+# #\r
+# Copyright (C) 2011 Ingo Berg #\r
+# #\r
+# Web: muparser.beltoforion.de #\r
+# e-mail: muparser@beltoforion.de #\r
+# #\r
+# #\r
+#######################################################################\r
+\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+ OR OTHER DEALINGS IN THE SOFTWARE.\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+#ifndef MU_PARSER_H\r
+#define MU_PARSER_H\r
+\r
+//--- Standard includes ------------------------------------------------------------------------\r
+#include <vector>\r
+\r
+//--- Parser includes --------------------------------------------------------------------------\r
+#include "muParserBase.h"\r
+#include "muParserTemplateMagic.h"\r
+\r
+/** \file\r
+ \brief Definition of the standard floating point parser.\r
+*/\r
+\r
+namespace mu\r
+{\r
+ /** \brief Mathematical expressions parser.\r
+ \r
+ Standard implementation of the mathematical expressions parser. \r
+ Can be used as a reference implementation for subclassing the parser.\r
+\r
+ <small>\r
+ (C) 2011 Ingo Berg<br>\r
+ muparser(at)gmx.de\r
+ </small>\r
+ */\r
+ /* final */ class Parser : public ParserBase\r
+ {\r
+ public:\r
+\r
+ Parser();\r
+\r
+ virtual void InitCharSets();\r
+ virtual void InitFun();\r
+ virtual void InitConst();\r
+ virtual void InitOprt();\r
+ virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd);\r
+\r
+ value_type Diff(value_type *a_Var, \r
+ value_type a_fPos, \r
+ value_type a_fEpsilon = 0) const;\r
+\r
+ protected:\r
+\r
+ // Trigonometric functions\r
+ static value_type Sin(value_type);\r
+ static value_type Cos(value_type);\r
+ static value_type Tan(value_type);\r
+ static value_type Tan2(value_type, value_type);\r
+ // arcus functions\r
+ static value_type ASin(value_type);\r
+ static value_type ACos(value_type);\r
+ static value_type ATan(value_type);\r
+ static value_type ATan2(value_type, value_type);\r
+\r
+ // hyperbolic functions\r
+ static value_type Sinh(value_type);\r
+ static value_type Cosh(value_type);\r
+ static value_type Tanh(value_type);\r
+ // arcus hyperbolic functions\r
+ static value_type ASinh(value_type);\r
+ static value_type ACosh(value_type);\r
+ static value_type ATanh(value_type);\r
+ // Logarithm functions\r
+ static value_type Log2(value_type); // Logarithm Base 2\r
+ static value_type Log10(value_type); // Logarithm Base 10\r
+ static value_type Ln(value_type); // Logarithm Base e (natural logarithm)\r
+ // misc\r
+ static value_type Exp(value_type);\r
+ static value_type Abs(value_type);\r
+ static value_type Sqrt(value_type);\r
+ static value_type Rint(value_type);\r
+ static value_type Sign(value_type);\r
+\r
+ // Prefix operators\r
+ // !!! Unary Minus is a MUST if you want to use negative signs !!!\r
+ static value_type UnaryMinus(value_type);\r
+\r
+ // Functions with variable number of arguments\r
+ static value_type Sum(const value_type*, int); // sum\r
+ static value_type Avg(const value_type*, int); // mean value\r
+ static value_type Min(const value_type*, int); // minimum\r
+ static value_type Max(const value_type*, int); // maximum\r
+\r
+ static int IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal);\r
+ };\r
+} // namespace mu\r
+\r
+#endif\r
+\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+#ifndef MU_PARSER_BASE_H\r
+#define MU_PARSER_BASE_H\r
+\r
+//--- Standard includes ------------------------------------------------------------------------\r
+#include <cmath>\r
+#include <string>\r
+#include <iostream>\r
+#include <map>\r
+#include <memory>\r
+#include <locale>\r
+\r
+//--- Parser includes --------------------------------------------------------------------------\r
+#include "muParserDef.h"\r
+#include "muParserStack.h"\r
+#include "muParserTokenReader.h"\r
+#include "muParserBytecode.h"\r
+#include "muParserError.h"\r
+\r
+\r
+namespace mu\r
+{\r
+/** \file\r
+ \brief This file contains the class definition of the muparser engine.\r
+*/\r
+\r
+//--------------------------------------------------------------------------------------------------\r
+/** \brief Mathematical expressions parser (base parser engine).\r
+ \author (C) 2013 Ingo Berg\r
+\r
+ This is the implementation of a bytecode based mathematical expressions parser. \r
+ The formula will be parsed from string and converted into a bytecode. \r
+ Future calculations will be done with the bytecode instead the formula string\r
+ resulting in a significant performance increase. \r
+ Complementary to a set of internally implemented functions the parser is able to handle \r
+ user defined functions and variables. \r
+*/\r
+class ParserBase \r
+{\r
+friend class ParserTokenReader;\r
+\r
+private:\r
+\r
+ /** \brief Typedef for the parse functions. \r
+ \r
+ The parse function do the actual work. The parser exchanges\r
+ the function pointer to the parser function depending on \r
+ which state it is in. (i.e. bytecode parser vs. string parser)\r
+ */\r
+ typedef value_type (ParserBase::*ParseFunction)() const; \r
+\r
+ /** \brief Type used for storing an array of values. */\r
+ typedef std::vector<value_type> valbuf_type;\r
+\r
+ /** \brief Type for a vector of strings. */\r
+ typedef std::vector<string_type> stringbuf_type;\r
+\r
+ /** \brief Typedef for the token reader. */\r
+ typedef ParserTokenReader token_reader_type;\r
+ \r
+ /** \brief Type used for parser tokens. */\r
+ typedef ParserToken<value_type, string_type> token_type;\r
+\r
+ /** \brief Maximum number of threads spawned by OpenMP when using the bulk mode. */\r
+ static const int s_MaxNumOpenMPThreads = 4;\r
+\r
+ public:\r
+\r
+ /** \brief Type of the error class. \r
+ \r
+ Included for backwards compatibility.\r
+ */\r
+ typedef ParserError exception_type;\r
+\r
+ static void EnableDebugDump(bool bDumpCmd, bool bDumpStack);\r
+\r
+ ParserBase(); \r
+ ParserBase(const ParserBase &a_Parser);\r
+ ParserBase& operator=(const ParserBase &a_Parser);\r
+\r
+ virtual ~ParserBase();\r
+ \r
+ value_type Eval() const;\r
+ value_type* Eval(int &nStackSize) const;\r
+ void Eval(value_type *results, int nBulkSize);\r
+\r
+ int GetNumResults() const;\r
+\r
+ void SetExpr(const string_type &a_sExpr);\r
+ void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL);\r
+\r
+ void SetDecSep(char_type cDecSep);\r
+ void SetThousandsSep(char_type cThousandsSep = 0);\r
+ void ResetLocale();\r
+\r
+ void EnableOptimizer(bool a_bIsOn=true);\r
+ void EnableBuiltInOprt(bool a_bIsOn=true);\r
+\r
+ bool HasBuiltInOprt() const;\r
+ void AddValIdent(identfun_type a_pCallback);\r
+\r
+ /** \fn void mu::ParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true) \r
+ \brief Define a parser function without arguments.\r
+ \param a_strName Name of the function\r
+ \param a_pFun Pointer to the callback function\r
+ \param a_bAllowOpt A flag indicating this function may be optimized\r
+ */\r
+ template<typename T>\r
+ void DefineFun(const string_type &a_strName, T a_pFun, bool a_bAllowOpt = true)\r
+ {\r
+ AddCallback( a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars() );\r
+ }\r
+\r
+ void DefineOprt(const string_type &a_strName, \r
+ fun_type2 a_pFun, \r
+ unsigned a_iPri=0, \r
+ EOprtAssociativity a_eAssociativity = oaLEFT,\r
+ bool a_bAllowOpt = false);\r
+ void DefineConst(const string_type &a_sName, value_type a_fVal);\r
+ void DefineStrConst(const string_type &a_sName, const string_type &a_strVal);\r
+ void DefineVar(const string_type &a_sName, value_type *a_fVar);\r
+ void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true);\r
+ void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true);\r
+\r
+ // Clear user defined variables, constants or functions\r
+ void ClearVar();\r
+ void ClearFun();\r
+ void ClearConst();\r
+ void ClearInfixOprt();\r
+ void ClearPostfixOprt();\r
+ void ClearOprt();\r
+ \r
+ void RemoveVar(const string_type &a_strVarName);\r
+ const varmap_type& GetUsedVar() const;\r
+ const varmap_type& GetVar() const;\r
+ const valmap_type& GetConst() const;\r
+ const string_type& GetExpr() const;\r
+ const funmap_type& GetFunDef() const;\r
+ string_type GetVersion(EParserVersionInfo eInfo = pviFULL) const;\r
+\r
+ const char_type ** GetOprtDef() const;\r
+ void DefineNameChars(const char_type *a_szCharset);\r
+ void DefineOprtChars(const char_type *a_szCharset);\r
+ void DefineInfixOprtChars(const char_type *a_szCharset);\r
+\r
+ const char_type* ValidNameChars() const;\r
+ const char_type* ValidOprtChars() const;\r
+ const char_type* ValidInfixOprtChars() const;\r
+\r
+ void SetArgSep(char_type cArgSep);\r
+ char_type GetArgSep() const;\r
+ \r
+ void Error(EErrorCodes a_iErrc, \r
+ int a_iPos = (int)mu::string_type::npos, \r
+ const string_type &a_strTok = string_type() ) const;\r
+\r
+ protected:\r
+ \r
+ void Init();\r
+\r
+ virtual void InitCharSets() = 0;\r
+ virtual void InitFun() = 0;\r
+ virtual void InitConst() = 0;\r
+ virtual void InitOprt() = 0; \r
+\r
+ virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd);\r
+\r
+ static const char_type *c_DefaultOprt[]; \r
+ static std::locale s_locale; ///< The locale used by the parser\r
+ static bool g_DbgDumpCmdCode;\r
+ static bool g_DbgDumpStack;\r
+\r
+ /** \brief A facet class used to change decimal and thousands separator. */\r
+ template<class TChar>\r
+ class change_dec_sep : public std::numpunct<TChar>\r
+ {\r
+ public:\r
+ \r
+ explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3)\r
+ :std::numpunct<TChar>()\r
+ ,m_nGroup(nGroup)\r
+ ,m_cDecPoint(cDecSep)\r
+ ,m_cThousandsSep(cThousandsSep)\r
+ {}\r
+ \r
+ protected:\r
+ \r
+ virtual char_type do_decimal_point() const\r
+ {\r
+ return m_cDecPoint;\r
+ }\r
+\r
+ virtual char_type do_thousands_sep() const\r
+ {\r
+ return m_cThousandsSep;\r
+ }\r
+\r
+ virtual std::string do_grouping() const \r
+ { \r
+ return std::string(1, m_nGroup); \r
+ }\r
+\r
+ private:\r
+\r
+ int m_nGroup;\r
+ char_type m_cDecPoint; \r
+ char_type m_cThousandsSep;\r
+ };\r
+\r
+ private:\r
+\r
+ void Assign(const ParserBase &a_Parser);\r
+ void InitTokenReader();\r
+ void ReInit() const;\r
+\r
+ void AddCallback( const string_type &a_strName, \r
+ const ParserCallback &a_Callback, \r
+ funmap_type &a_Storage,\r
+ const char_type *a_szCharSet );\r
+\r
+ void ApplyRemainingOprt(ParserStack<token_type> &a_stOpt,\r
+ ParserStack<token_type> &a_stVal) const;\r
+ void ApplyBinOprt(ParserStack<token_type> &a_stOpt,\r
+ ParserStack<token_type> &a_stVal) const;\r
+\r
+ void ApplyIfElse(ParserStack<token_type> &a_stOpt,\r
+ ParserStack<token_type> &a_stVal) const;\r
+\r
+ void ApplyFunc(ParserStack<token_type> &a_stOpt,\r
+ ParserStack<token_type> &a_stVal, \r
+ int iArgCount) const; \r
+\r
+ token_type ApplyStrFunc(const token_type &a_FunTok,\r
+ const std::vector<token_type> &a_vArg) const;\r
+\r
+ int GetOprtPrecedence(const token_type &a_Tok) const;\r
+ EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const;\r
+\r
+ void CreateRPN() const;\r
+\r
+ value_type ParseString() const; \r
+ value_type ParseCmdCode() const;\r
+ value_type ParseCmdCodeBulk(int nOffset, int nThreadID) const;\r
+\r
+ void CheckName(const string_type &a_strName, const string_type &a_CharSet) const;\r
+ void CheckOprt(const string_type &a_sName,\r
+ const ParserCallback &a_Callback,\r
+ const string_type &a_szCharSet) const;\r
+\r
+ void StackDump(const ParserStack<token_type > &a_stVal, \r
+ const ParserStack<token_type > &a_stOprt) const;\r
+\r
+ /** \brief Pointer to the parser function. \r
+ \r
+ Eval() calls the function whose address is stored there.\r
+ */\r
+ mutable ParseFunction m_pParseFormula;\r
+ mutable ParserByteCode m_vRPN; ///< The Bytecode class.\r
+ mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments\r
+ stringbuf_type m_vStringVarBuf;\r
+\r
+ std::auto_ptr<token_reader_type> m_pTokenReader; ///< Managed pointer to the token reader object.\r
+\r
+ funmap_type m_FunDef; ///< Map of function names and pointers.\r
+ funmap_type m_PostOprtDef; ///< Postfix operator callbacks\r
+ funmap_type m_InfixOprtDef; ///< unary infix operator.\r
+ funmap_type m_OprtDef; ///< Binary operator callbacks\r
+ valmap_type m_ConstDef; ///< user constants.\r
+ strmap_type m_StrVarDef; ///< user defined string constants\r
+ varmap_type m_VarDef; ///< user defind variables.\r
+\r
+ bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off\r
+\r
+ string_type m_sNameChars; ///< Charset for names\r
+ string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens\r
+ string_type m_sInfixOprtChars; ///< Charset for infix operator tokens\r
+ \r
+ mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses\r
+\r
+ // items merely used for caching state information\r
+ mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine\r
+ mutable int m_nFinalResultIdx;\r
+};\r
+\r
+} // namespace mu\r
+\r
+#endif\r
+\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2004-2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+#ifndef MU_PARSER_BYTECODE_H\r
+#define MU_PARSER_BYTECODE_H\r
+\r
+#include <cassert>\r
+#include <string>\r
+#include <stack>\r
+#include <vector>\r
+\r
+#include "muParserDef.h"\r
+#include "muParserError.h"\r
+#include "muParserToken.h"\r
+\r
+/** \file\r
+ \brief Definition of the parser bytecode class.\r
+*/\r
+\r
+\r
+namespace mu\r
+{\r
+ struct SToken\r
+ {\r
+ ECmdCode Cmd;\r
+ int StackPos;\r
+\r
+ union\r
+ {\r
+ struct //SValData\r
+ {\r
+ value_type *ptr;\r
+ value_type data;\r
+ value_type data2;\r
+ } Val;\r
+\r
+ struct //SFunData\r
+ {\r
+ // Note: generic_fun_type is merely a placeholder. The real type could be \r
+ // anything between gun_type1 and fun_type9. I can't use a void\r
+ // pointer due to constraints in the ANSI standard which allows\r
+ // data pointers and function pointers to differ in size.\r
+ generic_fun_type ptr;\r
+ int argc;\r
+ int idx;\r
+ } Fun;\r
+\r
+ struct //SOprtData\r
+ {\r
+ value_type *ptr;\r
+ int offset;\r
+ } Oprt;\r
+ };\r
+ };\r
+ \r
+ \r
+ /** \brief Bytecode implementation of the Math Parser.\r
+\r
+ The bytecode contains the formula converted to revers polish notation stored in a continious\r
+ memory area. Associated with this data are operator codes, variable pointers, constant \r
+ values and function pointers. Those are necessary in order to calculate the result.\r
+ All those data items will be casted to the underlying datatype of the bytecode.\r
+\r
+ \author (C) 2004-2013 Ingo Berg \r
+*/\r
+class ParserByteCode\r
+{\r
+private:\r
+\r
+ /** \brief Token type for internal use only. */\r
+ typedef ParserToken<value_type, string_type> token_type;\r
+\r
+ /** \brief Token vector for storing the RPN. */\r
+ typedef std::vector<SToken> rpn_type;\r
+\r
+ /** \brief Position in the Calculation array. */\r
+ unsigned m_iStackPos;\r
+\r
+ /** \brief Maximum size needed for the stack. */\r
+ std::size_t m_iMaxStackSize;\r
+ \r
+ /** \brief The actual rpn storage. */\r
+ rpn_type m_vRPN;\r
+\r
+ bool m_bEnableOptimizer;\r
+\r
+ void ConstantFolding(ECmdCode a_Oprt);\r
+\r
+public:\r
+\r
+ ParserByteCode();\r
+ ParserByteCode(const ParserByteCode &a_ByteCode);\r
+ ParserByteCode& operator=(const ParserByteCode &a_ByteCode);\r
+ void Assign(const ParserByteCode &a_ByteCode);\r
+\r
+ void AddVar(value_type *a_pVar);\r
+ void AddVal(value_type a_fVal);\r
+ void AddOp(ECmdCode a_Oprt);\r
+ void AddIfElse(ECmdCode a_Oprt);\r
+ void AddAssignOp(value_type *a_pVar);\r
+ void AddFun(generic_fun_type a_pFun, int a_iArgc);\r
+ void AddBulkFun(generic_fun_type a_pFun, int a_iArgc);\r
+ void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx);\r
+\r
+ void EnableOptimizer(bool bStat);\r
+\r
+ void Finalize();\r
+ void clear();\r
+ std::size_t GetMaxStackSize() const;\r
+ std::size_t GetSize() const;\r
+\r
+ const SToken* GetBase() const;\r
+ void AsciiDump();\r
+};\r
+\r
+} // namespace mu\r
+\r
+#endif\r
+\r
+\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2004-2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#ifndef MU_PARSER_CALLBACK_H\r
+#define MU_PARSER_CALLBACK_H\r
+\r
+#include "muParserDef.h"\r
+\r
+/** \file\r
+ \brief Definition of the parser callback class.\r
+*/\r
+\r
+namespace mu\r
+{\r
+\r
+/** \brief Encapsulation of prototypes for a numerical parser function.\r
+\r
+ Encapsulates the prototyp for numerical parser functions. The class\r
+ stores the number of arguments for parser functions as well\r
+ as additional flags indication the function is non optimizeable.\r
+ The pointer to the callback function pointer is stored as void* \r
+ and needs to be casted according to the argument count.\r
+ Negative argument counts indicate a parser function with a variable number\r
+ of arguments. \r
+\r
+ \author (C) 2004-2011 Ingo Berg\r
+*/\r
+class ParserCallback\r
+{\r
+public:\r
+ ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC);\r
+ ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity);\r
+ ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti);\r
+\r
+ ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti);\r
+\r
+ ParserCallback(multfun_type a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti);\r
+ ParserCallback();\r
+ ParserCallback(const ParserCallback &a_Fun);\r
+ \r
+ ParserCallback* Clone() const;\r
+\r
+ bool IsOptimizable() const;\r
+ void* GetAddr() const;\r
+ ECmdCode GetCode() const;\r
+ ETypeCode GetType() const;\r
+ int GetPri() const;\r
+ EOprtAssociativity GetAssociativity() const;\r
+ int GetArgc() const;\r
+\r
+private:\r
+ void *m_pFun; ///< Pointer to the callback function, casted to void\r
+ \r
+ /** \brief Number of numeric function arguments\r
+ \r
+ This number is negative for functions with variable number of arguments. in this cases\r
+ they represent the actual number of arguments found.\r
+ */\r
+ int m_iArgc; \r
+ int m_iPri; ///< Valid only for binary and infix operators; Operator precedence.\r
+ EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators \r
+ ECmdCode m_iCode;\r
+ ETypeCode m_iType;\r
+ bool m_bAllowOpti; ///< Flag indication optimizeability \r
+};\r
+\r
+//------------------------------------------------------------------------------\r
+/** \brief Container for Callback objects. */\r
+typedef std::map<string_type, ParserCallback> funmap_type; \r
+\r
+} // namespace mu\r
+\r
+#endif\r
+\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+#ifndef MU_PARSER_DLL_H\r
+#define MU_PARSER_DLL_H\r
+\r
+#if defined(WIN32) || defined(_WIN32)\r
+ #ifdef MUPARSERLIB_EXPORTS\r
+ #define API_EXPORT(TYPE) __declspec(dllexport) TYPE __cdecl\r
+ #else\r
+ #define API_EXPORT(TYPE) __declspec(dllimport) TYPE __cdecl\r
+ #endif\r
+#else\r
+ #define API_EXPORT(TYPE) TYPE\r
+#endif\r
+\r
+\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif\r
+\r
+/** \file \r
+ \brief This file contains the DLL interface of muparser.\r
+*/\r
+\r
+// Basic types\r
+typedef void* muParserHandle_t; // parser handle\r
+typedef char muChar_t; // character type\r
+typedef int muBool_t; // boolean type\r
+typedef int muInt_t; // integer type \r
+typedef double muFloat_t; // floating point type\r
+\r
+// function types for calculation\r
+typedef muFloat_t (*muFun0_t )(); \r
+typedef muFloat_t (*muFun1_t )(muFloat_t); \r
+typedef muFloat_t (*muFun2_t )(muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muFun3_t )(muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muFun4_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muFun5_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muFun6_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muFun7_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muFun8_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muFun9_t )(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+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); \r
+\r
+// Function prototypes for bulkmode functions\r
+typedef muFloat_t (*muBulkFun0_t )(int, int); \r
+typedef muFloat_t (*muBulkFun1_t )(int, int, muFloat_t); \r
+typedef muFloat_t (*muBulkFun2_t )(int, int, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muBulkFun3_t )(int, int, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muBulkFun4_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muBulkFun5_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muBulkFun6_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muBulkFun7_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+typedef muFloat_t (*muBulkFun8_t )(int, int, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t); \r
+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); \r
+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); \r
+\r
+typedef muFloat_t (*muMultFun_t)(const muFloat_t*, muInt_t);\r
+typedef muFloat_t (*muStrFun1_t)(const muChar_t*);\r
+typedef muFloat_t (*muStrFun2_t)(const muChar_t*, muFloat_t);\r
+typedef muFloat_t (*muStrFun3_t)(const muChar_t*, muFloat_t, muFloat_t);\r
+\r
+// Functions for parser management\r
+typedef void (*muErrorHandler_t)(muParserHandle_t a_hParser); // [optional] callback to an error handler\r
+typedef muFloat_t* (*muFacFun_t)(const muChar_t*, void*); // [optional] callback for creating new variables\r
+typedef muInt_t (*muIdentFun_t)(const muChar_t*, muInt_t*, muFloat_t*); // [optional] value identification callbacks\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+// Constants\r
+static const int muOPRT_ASCT_LEFT = 0;\r
+static const int muOPRT_ASCT_RIGHT = 1;\r
+\r
+static const int muBASETYPE_FLOAT = 0;\r
+static const int muBASETYPE_INT = 1;\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+//\r
+//\r
+// muParser C compatible bindings\r
+//\r
+//\r
+//-----------------------------------------------------------------------------------------------------\r
+\r
+\r
+// Basic operations / initialization \r
+API_EXPORT(muParserHandle_t) mupCreate(int nBaseType);\r
+API_EXPORT(void) mupRelease(muParserHandle_t a_hParser);\r
+API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser);\r
+API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t *a_szExpr);\r
+API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void* pUserData);\r
+API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser);\r
+API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser);\r
+API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int *nNum);\r
+API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t *a_fResult, int nSize);\r
+\r
+// Defining callbacks / variables / constants\r
+API_EXPORT(void) mupDefineFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun0_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun1_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun2_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun3_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun4_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun5_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun6_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun7_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun8_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun9_t a_pFun, muBool_t a_bOptimize);\r
+API_EXPORT(void) mupDefineFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muFun10_t a_pFun, muBool_t a_bOptimize);\r
+\r
+// Defining bulkmode functions\r
+API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun0_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun1_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun2_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun3_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun4_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun5_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun6_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun7_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun8_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun9_t a_pFun);\r
+API_EXPORT(void) mupDefineBulkFun10(muParserHandle_t a_hParser, const muChar_t *a_szName, muBulkFun10_t a_pFun);\r
+\r
+// string functions\r
+API_EXPORT(void) mupDefineStrFun1(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun1_t a_pFun);\r
+API_EXPORT(void) mupDefineStrFun2(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun2_t a_pFun);\r
+API_EXPORT(void) mupDefineStrFun3(muParserHandle_t a_hParser, const muChar_t *a_szName, muStrFun3_t a_pFun);\r
+\r
+API_EXPORT(void) mupDefineMultFun( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muMultFun_t a_pFun, \r
+ muBool_t a_bOptimize);\r
+\r
+API_EXPORT(void) mupDefineOprt( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFun2_t a_pFun, \r
+ muInt_t a_nPrec, \r
+ muInt_t a_nOprtAsct,\r
+ muBool_t a_bOptimize);\r
+\r
+API_EXPORT(void) mupDefineConst( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFloat_t a_fVal );\r
+\r
+API_EXPORT(void) mupDefineStrConst( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ const muChar_t *a_sVal );\r
+\r
+API_EXPORT(void) mupDefineVar( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFloat_t *a_fVar);\r
+\r
+API_EXPORT(void) mupDefineBulkVar( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFloat_t *a_fVar);\r
+\r
+API_EXPORT(void) mupDefinePostfixOprt( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFun1_t a_pOprt, \r
+ muBool_t a_bOptimize);\r
+\r
+\r
+API_EXPORT(void) mupDefineInfixOprt( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFun1_t a_pOprt, \r
+ muBool_t a_bOptimize);\r
+\r
+// Define character sets for identifiers\r
+API_EXPORT(void) mupDefineNameChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset);\r
+API_EXPORT(void) mupDefineOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset);\r
+API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, const muChar_t* a_szCharset);\r
+\r
+// Remove all / single variables\r
+API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName);\r
+API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser);\r
+API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser);\r
+API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser);\r
+API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser);\r
+\r
+// Querying variables / expression variables / constants\r
+API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser);\r
+API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser);\r
+API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser);\r
+API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar);\r
+API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t** a_pVar);\r
+API_EXPORT(void) mupGetConst(muParserHandle_t a_hParser, unsigned a_iVar, const muChar_t** a_pszName, muFloat_t* a_pVar);\r
+API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep);\r
+API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cArgSep);\r
+API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cArgSep);\r
+API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser);\r
+\r
+// Add value recognition callbacks\r
+API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, muIdentFun_t);\r
+\r
+// Error handling\r
+API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser);\r
+API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser);\r
+API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t a_pErrHandler);\r
+API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser);\r
+API_EXPORT(muInt_t) mupGetErrorCode(muParserHandle_t a_hParser);\r
+API_EXPORT(muInt_t) mupGetErrorPos(muParserHandle_t a_hParser);\r
+API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser);\r
+//API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser);\r
+\r
+// This is used for .NET only. It creates a new variable allowing the dll to\r
+// manage the variable rather than the .NET garbage collector.\r
+API_EXPORT(muFloat_t*) mupCreateVar();\r
+API_EXPORT(void) mupReleaseVar(muFloat_t*);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif // include guard\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+#ifndef MUP_DEF_H\r
+#define MUP_DEF_H\r
+\r
+#include <iostream>\r
+#include <string>\r
+#include <sstream>\r
+#include <map>\r
+\r
+#include "muParserFixes.h"\r
+\r
+/** \file\r
+ \brief This file contains standard definitions used by the parser.\r
+*/\r
+\r
+#define MUP_VERSION _T("2.2.3")\r
+#define MUP_VERSION_DATE _T("20121222; SF")\r
+\r
+#define MUP_CHARS _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")\r
+\r
+/** \brief If this macro is defined mathematical exceptions (div by zero) will be thrown as exceptions. */\r
+//#define MUP_MATH_EXCEPTIONS\r
+\r
+/** \brief Define the base datatype for values.\r
+\r
+ This datatype must be a built in value type. You can not use custom classes.\r
+ It should be working with all types except "int"!\r
+*/\r
+#define MUP_BASETYPE double\r
+\r
+/** \brief Activate this option in order to compile with OpenMP support. \r
+\r
+ OpenMP is used only in the bulk mode it may increase the performance a bit. \r
+*/\r
+//#define MUP_USE_OPENMP\r
+\r
+#if defined(_UNICODE)\r
+ /** \brief Definition of the basic parser string type. */\r
+ #define MUP_STRING_TYPE std::wstring\r
+\r
+ #if !defined(_T)\r
+ #define _T(x) L##x\r
+ #endif // not defined _T\r
+#else\r
+ #ifndef _T\r
+ #define _T(x) x\r
+ #endif\r
+ \r
+ /** \brief Definition of the basic parser string type. */\r
+ #define MUP_STRING_TYPE std::string\r
+#endif\r
+\r
+#if defined(_DEBUG)\r
+ /** \brief Debug macro to force an abortion of the programm with a certain message.\r
+ */\r
+ #define MUP_FAIL(MSG) \\r
+ { \\r
+ bool MSG=false; \\r
+ assert(MSG); \\r
+ }\r
+\r
+ /** \brief An assertion that does not kill the program.\r
+\r
+ This macro is neutralised in UNICODE builds. It's\r
+ too difficult to translate.\r
+ */\r
+ #define MUP_ASSERT(COND) \\r
+ if (!(COND)) \\r
+ { \\r
+ stringstream_type ss; \\r
+ ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") \\r
+ << __FILE__ << _T(" line ") \\r
+ << __LINE__ << _T("."); \\r
+ throw ParserError( ss.str() ); \\r
+ }\r
+#else\r
+ #define MUP_FAIL(MSG)\r
+ #define MUP_ASSERT(COND)\r
+#endif\r
+\r
+\r
+namespace mu\r
+{\r
+#if defined(_UNICODE)\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Encapsulate wcout. */\r
+ inline std::wostream& console()\r
+ {\r
+ return std::wcout;\r
+ }\r
+\r
+ /** \brief Encapsulate cin. */\r
+ inline std::wistream& console_in()\r
+ {\r
+ return std::wcin;\r
+ }\r
+\r
+#else\r
+\r
+ /** \brief Encapsulate cout. \r
+ \r
+ Used for supporting UNICODE more easily.\r
+ */\r
+ inline std::ostream& console()\r
+ {\r
+ return std::cout;\r
+ }\r
+\r
+ /** \brief Encapsulate cin. \r
+\r
+ Used for supporting UNICODE more easily.\r
+ */\r
+ inline std::istream& console_in()\r
+ {\r
+ return std::cin;\r
+ }\r
+\r
+#endif\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Bytecode values.\r
+\r
+ \attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt!\r
+ */\r
+ enum ECmdCode\r
+ {\r
+ // The following are codes for built in binary operators\r
+ // apart from built in operators the user has the opportunity to\r
+ // add user defined operators.\r
+ cmLE = 0, ///< Operator item: less or equal\r
+ cmGE = 1, ///< Operator item: greater or equal\r
+ cmNEQ = 2, ///< Operator item: not equal\r
+ cmEQ = 3, ///< Operator item: equals\r
+ cmLT = 4, ///< Operator item: less than\r
+ cmGT = 5, ///< Operator item: greater than\r
+ cmADD = 6, ///< Operator item: add\r
+ cmSUB = 7, ///< Operator item: subtract\r
+ cmMUL = 8, ///< Operator item: multiply\r
+ cmDIV = 9, ///< Operator item: division\r
+ cmPOW = 10, ///< Operator item: y to the power of ...\r
+ cmLAND = 11,\r
+ cmLOR = 12,\r
+ cmASSIGN = 13, ///< Operator item: Assignment operator\r
+ cmBO = 14, ///< Operator item: opening bracket\r
+ cmBC = 15, ///< Operator item: closing bracket\r
+ cmIF = 16, ///< For use in the ternary if-then-else operator\r
+ cmELSE = 17, ///< For use in the ternary if-then-else operator\r
+ cmENDIF = 18, ///< For use in the ternary if-then-else operator\r
+ cmARG_SEP = 19, ///< function argument separator\r
+ cmVAR = 20, ///< variable item\r
+ cmVAL = 21, ///< value item\r
+\r
+ // For optimization purposes\r
+ cmVARPOW2,\r
+ cmVARPOW3,\r
+ cmVARPOW4,\r
+ cmVARMUL,\r
+ cmPOW2,\r
+\r
+ // operators and functions\r
+ cmFUNC, ///< Code for a generic function item\r
+ cmFUNC_STR, ///< Code for a function with a string parameter\r
+ cmFUNC_BULK, ///< Special callbacks for Bulk mode with an additional parameter for the bulk index \r
+ cmSTRING, ///< Code for a string token\r
+ cmOPRT_BIN, ///< user defined binary operator\r
+ cmOPRT_POSTFIX, ///< code for postfix operators\r
+ cmOPRT_INFIX, ///< code for infix operators\r
+ cmEND, ///< end of formula\r
+ cmUNKNOWN ///< uninitialized item\r
+ };\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Types internally used by the parser.\r
+ */\r
+ enum ETypeCode\r
+ {\r
+ tpSTR = 0, ///< String type (Function arguments and constants only, no string variables)\r
+ tpDBL = 1, ///< Floating point variables\r
+ tpVOID = 2 ///< Undefined type.\r
+ };\r
+\r
+ //------------------------------------------------------------------------------\r
+ enum EParserVersionInfo\r
+ {\r
+ pviBRIEF,\r
+ pviFULL\r
+ };\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Parser operator precedence values. */\r
+ enum EOprtAssociativity\r
+ {\r
+ oaLEFT = 0,\r
+ oaRIGHT = 1,\r
+ oaNONE = 2\r
+ };\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Parser operator precedence values. */\r
+ enum EOprtPrecedence\r
+ {\r
+ // binary operators\r
+ prLOR = 1,\r
+ prLAND = 2,\r
+ prLOGIC = 3, ///< logic operators\r
+ prCMP = 4, ///< comparsion operators\r
+ prADD_SUB = 5, ///< addition\r
+ prMUL_DIV = 6, ///< multiplication/division\r
+ prPOW = 7, ///< power operator priority (highest)\r
+\r
+ // infix operators\r
+ prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator\r
+ prPOSTFIX = 6 ///< Postfix operator priority (currently unused)\r
+ };\r
+\r
+ //------------------------------------------------------------------------------\r
+ // basic types\r
+\r
+ /** \brief The numeric datatype used by the parser. \r
+ \r
+ Normally this is a floating point type either single or double precision.\r
+ */\r
+ typedef MUP_BASETYPE value_type;\r
+\r
+ /** \brief The stringtype used by the parser. \r
+\r
+ Depends on wether UNICODE is used or not.\r
+ */\r
+ typedef MUP_STRING_TYPE string_type;\r
+\r
+ /** \brief The character type used by the parser. \r
+ \r
+ Depends on wether UNICODE is used or not.\r
+ */\r
+ typedef string_type::value_type char_type;\r
+\r
+ /** \brief Typedef for easily using stringstream that respect the parser stringtype. */\r
+ typedef std::basic_stringstream<char_type,\r
+ std::char_traits<char_type>,\r
+ std::allocator<char_type> > stringstream_type;\r
+\r
+ // Data container types\r
+\r
+ /** \brief Type used for storing variables. */\r
+ typedef std::map<string_type, value_type*> varmap_type;\r
+ \r
+ /** \brief Type used for storing constants. */\r
+ typedef std::map<string_type, value_type> valmap_type;\r
+ \r
+ /** \brief Type for assigning a string name to an index in the internal string table. */\r
+ typedef std::map<string_type, std::size_t> strmap_type;\r
+\r
+ // Parser callbacks\r
+ \r
+ /** \brief Callback type used for functions without arguments. */\r
+ typedef value_type (*generic_fun_type)();\r
+\r
+ /** \brief Callback type used for functions without arguments. */\r
+ typedef value_type (*fun_type0)();\r
+\r
+ /** \brief Callback type used for functions with a single arguments. */\r
+ typedef value_type (*fun_type1)(value_type);\r
+\r
+ /** \brief Callback type used for functions with two arguments. */\r
+ typedef value_type (*fun_type2)(value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with three arguments. */\r
+ typedef value_type (*fun_type3)(value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with four arguments. */\r
+ typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ typedef value_type (*fun_type6)(value_type, value_type, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ typedef value_type (*fun_type7)(value_type, value_type, value_type, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ typedef value_type (*fun_type8)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ typedef value_type (*fun_type9)(value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ 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);\r
+\r
+ /** \brief Callback type used for functions without arguments. */\r
+ typedef value_type (*bulkfun_type0)(int, int);\r
+\r
+ /** \brief Callback type used for functions with a single arguments. */\r
+ typedef value_type (*bulkfun_type1)(int, int, value_type);\r
+\r
+ /** \brief Callback type used for functions with two arguments. */\r
+ typedef value_type (*bulkfun_type2)(int, int, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with three arguments. */\r
+ typedef value_type (*bulkfun_type3)(int, int, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with four arguments. */\r
+ typedef value_type (*bulkfun_type4)(int, int, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ typedef value_type (*bulkfun_type5)(int, int, value_type, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ typedef value_type (*bulkfun_type6)(int, int, value_type, value_type, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ typedef value_type (*bulkfun_type7)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ typedef value_type (*bulkfun_type8)(int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ 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);\r
+\r
+ /** \brief Callback type used for functions with five arguments. */\r
+ 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);\r
+\r
+ /** \brief Callback type used for functions with a variable argument list. */\r
+ typedef value_type (*multfun_type)(const value_type*, int);\r
+\r
+ /** \brief Callback type used for functions taking a string as an argument. */\r
+ typedef value_type (*strfun_type1)(const char_type*);\r
+\r
+ /** \brief Callback type used for functions taking a string and a value as arguments. */\r
+ typedef value_type (*strfun_type2)(const char_type*, value_type);\r
+\r
+ /** \brief Callback type used for functions taking a string and two values as arguments. */\r
+ typedef value_type (*strfun_type3)(const char_type*, value_type, value_type);\r
+\r
+ /** \brief Callback used for functions that identify values in a string. */\r
+ typedef int (*identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal);\r
+\r
+ /** \brief Callback used for variable creation factory functions. */\r
+ typedef value_type* (*facfun_type)(const char_type*, void*);\r
+} // end of namespace\r
+\r
+#endif\r
+\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2004-2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#ifndef MU_PARSER_ERROR_H\r
+#define MU_PARSER_ERROR_H\r
+\r
+#include <cassert>\r
+#include <stdexcept>\r
+#include <string>\r
+#include <sstream>\r
+#include <vector>\r
+#include <memory>\r
+\r
+#include "muParserDef.h"\r
+\r
+/** \file \r
+ \brief This file defines the error class used by the parser.\r
+*/\r
+\r
+namespace mu\r
+{\r
+\r
+/** \brief Error codes. */\r
+enum EErrorCodes\r
+{\r
+ // Formula syntax errors\r
+ ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found\r
+ ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified.\r
+ ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(")\r
+ ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23")\r
+ ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found\r
+ ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found\r
+ ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found\r
+ ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing\r
+ ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position\r
+ ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument\r
+ ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument\r
+ ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3")\r
+ ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)")\r
+ ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)")\r
+ ecTOO_MANY_PARAMS = 14, ///< Too many function parameters\r
+ ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)")\r
+ ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type\r
+ ecSTR_RESULT = 17, ///< result is a string\r
+\r
+ // Invalid Parser input Parameters\r
+ ecINVALID_NAME = 18, ///< Invalid function, variable or constant name.\r
+ ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier\r
+ ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name.\r
+ ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name.\r
+\r
+ ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator\r
+ ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer \r
+ ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer \r
+ ecEMPTY_EXPRESSION = 25, ///< The Expression is empty\r
+ ecNAME_CONFLICT = 26, ///< Name conflict\r
+ ecOPT_PRI = 27, ///< Invalid operator priority\r
+ // \r
+ ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused)\r
+ ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused)\r
+ ecGENERIC = 30, ///< Generic error\r
+ ecLOCALE = 31, ///< Conflict with current locale\r
+\r
+ ecUNEXPECTED_CONDITIONAL = 32,\r
+ ecMISSING_ELSE_CLAUSE = 33, \r
+ ecMISPLACED_COLON = 34,\r
+\r
+ // internal errors\r
+ ecINTERNAL_ERROR = 35, ///< Internal error of any kind.\r
+ \r
+ // The last two are special entries \r
+ ecCOUNT, ///< This is no error code, It just stores just the total number of error codes\r
+ ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages\r
+};\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief A class that handles the error messages.\r
+*/\r
+class ParserErrorMsg\r
+{\r
+public:\r
+ typedef ParserErrorMsg self_type;\r
+\r
+ ParserErrorMsg& operator=(const ParserErrorMsg &);\r
+ ParserErrorMsg(const ParserErrorMsg&);\r
+ ParserErrorMsg();\r
+\r
+ ~ParserErrorMsg();\r
+\r
+ static const ParserErrorMsg& Instance();\r
+ string_type operator[](unsigned a_iIdx) const;\r
+\r
+private:\r
+ std::vector<string_type> m_vErrMsg; ///< A vector with the predefined error messages\r
+ static const self_type m_Instance; ///< The instance pointer\r
+};\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Error class of the parser. \r
+ \author Ingo Berg\r
+\r
+ Part of the math parser package.\r
+*/\r
+class ParserError\r
+{\r
+private:\r
+\r
+ /** \brief Replace all ocuurences of a substring with another string. */\r
+ void ReplaceSubString( string_type &strSource, \r
+ const string_type &strFind,\r
+ const string_type &strReplaceWith);\r
+ void Reset();\r
+\r
+public:\r
+\r
+ ParserError();\r
+ explicit ParserError(EErrorCodes a_iErrc);\r
+ explicit ParserError(const string_type &sMsg);\r
+ ParserError( EErrorCodes a_iErrc,\r
+ const string_type &sTok,\r
+ const string_type &sFormula = string_type(),\r
+ int a_iPos = -1);\r
+ ParserError( EErrorCodes a_iErrc, \r
+ int a_iPos, \r
+ const string_type &sTok);\r
+ ParserError( const char_type *a_szMsg, \r
+ int a_iPos = -1, \r
+ const string_type &sTok = string_type());\r
+ ParserError(const ParserError &a_Obj);\r
+ ParserError& operator=(const ParserError &a_Obj);\r
+ ~ParserError();\r
+\r
+ void SetFormula(const string_type &a_strFormula);\r
+ const string_type& GetExpr() const;\r
+ const string_type& GetMsg() const;\r
+ std::size_t GetPos() const;\r
+ const string_type& GetToken() const;\r
+ EErrorCodes GetCode() const;\r
+\r
+private:\r
+ string_type m_strMsg; ///< The message string\r
+ string_type m_strFormula; ///< Formula string\r
+ string_type m_strTok; ///< Token related with the error\r
+ int m_iPos; ///< Formula position related to the error \r
+ EErrorCodes m_iErrc; ///< Error code\r
+ const ParserErrorMsg &m_ErrMsg;\r
+}; \r
+\r
+} // namespace mu\r
+\r
+#endif\r
+\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#ifndef MU_PARSER_FIXES_H\r
+#define MU_PARSER_FIXES_H\r
+\r
+/** \file\r
+ \brief This file contains compatibility fixes for some platforms.\r
+*/\r
+\r
+//\r
+// Compatibility fixes\r
+//\r
+\r
+//---------------------------------------------------------------------------\r
+//\r
+// Intel Compiler\r
+//\r
+//---------------------------------------------------------------------------\r
+\r
+#ifdef __INTEL_COMPILER\r
+\r
+// remark #981: operands are evaluated in unspecified order\r
+// disabled -> completely pointless if the functions do not have side effects\r
+//\r
+#pragma warning(disable:981)\r
+\r
+// remark #383: value copied to temporary, reference to temporary used\r
+#pragma warning(disable:383)\r
+\r
+// remark #1572: floating-point equality and inequality comparisons are unreliable\r
+// disabled -> everyone knows it, the parser passes this problem\r
+// deliberately to the user\r
+#pragma warning(disable:1572)\r
+\r
+#endif\r
+\r
+#endif // include guard\r
+\r
+\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2004-2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#ifndef MU_PARSER_INT_H\r
+#define MU_PARSER_INT_H\r
+\r
+#include "muParserBase.h"\r
+#include <vector>\r
+\r
+\r
+/** \file\r
+ \brief Definition of a parser using integer value.\r
+*/\r
+\r
+\r
+namespace mu\r
+{\r
+\r
+/** \brief Mathematical expressions parser.\r
+ \r
+ This version of the parser handles only integer numbers. It disables the built in operators thus it is \r
+ slower than muParser. Integer values are stored in the double value_type and converted if needed.\r
+*/\r
+class ParserInt : public ParserBase\r
+{\r
+private:\r
+ static int Round(value_type v) { return (int)(v + ((v>=0) ? 0.5 : -0.5) ); };\r
+ \r
+ static value_type Abs(value_type);\r
+ static value_type Sign(value_type);\r
+ static value_type Ite(value_type, value_type, value_type);\r
+ // !! The unary Minus is a MUST, otherwise you cant use negative signs !!\r
+ static value_type UnaryMinus(value_type);\r
+ // Functions with variable number of arguments\r
+ static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum\r
+ static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum\r
+ static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum\r
+ // binary operator callbacks\r
+ static value_type Add(value_type v1, value_type v2);\r
+ static value_type Sub(value_type v1, value_type v2);\r
+ static value_type Mul(value_type v1, value_type v2);\r
+ static value_type Div(value_type v1, value_type v2);\r
+ static value_type Mod(value_type v1, value_type v2);\r
+ static value_type Pow(value_type v1, value_type v2);\r
+ static value_type Shr(value_type v1, value_type v2);\r
+ static value_type Shl(value_type v1, value_type v2);\r
+ static value_type LogAnd(value_type v1, value_type v2);\r
+ static value_type LogOr(value_type v1, value_type v2);\r
+ static value_type And(value_type v1, value_type v2);\r
+ static value_type Or(value_type v1, value_type v2);\r
+ static value_type Xor(value_type v1, value_type v2);\r
+ static value_type Less(value_type v1, value_type v2);\r
+ static value_type Greater(value_type v1, value_type v2);\r
+ static value_type LessEq(value_type v1, value_type v2);\r
+ static value_type GreaterEq(value_type v1, value_type v2);\r
+ static value_type Equal(value_type v1, value_type v2);\r
+ static value_type NotEqual(value_type v1, value_type v2);\r
+ static value_type Not(value_type v1);\r
+\r
+ static int IsHexVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal);\r
+ static int IsBinVal(const char_type* a_szExpr, int *a_iPos, value_type *a_iVal);\r
+ static int IsVal (const char_type* a_szExpr, int *a_iPos, value_type *a_iVal);\r
+\r
+ /** \brief A facet class used to change decimal and thousands separator. */\r
+ template<class TChar>\r
+ class change_dec_sep : public std::numpunct<TChar>\r
+ {\r
+ public:\r
+ \r
+ explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3)\r
+ :std::numpunct<TChar>()\r
+ ,m_cDecPoint(cDecSep)\r
+ ,m_cThousandsSep(cThousandsSep)\r
+ ,m_nGroup(nGroup)\r
+ {}\r
+ \r
+ protected:\r
+ \r
+ virtual char_type do_decimal_point() const\r
+ {\r
+ return m_cDecPoint;\r
+ }\r
+\r
+ virtual char_type do_thousands_sep() const\r
+ {\r
+ return m_cThousandsSep;\r
+ }\r
+\r
+ virtual std::string do_grouping() const \r
+ { \r
+ return std::string(1, m_nGroup); \r
+ }\r
+\r
+ private:\r
+\r
+ int m_nGroup;\r
+ char_type m_cDecPoint; \r
+ char_type m_cThousandsSep;\r
+ };\r
+\r
+public:\r
+ ParserInt();\r
+\r
+ virtual void InitFun();\r
+ virtual void InitOprt();\r
+ virtual void InitConst();\r
+ virtual void InitCharSets();\r
+};\r
+\r
+} // namespace mu\r
+\r
+#endif\r
+\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2004-2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#ifndef MU_PARSER_STACK_H\r
+#define MU_PARSER_STACK_H\r
+\r
+#include <cassert>\r
+#include <string>\r
+#include <stack>\r
+#include <vector>\r
+\r
+#include "muParserError.h"\r
+#include "muParserToken.h"\r
+\r
+/** \file \r
+ \brief This file defines the stack used by muparser.\r
+*/\r
+\r
+namespace mu\r
+{\r
+\r
+ /** \brief Parser stack implementation. \r
+\r
+ Stack implementation based on a std::stack. The behaviour of pop() had been\r
+ slightly changed in order to get an error code if the stack is empty.\r
+ The stack is used within the Parser both as a value stack and as an operator stack.\r
+\r
+ \author (C) 2004-2011 Ingo Berg \r
+ */\r
+ template <typename TValueType>\r
+ class ParserStack \r
+ {\r
+ private:\r
+\r
+ /** \brief Type of the underlying stack implementation. */\r
+ typedef std::stack<TValueType, std::vector<TValueType> > impl_type;\r
+ \r
+ impl_type m_Stack; ///< This is the actual stack.\r
+\r
+ public: \r
+ \r
+ //---------------------------------------------------------------------------\r
+ ParserStack()\r
+ :m_Stack()\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ virtual ~ParserStack()\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Pop a value from the stack.\r
+ \r
+ Unlike the standard implementation this function will return the value that\r
+ is going to be taken from the stack.\r
+\r
+ \throw ParserException in case the stack is empty.\r
+ \sa pop(int &a_iErrc)\r
+ */\r
+ TValueType pop()\r
+ {\r
+ if (empty())\r
+ throw ParserError( _T("stack is empty.") );\r
+\r
+ TValueType el = top();\r
+ m_Stack.pop();\r
+ return el;\r
+ }\r
+\r
+ /** \brief Push an object into the stack. \r
+\r
+ \param a_Val object to push into the stack.\r
+ \throw nothrow\r
+ */\r
+ void push(const TValueType& a_Val) \r
+ { \r
+ m_Stack.push(a_Val); \r
+ }\r
+\r
+ /** \brief Return the number of stored elements. */\r
+ unsigned size() const\r
+ { \r
+ return (unsigned)m_Stack.size(); \r
+ }\r
+\r
+ /** \brief Returns true if stack is empty false otherwise. */\r
+ bool empty() const\r
+ {\r
+ return m_Stack.size()==0; \r
+ }\r
+ \r
+ /** \brief Return reference to the top object in the stack. \r
+ \r
+ The top object is the one pushed most recently.\r
+ */\r
+ TValueType& top() \r
+ { \r
+ return m_Stack.top(); \r
+ }\r
+ };\r
+} // namespace MathUtils\r
+\r
+#endif\r
--- /dev/null
+#ifndef MU_PARSER_TEMPLATE_MAGIC_H\r
+#define MU_PARSER_TEMPLATE_MAGIC_H\r
+\r
+#include <cmath>\r
+#include "muParserError.h"\r
+\r
+\r
+namespace mu\r
+{\r
+ //-----------------------------------------------------------------------------------------------\r
+ //\r
+ // Compile time type detection\r
+ //\r
+ //-----------------------------------------------------------------------------------------------\r
+\r
+ /** \brief A class singling out integer types at compile time using \r
+ template meta programming.\r
+ */\r
+ template<typename T>\r
+ struct TypeInfo\r
+ {\r
+ static bool IsInteger() { return false; }\r
+ };\r
+\r
+ template<>\r
+ struct TypeInfo<char>\r
+ {\r
+ static bool IsInteger() { return true; }\r
+ };\r
+\r
+ template<>\r
+ struct TypeInfo<short>\r
+ {\r
+ static bool IsInteger() { return true; }\r
+ };\r
+\r
+ template<>\r
+ struct TypeInfo<int>\r
+ {\r
+ static bool IsInteger() { return true; }\r
+ };\r
+\r
+ template<>\r
+ struct TypeInfo<long>\r
+ {\r
+ static bool IsInteger() { return true; }\r
+ };\r
+\r
+ template<>\r
+ struct TypeInfo<unsigned char>\r
+ {\r
+ static bool IsInteger() { return true; }\r
+ };\r
+\r
+ template<>\r
+ struct TypeInfo<unsigned short>\r
+ {\r
+ static bool IsInteger() { return true; }\r
+ };\r
+\r
+ template<>\r
+ struct TypeInfo<unsigned int>\r
+ {\r
+ static bool IsInteger() { return true; }\r
+ };\r
+\r
+ template<>\r
+ struct TypeInfo<unsigned long>\r
+ {\r
+ static bool IsInteger() { return true; }\r
+ };\r
+\r
+\r
+ //-----------------------------------------------------------------------------------------------\r
+ //\r
+ // Standard math functions with dummy overload for integer types\r
+ //\r
+ //-----------------------------------------------------------------------------------------------\r
+\r
+ /** \brief A template class for providing wrappers for essential math functions.\r
+\r
+ This template is spezialized for several types in order to provide a unified interface\r
+ for parser internal math function calls regardless of the data type.\r
+ */\r
+ template<typename T>\r
+ struct MathImpl\r
+ {\r
+ static T Sin(T v) { return sin(v); }\r
+ static T Cos(T v) { return cos(v); }\r
+ static T Tan(T v) { return tan(v); }\r
+ static T ASin(T v) { return asin(v); }\r
+ static T ACos(T v) { return acos(v); }\r
+ static T ATan(T v) { return atan(v); }\r
+ static T ATan2(T v1, T v2) { return atan2(v1, v2); }\r
+ static T Sinh(T v) { return sinh(v); }\r
+ static T Cosh(T v) { return cosh(v); }\r
+ static T Tanh(T v) { return tanh(v); }\r
+ static T ASinh(T v) { return log(v + sqrt(v * v + 1)); }\r
+ static T ACosh(T v) { return log(v + sqrt(v * v - 1)); }\r
+ static T ATanh(T v) { return ((T)0.5 * log((1 + v) / (1 - v))); }\r
+ static T Log(T v) { return log(v); } \r
+ static T Log2(T v) { return log(v)/log((T)2); } // Logarithm base 2\r
+ static T Log10(T v) { return log10(v); } // Logarithm base 10\r
+ static T Exp(T v) { return exp(v); }\r
+ static T Abs(T v) { return (v>=0) ? v : -v; }\r
+ static T Sqrt(T v) { return sqrt(v); }\r
+ static T Rint(T v) { return floor(v + (T)0.5); }\r
+ static T Sign(T v) { return (T)((v<0) ? -1 : (v>0) ? 1 : 0); }\r
+ static T Pow(T v1, T v2) { return std::pow(v1, v2); }\r
+ };\r
+\r
+ // Create (mostly) dummy math function definitions for integer types. They are mostly\r
+ // empty since they are not applicable for integer values.\r
+#define MAKE_MATH_DUMMY(TYPE) \\r
+ template<> \\r
+ struct MathImpl<TYPE> \\r
+ { \\r
+ static TYPE Sin(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Cos(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Tan(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE ASin(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE ACos(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE ATan(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE ATan2(TYPE, TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Sinh(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Cosh(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Tanh(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE ASinh(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE ACosh(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE ATanh(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Log(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Log2(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Log10(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Exp(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Abs(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Sqrt(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Rint(TYPE) { throw ParserError(_T("unimplemented function.")); } \\r
+ static TYPE Sign(TYPE v) { return (TYPE)((v<0) ? -1 : (v>0) ? 1 : 0); } \\r
+ static TYPE Pow(TYPE v1, TYPE v2) { return (TYPE)std::pow((double)v1, (double)v2); } \\r
+ };\r
+\r
+ MAKE_MATH_DUMMY(char)\r
+ MAKE_MATH_DUMMY(short)\r
+ MAKE_MATH_DUMMY(int)\r
+ MAKE_MATH_DUMMY(long)\r
+\r
+#undef MAKE_MATH_DUMMY\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#ifndef MU_PARSER_TEST_H\r
+#define MU_PARSER_TEST_H\r
+\r
+#include <string>\r
+#include <cstdlib>\r
+#include <numeric> // for accumulate\r
+#include "muParser.h"\r
+#include "muParserInt.h"\r
+\r
+/** \file\r
+ \brief This file contains the parser test class.\r
+*/\r
+\r
+namespace mu\r
+{\r
+ /** \brief Namespace for test cases. */\r
+ namespace Test\r
+ {\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Test cases for unit testing.\r
+\r
+ (C) 2004-2011 Ingo Berg\r
+ */\r
+ class ParserTester // final\r
+ {\r
+ private:\r
+ static int c_iCount;\r
+\r
+ // Multiarg callbacks\r
+ static value_type f1of1(value_type v) { return v;};\r
+ \r
+ static value_type f1of2(value_type v, value_type ) {return v;};\r
+ static value_type f2of2(value_type , value_type v) {return v;};\r
+\r
+ static value_type f1of3(value_type v, value_type , value_type ) {return v;};\r
+ static value_type f2of3(value_type , value_type v, value_type ) {return v;};\r
+ static value_type f3of3(value_type , value_type , value_type v) {return v;};\r
+ \r
+ static value_type f1of4(value_type v, value_type, value_type , value_type ) {return v;}\r
+ static value_type f2of4(value_type , value_type v, value_type , value_type ) {return v;}\r
+ static value_type f3of4(value_type , value_type, value_type v, value_type ) {return v;}\r
+ static value_type f4of4(value_type , value_type, value_type , value_type v) {return v;}\r
+\r
+ static value_type f1of5(value_type v, value_type, value_type , value_type , value_type ) { return v; }\r
+ static value_type f2of5(value_type , value_type v, value_type , value_type , value_type ) { return v; }\r
+ static value_type f3of5(value_type , value_type, value_type v, value_type , value_type ) { return v; }\r
+ static value_type f4of5(value_type , value_type, value_type , value_type v, value_type ) { return v; }\r
+ static value_type f5of5(value_type , value_type, value_type , value_type , value_type v) { return v; }\r
+\r
+ static value_type Min(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1<a_fVal2) ? a_fVal1 : a_fVal2; }\r
+ static value_type Max(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1>a_fVal2) ? a_fVal1 : a_fVal2; }\r
+\r
+ static value_type plus2(value_type v1) { return v1+2; }\r
+ static value_type times3(value_type v1) { return v1*3; }\r
+ static value_type sqr(value_type v1) { return v1*v1; }\r
+ static value_type sign(value_type v) { return -v; }\r
+ static value_type add(value_type v1, value_type v2) { return v1+v2; }\r
+ static value_type land(value_type v1, value_type v2) { return (int)v1 & (int)v2; }\r
+ \r
+\r
+ static value_type FirstArg(const value_type* a_afArg, int a_iArgc)\r
+ {\r
+ if (!a_iArgc) \r
+ throw mu::Parser::exception_type( _T("too few arguments for function FirstArg.") );\r
+\r
+ return a_afArg[0];\r
+ }\r
+\r
+ static value_type LastArg(const value_type* a_afArg, int a_iArgc)\r
+ {\r
+ if (!a_iArgc) \r
+ throw mu::Parser::exception_type( _T("too few arguments for function LastArg.") );\r
+\r
+ return a_afArg[a_iArgc-1];\r
+ }\r
+\r
+ static value_type Sum(const value_type* a_afArg, int a_iArgc)\r
+ { \r
+ if (!a_iArgc) \r
+ throw mu::Parser::exception_type( _T("too few arguments for function sum.") );\r
+\r
+ value_type fRes=0;\r
+ for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];\r
+ return fRes;\r
+ }\r
+\r
+ static value_type Rnd(value_type v)\r
+ {\r
+ return (value_type)(1+(v*std::rand()/(RAND_MAX+1.0)));\r
+ }\r
+\r
+ static value_type RndWithString(const char_type*)\r
+ {\r
+ return (value_type)( 1 + (1000.0f * std::rand() / (RAND_MAX + 1.0) ) );\r
+ }\r
+\r
+ static value_type Ping()\r
+ { \r
+ return 10; \r
+ }\r
+\r
+ static value_type ValueOf(const char_type*) \r
+ { \r
+ return 123; \r
+ }\r
+\r
+ static value_type StrFun1(const char_type* v1) \r
+ { \r
+ int val(0);\r
+ stringstream_type(v1) >> val;\r
+ return (value_type)val;\r
+ }\r
+\r
+ static value_type StrFun2(const char_type* v1, value_type v2) \r
+ { \r
+ int val(0);\r
+ stringstream_type(v1) >> val;\r
+ return (value_type)(val + v2);\r
+ }\r
+ \r
+ static value_type StrFun3(const char_type* v1, value_type v2, value_type v3) \r
+ { \r
+ int val(0);\r
+ stringstream_type(v1) >> val;\r
+ return val + v2 + v3;\r
+ }\r
+\r
+ static value_type StrToFloat(const char_type* a_szMsg)\r
+ {\r
+ value_type val(0);\r
+ stringstream_type(a_szMsg) >> val;\r
+ return val;\r
+ }\r
+\r
+ // postfix operator callback\r
+ static value_type Mega(value_type a_fVal) { return a_fVal * (value_type)1e6; }\r
+ static value_type Micro(value_type a_fVal) { return a_fVal * (value_type)1e-6; }\r
+ static value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }\r
+\r
+ // Custom value recognition\r
+ static int IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal);\r
+\r
+ int TestNames();\r
+ int TestSyntax();\r
+ int TestMultiArg();\r
+ int TestPostFix();\r
+ int TestExpression();\r
+ int TestInfixOprt();\r
+ int TestBinOprt();\r
+ int TestVarConst();\r
+ int TestInterface();\r
+ int TestException();\r
+ int TestStrArg();\r
+ int TestIfThenElse();\r
+\r
+ void Abort() const;\r
+\r
+ public:\r
+ typedef int (ParserTester::*testfun_type)();\r
+\r
+ ParserTester();\r
+ void Run();\r
+\r
+ private:\r
+ std::vector<testfun_type> m_vTestFun;\r
+ void AddTest(testfun_type a_pFun);\r
+\r
+ // Test Double Parser\r
+ int EqnTest(const string_type& a_str, double a_fRes, bool a_fPass);\r
+ int EqnTestWithVarChange(const string_type& a_str, \r
+ double a_fRes1, \r
+ double a_fVar1, \r
+ double a_fRes2, \r
+ double a_fVar2);\r
+ int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true);\r
+\r
+ // Test Int Parser\r
+ int EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass);\r
+ };\r
+ } // namespace Test\r
+} // namespace mu\r
+\r
+#endif\r
+\r
+\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2004-2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#ifndef MU_PARSER_TOKEN_H\r
+#define MU_PARSER_TOKEN_H\r
+\r
+#include <cassert>\r
+#include <string>\r
+#include <stack>\r
+#include <vector>\r
+#include <memory>\r
+\r
+#include "muParserError.h"\r
+#include "muParserCallback.h"\r
+\r
+/** \file\r
+ \brief This file contains the parser token definition.\r
+*/\r
+\r
+namespace mu\r
+{\r
+ /** \brief Encapsulation of the data for a single formula token. \r
+\r
+ Formula token implementation. Part of the Math Parser Package.\r
+ Formula tokens can be either one of the following:\r
+ <ul>\r
+ <li>value</li>\r
+ <li>variable</li>\r
+ <li>function with numerical arguments</li>\r
+ <li>functions with a string as argument</li>\r
+ <li>prefix operators</li>\r
+ <li>infix operators</li>\r
+ <li>binary operator</li>\r
+ </ul>\r
+\r
+ \author (C) 2004-2013 Ingo Berg \r
+ */\r
+ template<typename TBase, typename TString>\r
+ class ParserToken\r
+ {\r
+ private:\r
+\r
+ ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode.\r
+ ETypeCode m_iType;\r
+ void *m_pTok; ///< Stores Token pointer; not applicable for all tokens\r
+ int m_iIdx; ///< An otional index to an external buffer storing the token data\r
+ TString m_strTok; ///< Token string\r
+ TString m_strVal; ///< Value for string variables\r
+ value_type m_fVal; ///< the value \r
+ std::auto_ptr<ParserCallback> m_pCallback;\r
+\r
+ public:\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Constructor (default).\r
+ \r
+ Sets token to an neutral state of type cmUNKNOWN.\r
+ \throw nothrow\r
+ \sa ECmdCode\r
+ */\r
+ ParserToken()\r
+ :m_iCode(cmUNKNOWN)\r
+ ,m_iType(tpVOID)\r
+ ,m_pTok(0)\r
+ ,m_iIdx(-1)\r
+ ,m_strTok()\r
+ ,m_pCallback()\r
+ {}\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Create token from another one.\r
+ \r
+ Implemented by calling Assign(...)\r
+ \throw nothrow\r
+ \post m_iType==cmUNKNOWN\r
+ \sa #Assign\r
+ */\r
+ ParserToken(const ParserToken &a_Tok)\r
+ {\r
+ Assign(a_Tok);\r
+ }\r
+ \r
+ //------------------------------------------------------------------------------\r
+ /** \brief Assignement operator. \r
+ \r
+ Copy token state from another token and return this.\r
+ Implemented by calling Assign(...).\r
+ \throw nothrow\r
+ */\r
+ ParserToken& operator=(const ParserToken &a_Tok)\r
+ {\r
+ Assign(a_Tok);\r
+ return *this;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Copy token information from argument.\r
+ \r
+ \throw nothrow\r
+ */\r
+ void Assign(const ParserToken &a_Tok)\r
+ {\r
+ m_iCode = a_Tok.m_iCode;\r
+ m_pTok = a_Tok.m_pTok;\r
+ m_strTok = a_Tok.m_strTok;\r
+ m_iIdx = a_Tok.m_iIdx;\r
+ m_strVal = a_Tok.m_strVal;\r
+ m_iType = a_Tok.m_iType;\r
+ m_fVal = a_Tok.m_fVal;\r
+ // create new callback object if a_Tok has one \r
+ m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0);\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Assign a token type. \r
+\r
+ Token may not be of type value, variable or function. Those have seperate set functions. \r
+\r
+ \pre [assert] a_iType!=cmVAR\r
+ \pre [assert] a_iType!=cmVAL\r
+ \pre [assert] a_iType!=cmFUNC\r
+ \post m_fVal = 0\r
+ \post m_pTok = 0\r
+ */\r
+ ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString())\r
+ {\r
+ // The following types cant be set this way, they have special Set functions\r
+ assert(a_iType!=cmVAR);\r
+ assert(a_iType!=cmVAL);\r
+ assert(a_iType!=cmFUNC);\r
+\r
+ m_iCode = a_iType;\r
+ m_iType = tpVOID;\r
+ m_pTok = 0;\r
+ m_strTok = a_strTok;\r
+ m_iIdx = -1;\r
+\r
+ return *this;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Set Callback type. */\r
+ ParserToken& Set(const ParserCallback &a_pCallback, const TString &a_sTok)\r
+ {\r
+ assert(a_pCallback.GetAddr());\r
+\r
+ m_iCode = a_pCallback.GetCode();\r
+ m_iType = tpVOID;\r
+ m_strTok = a_sTok;\r
+ m_pCallback.reset(new ParserCallback(a_pCallback));\r
+\r
+ m_pTok = 0;\r
+ m_iIdx = -1;\r
+ \r
+ return *this;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Make this token a value token. \r
+ \r
+ Member variables not necessary for value tokens will be invalidated.\r
+ \throw nothrow\r
+ */\r
+ ParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString())\r
+ {\r
+ m_iCode = cmVAL;\r
+ m_iType = tpDBL;\r
+ m_fVal = a_fVal;\r
+ m_strTok = a_strTok;\r
+ m_iIdx = -1;\r
+ \r
+ m_pTok = 0;\r
+ m_pCallback.reset(0);\r
+\r
+ return *this;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief make this token a variable token. \r
+ \r
+ Member variables not necessary for variable tokens will be invalidated.\r
+ \throw nothrow\r
+ */\r
+ ParserToken& SetVar(TBase *a_pVar, const TString &a_strTok)\r
+ {\r
+ m_iCode = cmVAR;\r
+ m_iType = tpDBL;\r
+ m_strTok = a_strTok;\r
+ m_iIdx = -1;\r
+ m_pTok = (void*)a_pVar;\r
+ m_pCallback.reset(0);\r
+ return *this;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Make this token a variable token. \r
+ \r
+ Member variables not necessary for variable tokens will be invalidated.\r
+ \throw nothrow\r
+ */\r
+ ParserToken& SetString(const TString &a_strTok, std::size_t a_iSize)\r
+ {\r
+ m_iCode = cmSTRING;\r
+ m_iType = tpSTR;\r
+ m_strTok = a_strTok;\r
+ m_iIdx = static_cast<int>(a_iSize);\r
+\r
+ m_pTok = 0;\r
+ m_pCallback.reset(0);\r
+ return *this;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Set an index associated with the token related data. \r
+ \r
+ In cmSTRFUNC - This is the index to a string table in the main parser.\r
+ \param a_iIdx The index the string function result will take in the bytecode parser.\r
+ \throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING\r
+ */\r
+ void SetIdx(int a_iIdx)\r
+ {\r
+ if (m_iCode!=cmSTRING || a_iIdx<0)\r
+ throw ParserError(ecINTERNAL_ERROR);\r
+ \r
+ m_iIdx = a_iIdx;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Return Index associated with the token related data. \r
+ \r
+ In cmSTRFUNC - This is the index to a string table in the main parser.\r
+\r
+ \throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING\r
+ \return The index the result will take in the Bytecode calculatin array (#m_iIdx).\r
+ */\r
+ int GetIdx() const\r
+ {\r
+ if (m_iIdx<0 || m_iCode!=cmSTRING )\r
+ throw ParserError(ecINTERNAL_ERROR);\r
+\r
+ return m_iIdx;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Return the token type.\r
+ \r
+ \return #m_iType\r
+ \throw nothrow\r
+ */\r
+ ECmdCode GetCode() const\r
+ {\r
+ if (m_pCallback.get())\r
+ {\r
+ return m_pCallback->GetCode();\r
+ }\r
+ else\r
+ {\r
+ return m_iCode;\r
+ }\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ ETypeCode GetType() const\r
+ {\r
+ if (m_pCallback.get())\r
+ {\r
+ return m_pCallback->GetType();\r
+ }\r
+ else\r
+ {\r
+ return m_iType;\r
+ }\r
+ }\r
+ \r
+ //------------------------------------------------------------------------------\r
+ int GetPri() const\r
+ {\r
+ if ( !m_pCallback.get())\r
+ throw ParserError(ecINTERNAL_ERROR);\r
+ \r
+ if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX)\r
+ throw ParserError(ecINTERNAL_ERROR);\r
+\r
+ return m_pCallback->GetPri();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ EOprtAssociativity GetAssociativity() const\r
+ {\r
+ if (m_pCallback.get()==NULL || m_pCallback->GetCode()!=cmOPRT_BIN)\r
+ throw ParserError(ecINTERNAL_ERROR);\r
+\r
+ return m_pCallback->GetAssociativity();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Return the address of the callback function assoziated with\r
+ function and operator tokens.\r
+\r
+ \return The pointer stored in #m_pTok.\r
+ \throw exception_type if token type is non of:\r
+ <ul>\r
+ <li>cmFUNC</li>\r
+ <li>cmSTRFUNC</li>\r
+ <li>cmPOSTOP</li>\r
+ <li>cmINFIXOP</li>\r
+ <li>cmOPRT_BIN</li>\r
+ </ul>\r
+ \sa ECmdCode\r
+ */\r
+ generic_fun_type GetFuncAddr() const\r
+ {\r
+ return (m_pCallback.get()) ? (generic_fun_type)m_pCallback->GetAddr() : 0;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \biref Get value of the token.\r
+ \r
+ Only applicable to variable and value tokens.\r
+ \throw exception_type if token is no value/variable token.\r
+ */\r
+ TBase GetVal() const\r
+ {\r
+ switch (m_iCode)\r
+ {\r
+ case cmVAL: return m_fVal;\r
+ case cmVAR: return *((TBase*)m_pTok);\r
+ default: throw ParserError(ecVAL_EXPECTED);\r
+ }\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Get address of a variable token.\r
+\r
+ Valid only if m_iType==CmdVar.\r
+ \throw exception_type if token is no variable token.\r
+ */\r
+ TBase* GetVar() const\r
+ {\r
+ if (m_iCode!=cmVAR)\r
+ throw ParserError(ecINTERNAL_ERROR);\r
+\r
+ return (TBase*)m_pTok;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Return the number of function arguments. \r
+\r
+ Valid only if m_iType==CmdFUNC.\r
+ */\r
+ int GetArgCount() const\r
+ {\r
+ assert(m_pCallback.get());\r
+\r
+ if (!m_pCallback->GetAddr())\r
+ throw ParserError(ecINTERNAL_ERROR);\r
+\r
+ return m_pCallback->GetArgc();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Return the token identifier. \r
+ \r
+ If #m_iType is cmSTRING the token identifier is the value of the string argument\r
+ for a string function.\r
+ \return #m_strTok\r
+ \throw nothrow\r
+ \sa m_strTok\r
+ */\r
+ const TString& GetAsString() const\r
+ {\r
+ return m_strTok;\r
+ }\r
+ };\r
+} // namespace mu\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2004-2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#ifndef MU_PARSER_TOKEN_READER_H\r
+#define MU_PARSER_TOKEN_READER_H\r
+\r
+#include <cassert>\r
+#include <cstdio>\r
+#include <cstring>\r
+#include <list>\r
+#include <map>\r
+#include <memory>\r
+#include <stack>\r
+#include <string>\r
+\r
+#include "muParserDef.h"\r
+#include "muParserToken.h"\r
+\r
+/** \file\r
+ \brief This file contains the parser token reader definition.\r
+*/\r
+\r
+\r
+namespace mu\r
+{\r
+ // Forward declaration\r
+ class ParserBase;\r
+\r
+ /** \brief Token reader for the ParserBase class.\r
+\r
+ */\r
+ class ParserTokenReader \r
+ {\r
+ private:\r
+\r
+ typedef ParserToken<value_type, string_type> token_type;\r
+\r
+ public:\r
+\r
+ ParserTokenReader(ParserBase *a_pParent);\r
+ ParserTokenReader* Clone(ParserBase *a_pParent) const;\r
+\r
+ void AddValIdent(identfun_type a_pCallback);\r
+ void SetVarCreator(facfun_type a_pFactory, void *pUserData);\r
+ void SetFormula(const string_type &a_strFormula);\r
+ void SetArgSep(char_type cArgSep);\r
+\r
+ int GetPos() const;\r
+ const string_type& GetExpr() const;\r
+ varmap_type& GetUsedVar();\r
+ char_type GetArgSep() const;\r
+\r
+ void IgnoreUndefVar(bool bIgnore);\r
+ void ReInit();\r
+ token_type ReadNextToken();\r
+\r
+ private:\r
+\r
+ /** \brief Syntax codes. \r
+ \r
+ The syntax codes control the syntax check done during the first time parsing of \r
+ the expression string. They are flags that indicate which tokens are allowed next\r
+ if certain tokens are identified.\r
+ */\r
+ enum ESynCodes\r
+ {\r
+ noBO = 1 << 0, ///< to avoid i.e. "cos(7)(" \r
+ noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()"\r
+ noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14"\r
+ noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a"\r
+ noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ...\r
+ noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin" \r
+ noOPT = 1 << 6, ///< to avoid i.e. "(+)"\r
+ noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!"\r
+ noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4"\r
+ noEND = 1 << 9, ///< to avoid unexpected end of formula\r
+ noSTR = 1 << 10, ///< to block numeric arguments on string functions\r
+ noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7"\r
+ noIF = 1 << 12,\r
+ noELSE = 1 << 13,\r
+ sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP,\r
+ noANY = ~0 ///< All of he above flags set\r
+ }; \r
+\r
+ ParserTokenReader(const ParserTokenReader &a_Reader);\r
+ ParserTokenReader& operator=(const ParserTokenReader &a_Reader);\r
+ void Assign(const ParserTokenReader &a_Reader);\r
+\r
+ void SetParent(ParserBase *a_pParent);\r
+ int ExtractToken(const char_type *a_szCharSet, \r
+ string_type &a_strTok, \r
+ int a_iPos) const;\r
+ int ExtractOperatorToken(string_type &a_sTok, int a_iPos) const;\r
+\r
+ bool IsBuiltIn(token_type &a_Tok);\r
+ bool IsArgSep(token_type &a_Tok);\r
+ bool IsEOF(token_type &a_Tok);\r
+ bool IsInfixOpTok(token_type &a_Tok);\r
+ bool IsFunTok(token_type &a_Tok);\r
+ bool IsPostOpTok(token_type &a_Tok);\r
+ bool IsOprt(token_type &a_Tok);\r
+ bool IsValTok(token_type &a_Tok);\r
+ bool IsVarTok(token_type &a_Tok);\r
+ bool IsStrVarTok(token_type &a_Tok);\r
+ bool IsUndefVarTok(token_type &a_Tok);\r
+ bool IsString(token_type &a_Tok);\r
+ void Error(EErrorCodes a_iErrc, \r
+ int a_iPos = -1, \r
+ const string_type &a_sTok = string_type() ) const;\r
+\r
+ token_type& SaveBeforeReturn(const token_type &tok);\r
+\r
+ ParserBase *m_pParser;\r
+ string_type m_strFormula;\r
+ int m_iPos;\r
+ int m_iSynFlags;\r
+ bool m_bIgnoreUndefVar;\r
+\r
+ const funmap_type *m_pFunDef;\r
+ const funmap_type *m_pPostOprtDef;\r
+ const funmap_type *m_pInfixOprtDef;\r
+ const funmap_type *m_pOprtDef;\r
+ const valmap_type *m_pConstDef;\r
+ const strmap_type *m_pStrVarDef;\r
+ varmap_type *m_pVarDef; ///< The only non const pointer to parser internals\r
+ facfun_type m_pFactory;\r
+ void *m_pFactoryData;\r
+ std::list<identfun_type> m_vIdentFun; ///< Value token identification function\r
+ varmap_type m_UsedVar;\r
+ value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables\r
+ int m_iBrackets;\r
+ token_type m_lastTok;\r
+ char_type m_cArgSep; ///< The character used for separating function arguments\r
+ };\r
+} // namespace mu\r
+\r
+#endif\r
+\r
+\r
--- /dev/null
+/* \r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+\r
+ Copyright (C) 2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+#include "muParser.h"\r
+#include "muParserTemplateMagic.h"\r
+\r
+//--- Standard includes ------------------------------------------------------------------------\r
+#include <cmath>\r
+#include <algorithm>\r
+#include <numeric>\r
+\r
+/** \brief Pi (what else?). */\r
+#define PARSER_CONST_PI 3.141592653589793238462643\r
+\r
+/** \brief The eulerian number. */\r
+#define PARSER_CONST_E 2.718281828459045235360287\r
+\r
+using namespace std;\r
+\r
+/** \file\r
+ \brief Implementation of the standard floating point parser.\r
+*/\r
+\r
+\r
+\r
+/** \brief Namespace for mathematical applications. */\r
+namespace mu\r
+{\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ // Trigonometric function\r
+ value_type Parser::Sin(value_type v) { return MathImpl<value_type>::Sin(v); }\r
+ value_type Parser::Cos(value_type v) { return MathImpl<value_type>::Cos(v); }\r
+ value_type Parser::Tan(value_type v) { return MathImpl<value_type>::Tan(v); }\r
+ value_type Parser::ASin(value_type v) { return MathImpl<value_type>::ASin(v); }\r
+ value_type Parser::ACos(value_type v) { return MathImpl<value_type>::ACos(v); }\r
+ value_type Parser::ATan(value_type v) { return MathImpl<value_type>::ATan(v); }\r
+ value_type Parser::ATan2(value_type v1, value_type v2) { return MathImpl<value_type>::ATan2(v1, v2); }\r
+ value_type Parser::Sinh(value_type v) { return MathImpl<value_type>::Sinh(v); }\r
+ value_type Parser::Cosh(value_type v) { return MathImpl<value_type>::Cosh(v); }\r
+ value_type Parser::Tanh(value_type v) { return MathImpl<value_type>::Tanh(v); }\r
+ value_type Parser::ASinh(value_type v) { return MathImpl<value_type>::ASinh(v); }\r
+ value_type Parser::ACosh(value_type v) { return MathImpl<value_type>::ACosh(v); }\r
+ value_type Parser::ATanh(value_type v) { return MathImpl<value_type>::ATanh(v); }\r
+\r
+ //---------------------------------------------------------------------------\r
+ // Logarithm functions\r
+\r
+ // Logarithm base 2\r
+ value_type Parser::Log2(value_type v) \r
+ { \r
+ #ifdef MUP_MATH_EXCEPTIONS\r
+ if (v<=0)\r
+ throw ParserError(ecDOMAIN_ERROR, _T("Log2"));\r
+ #endif\r
+\r
+ return MathImpl<value_type>::Log2(v); \r
+ } \r
+\r
+ // Logarithm base 10\r
+ value_type Parser::Log10(value_type v) \r
+ { \r
+ #ifdef MUP_MATH_EXCEPTIONS\r
+ if (v<=0)\r
+ throw ParserError(ecDOMAIN_ERROR, _T("Log10"));\r
+ #endif\r
+\r
+ return MathImpl<value_type>::Log10(v); \r
+ } \r
+\r
+// Logarithm base e (natural logarithm)\r
+ value_type Parser::Ln(value_type v) \r
+ { \r
+ #ifdef MUP_MATH_EXCEPTIONS\r
+ if (v<=0)\r
+ throw ParserError(ecDOMAIN_ERROR, _T("Ln"));\r
+ #endif\r
+\r
+ return MathImpl<value_type>::Log(v); \r
+ } \r
+\r
+ //---------------------------------------------------------------------------\r
+ // misc\r
+ value_type Parser::Exp(value_type v) { return MathImpl<value_type>::Exp(v); }\r
+ value_type Parser::Abs(value_type v) { return MathImpl<value_type>::Abs(v); }\r
+ value_type Parser::Sqrt(value_type v) \r
+ { \r
+ #ifdef MUP_MATH_EXCEPTIONS\r
+ if (v<0)\r
+ throw ParserError(ecDOMAIN_ERROR, _T("sqrt"));\r
+ #endif\r
+\r
+ return MathImpl<value_type>::Sqrt(v); \r
+ }\r
+ value_type Parser::Rint(value_type v) { return MathImpl<value_type>::Rint(v); }\r
+ value_type Parser::Sign(value_type v) { return MathImpl<value_type>::Sign(v); }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Callback for the unary minus operator.\r
+ \param v The value to negate\r
+ \return -v\r
+ */\r
+ value_type Parser::UnaryMinus(value_type v) \r
+ { \r
+ return -v; \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Callback for adding multiple values. \r
+ \param [in] a_afArg Vector with the function arguments\r
+ \param [in] a_iArgc The size of a_afArg\r
+ */\r
+ value_type Parser::Sum(const value_type *a_afArg, int a_iArgc)\r
+ { \r
+ if (!a_iArgc) \r
+ throw exception_type(_T("too few arguments for function sum."));\r
+\r
+ value_type fRes=0;\r
+ for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];\r
+ return fRes;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Callback for averaging multiple values. \r
+ \param [in] a_afArg Vector with the function arguments\r
+ \param [in] a_iArgc The size of a_afArg\r
+ */\r
+ value_type Parser::Avg(const value_type *a_afArg, int a_iArgc)\r
+ { \r
+ if (!a_iArgc) \r
+ throw exception_type(_T("too few arguments for function sum."));\r
+\r
+ value_type fRes=0;\r
+ for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];\r
+ return fRes/(value_type)a_iArgc;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Callback for determining the minimum value out of a vector. \r
+ \param [in] a_afArg Vector with the function arguments\r
+ \param [in] a_iArgc The size of a_afArg\r
+ */\r
+ value_type Parser::Min(const value_type *a_afArg, int a_iArgc)\r
+ { \r
+ if (!a_iArgc) \r
+ throw exception_type(_T("too few arguments for function min."));\r
+\r
+ value_type fRes=a_afArg[0];\r
+ for (int i=0; i<a_iArgc; ++i) \r
+ fRes = std::min(fRes, a_afArg[i]);\r
+\r
+ return fRes;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Callback for determining the maximum value out of a vector. \r
+ \param [in] a_afArg Vector with the function arguments\r
+ \param [in] a_iArgc The size of a_afArg\r
+ */\r
+ value_type Parser::Max(const value_type *a_afArg, int a_iArgc)\r
+ { \r
+ if (!a_iArgc) \r
+ throw exception_type(_T("too few arguments for function min."));\r
+\r
+ value_type fRes=a_afArg[0];\r
+ for (int i=0; i<a_iArgc; ++i) fRes = std::max(fRes, a_afArg[i]);\r
+\r
+ return fRes;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Default value recognition callback. \r
+ \param [in] a_szExpr Pointer to the expression\r
+ \param [in, out] a_iPos Pointer to an index storing the current position within the expression\r
+ \param [out] a_fVal Pointer where the value should be stored in case one is found.\r
+ \return 1 if a value was found 0 otherwise.\r
+ */\r
+ int Parser::IsVal(const char_type* a_szExpr, int *a_iPos, value_type *a_fVal)\r
+ {\r
+ value_type fVal(0);\r
+\r
+ stringstream_type stream(a_szExpr);\r
+ stream.seekg(0); // todo: check if this really is necessary\r
+ stream.imbue(Parser::s_locale);\r
+ stream >> fVal;\r
+ stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading\r
+\r
+ if (iEnd==(stringstream_type::pos_type)-1)\r
+ return 0;\r
+\r
+ *a_iPos += (int)iEnd;\r
+ *a_fVal = fVal;\r
+ return 1;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Constructor. \r
+\r
+ Call ParserBase class constructor and trigger Function, Operator and Constant initialization.\r
+ */\r
+ Parser::Parser()\r
+ :ParserBase()\r
+ {\r
+ AddValIdent(IsVal);\r
+\r
+ InitCharSets();\r
+ InitFun();\r
+ InitConst();\r
+ InitOprt();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Define the character sets. \r
+ \sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars\r
+ \r
+ This function is used for initializing the default character sets that define\r
+ the characters to be useable in function and variable names and operators.\r
+ */\r
+ void Parser::InitCharSets()\r
+ {\r
+ DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") );\r
+ DefineOprtChars( _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}") );\r
+ DefineInfixOprtChars( _T("/+-*^?<>=#!$%&|~'_") );\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Initialize the default functions. */\r
+ void Parser::InitFun()\r
+ {\r
+ if (mu::TypeInfo<mu::value_type>::IsInteger())\r
+ {\r
+ // When setting MUP_BASETYPE to an integer type\r
+ // Place functions for dealing with integer values here\r
+ // ...\r
+ // ...\r
+ // ...\r
+ }\r
+ else\r
+ {\r
+ // trigonometric functions\r
+ DefineFun(_T("sin"), Sin);\r
+ DefineFun(_T("cos"), Cos);\r
+ DefineFun(_T("tan"), Tan);\r
+ // arcus functions\r
+ DefineFun(_T("asin"), ASin);\r
+ DefineFun(_T("acos"), ACos);\r
+ DefineFun(_T("atan"), ATan);\r
+ DefineFun(_T("atan2"), ATan2);\r
+ // hyperbolic functions\r
+ DefineFun(_T("sinh"), Sinh);\r
+ DefineFun(_T("cosh"), Cosh);\r
+ DefineFun(_T("tanh"), Tanh);\r
+ // arcus hyperbolic functions\r
+ DefineFun(_T("asinh"), ASinh);\r
+ DefineFun(_T("acosh"), ACosh);\r
+ DefineFun(_T("atanh"), ATanh);\r
+ // Logarithm functions\r
+ DefineFun(_T("log2"), Log2);\r
+ DefineFun(_T("log10"), Log10);\r
+ DefineFun(_T("log"), Log10);\r
+ DefineFun(_T("ln"), Ln);\r
+ // misc\r
+ DefineFun(_T("exp"), Exp);\r
+ DefineFun(_T("sqrt"), Sqrt);\r
+ DefineFun(_T("sign"), Sign);\r
+ DefineFun(_T("rint"), Rint);\r
+ DefineFun(_T("abs"), Abs);\r
+ // Functions with variable number of arguments\r
+ DefineFun(_T("sum"), Sum);\r
+ DefineFun(_T("avg"), Avg);\r
+ DefineFun(_T("min"), Min);\r
+ DefineFun(_T("max"), Max);\r
+ }\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Initialize constants.\r
+ \r
+ By default the parser recognizes two constants. Pi ("pi") and the eulerian\r
+ number ("_e").\r
+ */\r
+ void Parser::InitConst()\r
+ {\r
+ DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI);\r
+ DefineConst(_T("_e"), (value_type)PARSER_CONST_E);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Initialize operators. \r
+ \r
+ By default only the unary minus operator is added.\r
+ */\r
+ void Parser::InitOprt()\r
+ {\r
+ DefineInfixOprt(_T("-"), UnaryMinus);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void Parser::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/)\r
+ {\r
+ // this is just sample code to illustrate modifying variable names on the fly.\r
+ // I'm not sure anyone really needs such a feature...\r
+ /*\r
+\r
+\r
+ string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd);\r
+ string sRepl = std::string("_") + sVar + "_";\r
+ \r
+ int nOrigVarEnd = nEnd;\r
+ cout << "variable detected!\n";\r
+ cout << " Expr: " << *pExpr << "\n";\r
+ cout << " Start: " << nStart << "\n";\r
+ cout << " End: " << nEnd << "\n";\r
+ cout << " Var: \"" << sVar << "\"\n";\r
+ cout << " Repl: \"" << sRepl << "\"\n";\r
+ nEnd = nStart + sRepl.length();\r
+ cout << " End: " << nEnd << "\n";\r
+ pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl);\r
+ cout << " New expr: " << *pExpr << "\n";\r
+ */\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Numerically differentiate with regard to a variable. \r
+ \param [in] a_Var Pointer to the differentiation variable.\r
+ \param [in] a_fPos Position at which the differentiation should take place.\r
+ \param [in] a_fEpsilon Epsilon used for the numerical differentiation.\r
+\r
+ Numerical differentiation uses a 5 point operator yielding a 4th order \r
+ formula. The default value for epsilon is 0.00074 which is\r
+ numeric_limits<double>::epsilon() ^ (1/5) as suggested in the muparser\r
+ forum:\r
+\r
+ http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843\r
+ */\r
+ value_type Parser::Diff(value_type *a_Var, \r
+ value_type a_fPos, \r
+ value_type a_fEpsilon) const\r
+ {\r
+ value_type fRes(0), \r
+ fBuf(*a_Var),\r
+ f[4] = {0,0,0,0},\r
+ fEpsilon(a_fEpsilon);\r
+\r
+ // Backwards compatible calculation of epsilon inc case the user doesnt provide\r
+ // his own epsilon\r
+ if (fEpsilon==0)\r
+ fEpsilon = (a_fPos==0) ? (value_type)1e-10 : (value_type)1e-7 * a_fPos;\r
+\r
+ *a_Var = a_fPos+2 * fEpsilon; f[0] = Eval();\r
+ *a_Var = a_fPos+1 * fEpsilon; f[1] = Eval();\r
+ *a_Var = a_fPos-1 * fEpsilon; f[2] = Eval();\r
+ *a_Var = a_fPos-2 * fEpsilon; f[3] = Eval();\r
+ *a_Var = fBuf; // restore variable\r
+\r
+ fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon);\r
+ return fRes;\r
+ }\r
+} // namespace mu\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#include "muParserBase.h"\r
+#include "muParserTemplateMagic.h"\r
+\r
+//--- Standard includes ------------------------------------------------------------------------\r
+#include <cassert>\r
+#include <cmath>\r
+#include <memory>\r
+#include <vector>\r
+#include <deque>\r
+#include <sstream>\r
+#include <locale>\r
+\r
+#ifdef MUP_USE_OPENMP\r
+ #include <omp.h>\r
+#endif\r
+\r
+using namespace std;\r
+\r
+/** \file\r
+ \brief This file contains the basic implementation of the muparser engine.\r
+*/\r
+\r
+namespace mu\r
+{\r
+ std::locale ParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep<char_type>('.'));\r
+\r
+ bool ParserBase::g_DbgDumpCmdCode = false;\r
+ bool ParserBase::g_DbgDumpStack = false;\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Identifiers for built in binary operators. \r
+\r
+ When defining custom binary operators with #AddOprt(...) make sure not to choose \r
+ names conflicting with these definitions. \r
+ */\r
+ const char_type* ParserBase::c_DefaultOprt[] = \r
+ { \r
+ _T("<="), _T(">="), _T("!="), \r
+ _T("=="), _T("<"), _T(">"), \r
+ _T("+"), _T("-"), _T("*"), \r
+ _T("/"), _T("^"), _T("&&"), \r
+ _T("||"), _T("="), _T("("), \r
+ _T(")"), _T("?"), _T(":"), 0 \r
+ };\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Constructor.\r
+ \param a_szFormula the formula to interpret.\r
+ \throw ParserException if a_szFormula is null.\r
+ */\r
+ ParserBase::ParserBase()\r
+ :m_pParseFormula(&ParserBase::ParseString)\r
+ ,m_vRPN()\r
+ ,m_vStringBuf()\r
+ ,m_pTokenReader()\r
+ ,m_FunDef()\r
+ ,m_PostOprtDef()\r
+ ,m_InfixOprtDef()\r
+ ,m_OprtDef()\r
+ ,m_ConstDef()\r
+ ,m_StrVarDef()\r
+ ,m_VarDef()\r
+ ,m_bBuiltInOp(true)\r
+ ,m_sNameChars()\r
+ ,m_sOprtChars()\r
+ ,m_sInfixOprtChars()\r
+ ,m_nIfElseCounter(0)\r
+ ,m_vStackBuffer()\r
+ ,m_nFinalResultIdx(0)\r
+ {\r
+ InitTokenReader();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Copy constructor. \r
+\r
+ Tha parser can be safely copy constructed but the bytecode is reset during\r
+ copy construction.\r
+ */\r
+ ParserBase::ParserBase(const ParserBase &a_Parser)\r
+ :m_pParseFormula(&ParserBase::ParseString)\r
+ ,m_vRPN()\r
+ ,m_vStringBuf()\r
+ ,m_pTokenReader()\r
+ ,m_FunDef()\r
+ ,m_PostOprtDef()\r
+ ,m_InfixOprtDef()\r
+ ,m_OprtDef()\r
+ ,m_ConstDef()\r
+ ,m_StrVarDef()\r
+ ,m_VarDef()\r
+ ,m_bBuiltInOp(true)\r
+ ,m_sNameChars()\r
+ ,m_sOprtChars()\r
+ ,m_sInfixOprtChars()\r
+ ,m_nIfElseCounter(0)\r
+ {\r
+ m_pTokenReader.reset(new token_reader_type(this));\r
+ Assign(a_Parser);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserBase::~ParserBase()\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Assignement operator. \r
+\r
+ Implemented by calling Assign(a_Parser). Self assignement is suppressed.\r
+ \param a_Parser Object to copy to this.\r
+ \return *this\r
+ \throw nothrow\r
+ */\r
+ ParserBase& ParserBase::operator=(const ParserBase &a_Parser)\r
+ {\r
+ Assign(a_Parser);\r
+ return *this;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Copy state of a parser object to this. \r
+\r
+ Clears Variables and Functions of this parser.\r
+ Copies the states of all internal variables.\r
+ Resets parse function to string parse mode.\r
+\r
+ \param a_Parser the source object.\r
+ */\r
+ void ParserBase::Assign(const ParserBase &a_Parser)\r
+ {\r
+ if (&a_Parser==this)\r
+ return;\r
+\r
+ // Don't copy bytecode instead cause the parser to create new bytecode\r
+ // by resetting the parse function.\r
+ ReInit();\r
+\r
+ m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants\r
+ m_VarDef = a_Parser.m_VarDef; // Copy user defined variables\r
+ m_bBuiltInOp = a_Parser.m_bBuiltInOp;\r
+ m_vStringBuf = a_Parser.m_vStringBuf;\r
+ m_vStackBuffer = a_Parser.m_vStackBuffer;\r
+ m_nFinalResultIdx = a_Parser.m_nFinalResultIdx;\r
+ m_StrVarDef = a_Parser.m_StrVarDef;\r
+ m_vStringVarBuf = a_Parser.m_vStringVarBuf;\r
+ m_nIfElseCounter = a_Parser.m_nIfElseCounter;\r
+ m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this));\r
+\r
+ // Copy function and operator callbacks\r
+ m_FunDef = a_Parser.m_FunDef; // Copy function definitions\r
+ m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators\r
+ m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation\r
+ m_OprtDef = a_Parser.m_OprtDef; // binary operators\r
+\r
+ m_sNameChars = a_Parser.m_sNameChars;\r
+ m_sOprtChars = a_Parser.m_sOprtChars;\r
+ m_sInfixOprtChars = a_Parser.m_sInfixOprtChars;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Set the decimal separator.\r
+ \param cDecSep Decimal separator as a character value.\r
+ \sa SetThousandsSep\r
+\r
+ By default muparser uses the "C" locale. The decimal separator of this\r
+ locale is overwritten by the one provided here.\r
+ */\r
+ void ParserBase::SetDecSep(char_type cDecSep)\r
+ {\r
+ char_type cThousandsSep = std::use_facet< change_dec_sep<char_type> >(s_locale).thousands_sep();\r
+ s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>(cDecSep, cThousandsSep));\r
+ }\r
+ \r
+ //---------------------------------------------------------------------------\r
+ /** \brief Sets the thousands operator. \r
+ \param cThousandsSep The thousands separator as a character\r
+ \sa SetDecSep\r
+\r
+ By default muparser uses the "C" locale. The thousands separator of this\r
+ locale is overwritten by the one provided here.\r
+ */\r
+ void ParserBase::SetThousandsSep(char_type cThousandsSep)\r
+ {\r
+ char_type cDecSep = std::use_facet< change_dec_sep<char_type> >(s_locale).decimal_point();\r
+ s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>(cDecSep, cThousandsSep));\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Resets the locale. \r
+\r
+ The default locale used "." as decimal separator, no thousands separator and\r
+ "," as function argument separator.\r
+ */\r
+ void ParserBase::ResetLocale()\r
+ {\r
+ s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>('.'));\r
+ SetArgSep(',');\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Initialize the token reader. \r
+\r
+ Create new token reader object and submit pointers to function, operator,\r
+ constant and variable definitions.\r
+\r
+ \post m_pTokenReader.get()!=0\r
+ \throw nothrow\r
+ */\r
+ void ParserBase::InitTokenReader()\r
+ {\r
+ m_pTokenReader.reset(new token_reader_type(this));\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Reset parser to string parsing mode and clear internal buffers.\r
+\r
+ Clear bytecode, reset the token reader.\r
+ \throw nothrow\r
+ */\r
+ void ParserBase::ReInit() const\r
+ {\r
+ m_pParseFormula = &ParserBase::ParseString;\r
+ m_vStringBuf.clear();\r
+ m_vRPN.clear();\r
+ m_pTokenReader->ReInit();\r
+ m_nIfElseCounter = 0;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserBase::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Returns the version of muparser. \r
+ \param eInfo A flag indicating whether the full version info should be \r
+ returned or not.\r
+\r
+ Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS\r
+ are returned only if eInfo==pviFULL.\r
+ */\r
+ string_type ParserBase::GetVersion(EParserVersionInfo eInfo) const\r
+ {\r
+ string_type sCompileTimeSettings;\r
+ \r
+ stringstream_type ss;\r
+\r
+ ss << MUP_VERSION;\r
+\r
+ if (eInfo==pviFULL)\r
+ {\r
+ ss << _T(" (") << MUP_VERSION_DATE;\r
+ ss << std::dec << _T("; ") << sizeof(void*)*8 << _T("BIT");\r
+\r
+#ifdef _DEBUG\r
+ ss << _T("; DEBUG");\r
+#else \r
+ ss << _T("; RELEASE");\r
+#endif\r
+\r
+#ifdef _UNICODE\r
+ ss << _T("; UNICODE");\r
+#else\r
+ #ifdef _MBCS\r
+ ss << _T("; MBCS");\r
+ #else\r
+ ss << _T("; ASCII");\r
+ #endif\r
+#endif\r
+\r
+#ifdef MUP_USE_OPENMP\r
+ ss << _T("; OPENMP");\r
+//#else\r
+// ss << _T("; NO_OPENMP");\r
+#endif\r
+\r
+#if defined(MUP_MATH_EXCEPTIONS)\r
+ ss << _T("; MATHEXC");\r
+//#else\r
+// ss << _T("; NO_MATHEXC");\r
+#endif\r
+\r
+ ss << _T(")");\r
+ }\r
+\r
+ return ss.str();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add a value parsing function. \r
+ \r
+ When parsing an expression muParser tries to detect values in the expression\r
+ string using different valident callbacks. Thuis it's possible to parse\r
+ for hex values, binary values and floating point values. \r
+ */\r
+ void ParserBase::AddValIdent(identfun_type a_pCallback)\r
+ {\r
+ m_pTokenReader->AddValIdent(a_pCallback);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Set a function that can create variable pointer for unknown expression variables. \r
+ \param a_pFactory A pointer to the variable factory.\r
+ \param pUserData A user defined context pointer.\r
+ */\r
+ void ParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData)\r
+ {\r
+ m_pTokenReader->SetVarCreator(a_pFactory, pUserData); \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add a function or operator callback to the parser. */\r
+ void ParserBase::AddCallback( const string_type &a_strName,\r
+ const ParserCallback &a_Callback, \r
+ funmap_type &a_Storage,\r
+ const char_type *a_szCharSet )\r
+ {\r
+ if (a_Callback.GetAddr()==0)\r
+ Error(ecINVALID_FUN_PTR);\r
+\r
+ const funmap_type *pFunMap = &a_Storage;\r
+\r
+ // Check for conflicting operator or function names\r
+ if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() )\r
+ Error(ecNAME_CONFLICT, -1, a_strName);\r
+\r
+ if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() )\r
+ Error(ecNAME_CONFLICT, -1, a_strName);\r
+\r
+ if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() )\r
+ Error(ecNAME_CONFLICT, -1, a_strName);\r
+\r
+ if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() )\r
+ Error(ecNAME_CONFLICT, -1, a_strName);\r
+\r
+ CheckOprt(a_strName, a_Callback, a_szCharSet);\r
+ a_Storage[a_strName] = a_Callback;\r
+ ReInit();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check if a name contains invalid characters. \r
+\r
+ \throw ParserException if the name contains invalid charakters.\r
+ */\r
+ void ParserBase::CheckOprt(const string_type &a_sName,\r
+ const ParserCallback &a_Callback,\r
+ const string_type &a_szCharSet) const\r
+ {\r
+ if ( !a_sName.length() ||\r
+ (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) ||\r
+ (a_sName[0]>='0' && a_sName[0]<='9'))\r
+ {\r
+ switch(a_Callback.GetCode())\r
+ {\r
+ case cmOPRT_POSTFIX: Error(ecINVALID_POSTFIX_IDENT, -1, a_sName);\r
+ case cmOPRT_INFIX: Error(ecINVALID_INFIX_IDENT, -1, a_sName);\r
+ default: Error(ecINVALID_NAME, -1, a_sName);\r
+ }\r
+ }\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check if a name contains invalid characters. \r
+\r
+ \throw ParserException if the name contains invalid charakters.\r
+ */\r
+ void ParserBase::CheckName(const string_type &a_sName,\r
+ const string_type &a_szCharSet) const\r
+ {\r
+ if ( !a_sName.length() ||\r
+ (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) ||\r
+ (a_sName[0]>='0' && a_sName[0]<='9'))\r
+ {\r
+ Error(ecINVALID_NAME);\r
+ }\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Set the formula. \r
+ \param a_strFormula Formula as string_type\r
+ \throw ParserException in case of syntax errors.\r
+\r
+ Triggers first time calculation thus the creation of the bytecode and\r
+ scanning of used variables.\r
+ */\r
+ void ParserBase::SetExpr(const string_type &a_sExpr)\r
+ {\r
+ // Check locale compatibility\r
+ std::locale loc;\r
+ if (m_pTokenReader->GetArgSep()==std::use_facet<numpunct<char_type> >(loc).decimal_point())\r
+ Error(ecLOCALE);\r
+\r
+ // <ibg> 20060222: Bugfix for Borland-Kylix:\r
+ // adding a space to the expression will keep Borlands KYLIX from going wild\r
+ // when calling tellg on a stringstream created from the expression after \r
+ // reading a value at the end of an expression. (mu::Parser::IsVal function)\r
+ // (tellg returns -1 otherwise causing the parser to ignore the value)\r
+ string_type sBuf(a_sExpr + _T(" ") );\r
+ m_pTokenReader->SetFormula(sBuf);\r
+ ReInit();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Get the default symbols used for the built in operators. \r
+ \sa c_DefaultOprt\r
+ */\r
+ const char_type** ParserBase::GetOprtDef() const\r
+ {\r
+ return (const char_type **)(&c_DefaultOprt[0]);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Define the set of valid characters to be used in names of\r
+ functions, variables, constants.\r
+ */\r
+ void ParserBase::DefineNameChars(const char_type *a_szCharset)\r
+ {\r
+ m_sNameChars = a_szCharset;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Define the set of valid characters to be used in names of\r
+ binary operators and postfix operators.\r
+ */\r
+ void ParserBase::DefineOprtChars(const char_type *a_szCharset)\r
+ {\r
+ m_sOprtChars = a_szCharset;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Define the set of valid characters to be used in names of\r
+ infix operators.\r
+ */\r
+ void ParserBase::DefineInfixOprtChars(const char_type *a_szCharset)\r
+ {\r
+ m_sInfixOprtChars = a_szCharset;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Virtual function that defines the characters allowed in name identifiers. \r
+ \sa #ValidOprtChars, #ValidPrefixOprtChars\r
+ */ \r
+ const char_type* ParserBase::ValidNameChars() const\r
+ {\r
+ assert(m_sNameChars.size());\r
+ return m_sNameChars.c_str();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Virtual function that defines the characters allowed in operator definitions. \r
+ \sa #ValidNameChars, #ValidPrefixOprtChars\r
+ */\r
+ const char_type* ParserBase::ValidOprtChars() const\r
+ {\r
+ assert(m_sOprtChars.size());\r
+ return m_sOprtChars.c_str();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Virtual function that defines the characters allowed in infix operator definitions.\r
+ \sa #ValidNameChars, #ValidOprtChars\r
+ */\r
+ const char_type* ParserBase::ValidInfixOprtChars() const\r
+ {\r
+ assert(m_sInfixOprtChars.size());\r
+ return m_sInfixOprtChars.c_str();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add a user defined operator. \r
+ \post Will reset the Parser to string parsing mode.\r
+ */\r
+ void ParserBase::DefinePostfixOprt(const string_type &a_sName, \r
+ fun_type1 a_pFun,\r
+ bool a_bAllowOpt)\r
+ {\r
+ AddCallback(a_sName, \r
+ ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX),\r
+ m_PostOprtDef, \r
+ ValidOprtChars() );\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Initialize user defined functions. \r
+ \r
+ Calls the virtual functions InitFun(), InitConst() and InitOprt().\r
+ */\r
+ void ParserBase::Init()\r
+ {\r
+ InitCharSets();\r
+ InitFun();\r
+ InitConst();\r
+ InitOprt();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add a user defined operator. \r
+ \post Will reset the Parser to string parsing mode.\r
+ \param [in] a_sName operator Identifier \r
+ \param [in] a_pFun Operator callback function\r
+ \param [in] a_iPrec Operator Precedence (default=prSIGN)\r
+ \param [in] a_bAllowOpt True if operator is volatile (default=false)\r
+ \sa EPrec\r
+ */\r
+ void ParserBase::DefineInfixOprt(const string_type &a_sName, \r
+ fun_type1 a_pFun, \r
+ int a_iPrec, \r
+ bool a_bAllowOpt)\r
+ {\r
+ AddCallback(a_sName, \r
+ ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), \r
+ m_InfixOprtDef, \r
+ ValidInfixOprtChars() );\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Define a binary operator. \r
+ \param [in] a_sName The identifier of the operator.\r
+ \param [in] a_pFun Pointer to the callback function.\r
+ \param [in] a_iPrec Precedence of the operator.\r
+ \param [in] a_eAssociativity The associativity of the operator.\r
+ \param [in] a_bAllowOpt If this is true the operator may be optimized away.\r
+ \r
+ Adds a new Binary operator the the parser instance. \r
+ */\r
+ void ParserBase::DefineOprt( const string_type &a_sName, \r
+ fun_type2 a_pFun, \r
+ unsigned a_iPrec, \r
+ EOprtAssociativity a_eAssociativity,\r
+ bool a_bAllowOpt )\r
+ {\r
+ // Check for conflicts with built in operator names\r
+ for (int i=0; m_bBuiltInOp && i<cmENDIF; ++i)\r
+ if (a_sName == string_type(c_DefaultOprt[i]))\r
+ Error(ecBUILTIN_OVERLOAD, -1, a_sName);\r
+\r
+ AddCallback(a_sName, \r
+ ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, a_eAssociativity), \r
+ m_OprtDef, \r
+ ValidOprtChars() );\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Define a new string constant.\r
+ \param [in] a_strName The name of the constant.\r
+ \param [in] a_strVal the value of the constant. \r
+ */\r
+ void ParserBase::DefineStrConst(const string_type &a_strName, const string_type &a_strVal)\r
+ {\r
+ // Test if a constant with that names already exists\r
+ if (m_StrVarDef.find(a_strName)!=m_StrVarDef.end())\r
+ Error(ecNAME_CONFLICT);\r
+\r
+ CheckName(a_strName, ValidNameChars());\r
+ \r
+ m_vStringVarBuf.push_back(a_strVal); // Store variable string in internal buffer\r
+ m_StrVarDef[a_strName] = m_vStringBuf.size(); // bind buffer index to variable name\r
+\r
+ ReInit();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add a user defined variable. \r
+ \param [in] a_sName the variable name\r
+ \param [in] a_pVar A pointer to the variable vaule.\r
+ \post Will reset the Parser to string parsing mode.\r
+ \throw ParserException in case the name contains invalid signs or a_pVar is NULL.\r
+ */\r
+ void ParserBase::DefineVar(const string_type &a_sName, value_type *a_pVar)\r
+ {\r
+ if (a_pVar==0)\r
+ Error(ecINVALID_VAR_PTR);\r
+\r
+ // Test if a constant with that names already exists\r
+ if (m_ConstDef.find(a_sName)!=m_ConstDef.end())\r
+ Error(ecNAME_CONFLICT);\r
+\r
+ CheckName(a_sName, ValidNameChars());\r
+ m_VarDef[a_sName] = a_pVar;\r
+ ReInit();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add a user defined constant. \r
+ \param [in] a_sName The name of the constant.\r
+ \param [in] a_fVal the value of the constant.\r
+ \post Will reset the Parser to string parsing mode.\r
+ \throw ParserException in case the name contains invalid signs.\r
+ */\r
+ void ParserBase::DefineConst(const string_type &a_sName, value_type a_fVal)\r
+ {\r
+ CheckName(a_sName, ValidNameChars());\r
+ m_ConstDef[a_sName] = a_fVal;\r
+ ReInit();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Get operator priority.\r
+ \throw ParserException if a_Oprt is no operator code\r
+ */\r
+ int ParserBase::GetOprtPrecedence(const token_type &a_Tok) const\r
+ {\r
+ switch (a_Tok.GetCode())\r
+ {\r
+ // built in operators\r
+ case cmEND: return -5;\r
+ case cmARG_SEP: return -4;\r
+ case cmASSIGN: return -1; \r
+ case cmELSE:\r
+ case cmIF: return 0;\r
+ case cmLAND: return prLAND;\r
+ case cmLOR: return prLOR;\r
+ case cmLT:\r
+ case cmGT:\r
+ case cmLE:\r
+ case cmGE:\r
+ case cmNEQ:\r
+ case cmEQ: return prCMP; \r
+ case cmADD:\r
+ case cmSUB: return prADD_SUB;\r
+ case cmMUL:\r
+ case cmDIV: return prMUL_DIV;\r
+ case cmPOW: return prPOW;\r
+\r
+ // user defined binary operators\r
+ case cmOPRT_INFIX: \r
+ case cmOPRT_BIN: return a_Tok.GetPri();\r
+ default: Error(ecINTERNAL_ERROR, 5);\r
+ return 999;\r
+ } \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Get operator priority.\r
+ \throw ParserException if a_Oprt is no operator code\r
+ */\r
+ EOprtAssociativity ParserBase::GetOprtAssociativity(const token_type &a_Tok) const\r
+ {\r
+ switch (a_Tok.GetCode())\r
+ {\r
+ case cmASSIGN:\r
+ case cmLAND:\r
+ case cmLOR:\r
+ case cmLT:\r
+ case cmGT:\r
+ case cmLE:\r
+ case cmGE:\r
+ case cmNEQ:\r
+ case cmEQ: \r
+ case cmADD:\r
+ case cmSUB:\r
+ case cmMUL:\r
+ case cmDIV: return oaLEFT;\r
+ case cmPOW: return oaRIGHT;\r
+ case cmOPRT_BIN: return a_Tok.GetAssociativity();\r
+ default: return oaNONE;\r
+ } \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return a map containing the used variables only. */\r
+ const varmap_type& ParserBase::GetUsedVar() const\r
+ {\r
+ try\r
+ {\r
+ m_pTokenReader->IgnoreUndefVar(true);\r
+ CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it\r
+ // may contain references to nonexisting variables.\r
+ m_pParseFormula = &ParserBase::ParseString;\r
+ m_pTokenReader->IgnoreUndefVar(false);\r
+ }\r
+ catch(exception_type &e)\r
+ {\r
+ // Make sure to stay in string parse mode, dont call ReInit()\r
+ // because it deletes the array with the used variables\r
+ m_pParseFormula = &ParserBase::ParseString;\r
+ m_pTokenReader->IgnoreUndefVar(false);\r
+ throw e;\r
+ }\r
+ \r
+ return m_pTokenReader->GetUsedVar();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return a map containing the used variables only. */\r
+ const varmap_type& ParserBase::GetVar() const\r
+ {\r
+ return m_VarDef;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return a map containing all parser constants. */\r
+ const valmap_type& ParserBase::GetConst() const\r
+ {\r
+ return m_ConstDef;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return prototypes of all parser functions.\r
+ \return #m_FunDef\r
+ \sa FunProt\r
+ \throw nothrow\r
+ \r
+ The return type is a map of the public type #funmap_type containing the prototype\r
+ definitions for all numerical parser functions. String functions are not part of \r
+ this map. The Prototype definition is encapsulated in objects of the class FunProt\r
+ one per parser function each associated with function names via a map construct.\r
+ */\r
+ const funmap_type& ParserBase::GetFunDef() const\r
+ {\r
+ return m_FunDef;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Retrieve the formula. */\r
+ const string_type& ParserBase::GetExpr() const\r
+ {\r
+ return m_pTokenReader->GetExpr();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Execute a function that takes a single string argument.\r
+ \param a_FunTok Function token.\r
+ \throw exception_type If the function token is not a string function\r
+ */\r
+ ParserBase::token_type ParserBase::ApplyStrFunc(const token_type &a_FunTok,\r
+ const std::vector<token_type> &a_vArg) const\r
+ {\r
+ if (a_vArg.back().GetCode()!=cmSTRING)\r
+ Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());\r
+\r
+ token_type valTok;\r
+ generic_fun_type pFunc = a_FunTok.GetFuncAddr();\r
+ assert(pFunc);\r
+\r
+ try\r
+ {\r
+ // Check function arguments; write dummy value into valtok to represent the result\r
+ switch(a_FunTok.GetArgCount())\r
+ {\r
+ case 0: valTok.SetVal(1); a_vArg[0].GetAsString(); break;\r
+ case 1: valTok.SetVal(1); a_vArg[1].GetAsString(); a_vArg[0].GetVal(); break;\r
+ case 2: valTok.SetVal(1); a_vArg[2].GetAsString(); a_vArg[1].GetVal(); a_vArg[0].GetVal(); break;\r
+ default: Error(ecINTERNAL_ERROR);\r
+ }\r
+ }\r
+ catch(ParserError& )\r
+ {\r
+ Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());\r
+ }\r
+\r
+ // string functions won't be optimized\r
+ m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx());\r
+ \r
+ // Push dummy value representing the function result to the stack\r
+ return valTok;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Apply a function token. \r
+ \param iArgCount Number of Arguments actually gathered used only for multiarg functions.\r
+ \post The result is pushed to the value stack\r
+ \post The function token is removed from the stack\r
+ \throw exception_type if Argument count does not mach function requirements.\r
+ */\r
+ void ParserBase::ApplyFunc( ParserStack<token_type> &a_stOpt,\r
+ ParserStack<token_type> &a_stVal, \r
+ int a_iArgCount) const\r
+ { \r
+ assert(m_pTokenReader.get());\r
+\r
+ // Operator stack empty or does not contain tokens with callback functions\r
+ if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==0 )\r
+ return;\r
+\r
+ token_type funTok = a_stOpt.pop();\r
+ assert(funTok.GetFuncAddr());\r
+\r
+ // Binary operators must rely on their internal operator number\r
+ // since counting of operators relies on commas for function arguments\r
+ // binary operators do not have commas in their expression\r
+ int iArgCount = (funTok.GetCode()==cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount;\r
+\r
+ // determine how many parameters the function needs. To remember iArgCount includes the \r
+ // string parameter whilst GetArgCount() counts only numeric parameters.\r
+ int iArgRequired = funTok.GetArgCount() + ((funTok.GetType()==tpSTR) ? 1 : 0);\r
+\r
+ // Thats the number of numerical parameters\r
+ int iArgNumerical = iArgCount - ((funTok.GetType()==tpSTR) ? 1 : 0);\r
+\r
+ if (funTok.GetCode()==cmFUNC_STR && iArgCount-iArgNumerical>1)\r
+ Error(ecINTERNAL_ERROR);\r
+\r
+ if (funTok.GetArgCount()>=0 && iArgCount>iArgRequired) \r
+ Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());\r
+\r
+ if (funTok.GetCode()!=cmOPRT_BIN && iArgCount<iArgRequired )\r
+ Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());\r
+\r
+ if (funTok.GetCode()==cmFUNC_STR && iArgCount>iArgRequired )\r
+ Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());\r
+\r
+ // Collect the numeric function arguments from the value stack and store them\r
+ // in a vector\r
+ std::vector<token_type> stArg; \r
+ for (int i=0; i<iArgNumerical; ++i)\r
+ {\r
+ stArg.push_back( a_stVal.pop() );\r
+ if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR )\r
+ Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());\r
+ }\r
+\r
+ switch(funTok.GetCode())\r
+ {\r
+ case cmFUNC_STR: \r
+ stArg.push_back(a_stVal.pop());\r
+ \r
+ if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR )\r
+ Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());\r
+\r
+ ApplyStrFunc(funTok, stArg); \r
+ break;\r
+\r
+ case cmFUNC_BULK: \r
+ m_vRPN.AddBulkFun(funTok.GetFuncAddr(), (int)stArg.size()); \r
+ break;\r
+\r
+ case cmOPRT_BIN:\r
+ case cmOPRT_POSTFIX:\r
+ case cmOPRT_INFIX:\r
+ case cmFUNC:\r
+ if (funTok.GetArgCount()==-1 && iArgCount==0)\r
+ Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString());\r
+\r
+ m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount()==-1) ? -iArgNumerical : iArgNumerical);\r
+ break;\r
+ }\r
+\r
+ // Push dummy value representing the function result to the stack\r
+ token_type token;\r
+ token.SetVal(1); \r
+ a_stVal.push(token);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserBase::ApplyIfElse(ParserStack<token_type> &a_stOpt,\r
+ ParserStack<token_type> &a_stVal) const\r
+ {\r
+ // Check if there is an if Else clause to be calculated\r
+ while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE)\r
+ {\r
+ token_type opElse = a_stOpt.pop();\r
+ MUP_ASSERT(a_stOpt.size()>0);\r
+\r
+ // Take the value associated with the else branch from the value stack\r
+ token_type vVal2 = a_stVal.pop();\r
+\r
+ MUP_ASSERT(a_stOpt.size()>0);\r
+ MUP_ASSERT(a_stVal.size()>=2);\r
+\r
+ // it then else is a ternary operator Pop all three values from the value s\r
+ // tack and just return the right value\r
+ token_type vVal1 = a_stVal.pop();\r
+ token_type vExpr = a_stVal.pop();\r
+\r
+ a_stVal.push( (vExpr.GetVal()!=0) ? vVal1 : vVal2);\r
+\r
+ token_type opIf = a_stOpt.pop();\r
+ MUP_ASSERT(opElse.GetCode()==cmELSE);\r
+ MUP_ASSERT(opIf.GetCode()==cmIF);\r
+\r
+ m_vRPN.AddIfElse(cmENDIF);\r
+ } // while pending if-else-clause found\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Performs the necessary steps to write code for\r
+ the execution of binary operators into the bytecode. \r
+ */\r
+ void ParserBase::ApplyBinOprt(ParserStack<token_type> &a_stOpt,\r
+ ParserStack<token_type> &a_stVal) const\r
+ {\r
+ // is it a user defined binary operator?\r
+ if (a_stOpt.top().GetCode()==cmOPRT_BIN)\r
+ {\r
+ ApplyFunc(a_stOpt, a_stVal, 2);\r
+ }\r
+ else\r
+ {\r
+ MUP_ASSERT(a_stVal.size()>=2);\r
+ token_type valTok1 = a_stVal.pop(),\r
+ valTok2 = a_stVal.pop(),\r
+ optTok = a_stOpt.pop(),\r
+ resTok; \r
+\r
+ if ( valTok1.GetType()!=valTok2.GetType() || \r
+ (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) )\r
+ Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString());\r
+\r
+ if (optTok.GetCode()==cmASSIGN)\r
+ {\r
+ if (valTok2.GetCode()!=cmVAR)\r
+ Error(ecUNEXPECTED_OPERATOR, -1, _T("="));\r
+ \r
+ m_vRPN.AddAssignOp(valTok2.GetVar());\r
+ }\r
+ else\r
+ m_vRPN.AddOp(optTok.GetCode());\r
+\r
+ resTok.SetVal(1);\r
+ a_stVal.push(resTok);\r
+ }\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Apply a binary operator. \r
+ \param a_stOpt The operator stack\r
+ \param a_stVal The value stack\r
+ */\r
+ void ParserBase::ApplyRemainingOprt(ParserStack<token_type> &stOpt,\r
+ ParserStack<token_type> &stVal) const\r
+ {\r
+ while (stOpt.size() && \r
+ stOpt.top().GetCode() != cmBO &&\r
+ stOpt.top().GetCode() != cmIF)\r
+ {\r
+ token_type tok = stOpt.top();\r
+ switch (tok.GetCode())\r
+ {\r
+ case cmOPRT_INFIX:\r
+ case cmOPRT_BIN:\r
+ case cmLE:\r
+ case cmGE:\r
+ case cmNEQ:\r
+ case cmEQ:\r
+ case cmLT:\r
+ case cmGT:\r
+ case cmADD:\r
+ case cmSUB:\r
+ case cmMUL:\r
+ case cmDIV:\r
+ case cmPOW:\r
+ case cmLAND:\r
+ case cmLOR:\r
+ case cmASSIGN:\r
+ if (stOpt.top().GetCode()==cmOPRT_INFIX)\r
+ ApplyFunc(stOpt, stVal, 1);\r
+ else\r
+ ApplyBinOprt(stOpt, stVal);\r
+ break;\r
+\r
+ case cmELSE:\r
+ ApplyIfElse(stOpt, stVal);\r
+ break;\r
+\r
+ default:\r
+ Error(ecINTERNAL_ERROR);\r
+ }\r
+ }\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Parse the command code.\r
+ \sa ParseString(...)\r
+\r
+ Command code contains precalculated stack positions of the values and the\r
+ associated operators. The Stack is filled beginning from index one the \r
+ value at index zero is not used at all.\r
+ */\r
+ value_type ParserBase::ParseCmdCode() const\r
+ {\r
+ return ParseCmdCodeBulk(0, 0);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Evaluate the RPN. \r
+ \param nOffset The offset added to variable addresses (for bulk mode)\r
+ \param nThreadID OpenMP Thread id of the calling thread\r
+ */\r
+ value_type ParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const\r
+ {\r
+ assert(nThreadID<=s_MaxNumOpenMPThreads);\r
+\r
+ // Note: The check for nOffset==0 and nThreadID here is not necessary but \r
+ // brings a minor performance gain when not in bulk mode.\r
+ value_type *Stack = ((nOffset==0) && (nThreadID==0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID * (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)];\r
+ value_type buf;\r
+ int sidx(0);\r
+ for (const SToken *pTok = m_vRPN.GetBase(); pTok->Cmd!=cmEND ; ++pTok)\r
+ {\r
+ switch (pTok->Cmd)\r
+ {\r
+ // built in binary operators\r
+ case cmLE: --sidx; Stack[sidx] = Stack[sidx] <= Stack[sidx+1]; continue;\r
+ case cmGE: --sidx; Stack[sidx] = Stack[sidx] >= Stack[sidx+1]; continue;\r
+ case cmNEQ: --sidx; Stack[sidx] = Stack[sidx] != Stack[sidx+1]; continue;\r
+ case cmEQ: --sidx; Stack[sidx] = Stack[sidx] == Stack[sidx+1]; continue;\r
+ case cmLT: --sidx; Stack[sidx] = Stack[sidx] < Stack[sidx+1]; continue;\r
+ case cmGT: --sidx; Stack[sidx] = Stack[sidx] > Stack[sidx+1]; continue;\r
+ case cmADD: --sidx; Stack[sidx] += Stack[1+sidx]; continue;\r
+ case cmSUB: --sidx; Stack[sidx] -= Stack[1+sidx]; continue;\r
+ case cmMUL: --sidx; Stack[sidx] *= Stack[1+sidx]; continue;\r
+ case cmDIV: --sidx;\r
+\r
+ #if defined(MUP_MATH_EXCEPTIONS)\r
+ if (Stack[1+sidx]==0)\r
+ Error(ecDIV_BY_ZERO);\r
+ #endif\r
+ Stack[sidx] /= Stack[1+sidx]; \r
+ continue;\r
+\r
+ case cmPOW: \r
+ --sidx; Stack[sidx] = MathImpl<value_type>::Pow(Stack[sidx], Stack[1+sidx]);\r
+ continue;\r
+\r
+ case cmLAND: --sidx; Stack[sidx] = Stack[sidx] && Stack[sidx+1]; continue;\r
+ case cmLOR: --sidx; Stack[sidx] = Stack[sidx] || Stack[sidx+1]; continue;\r
+\r
+ case cmASSIGN: \r
+ --sidx; Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; continue;\r
+\r
+ //case cmBO: // unused, listed for compiler optimization purposes\r
+ //case cmBC:\r
+ // MUP_FAIL(INVALID_CODE_IN_BYTECODE);\r
+ // continue;\r
+\r
+ case cmIF:\r
+ if (Stack[sidx--]==0)\r
+ pTok += pTok->Oprt.offset;\r
+ continue;\r
+\r
+ case cmELSE:\r
+ pTok += pTok->Oprt.offset;\r
+ continue;\r
+\r
+ case cmENDIF:\r
+ continue;\r
+\r
+ //case cmARG_SEP:\r
+ // MUP_FAIL(INVALID_CODE_IN_BYTECODE);\r
+ // continue;\r
+\r
+ // value and variable tokens\r
+ case cmVAR: Stack[++sidx] = *(pTok->Val.ptr + nOffset); continue;\r
+ case cmVAL: Stack[++sidx] = pTok->Val.data2; continue;\r
+ \r
+ case cmVARPOW2: buf = *(pTok->Val.ptr + nOffset);\r
+ Stack[++sidx] = buf*buf;\r
+ continue;\r
+\r
+ case cmVARPOW3: buf = *(pTok->Val.ptr + nOffset);\r
+ Stack[++sidx] = buf*buf*buf;\r
+ continue;\r
+\r
+ case cmVARPOW4: buf = *(pTok->Val.ptr + nOffset);\r
+ Stack[++sidx] = buf*buf*buf*buf;\r
+ continue;\r
+ \r
+ case cmVARMUL: Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2;\r
+ continue;\r
+\r
+ // Next is treatment of numeric functions\r
+ case cmFUNC:\r
+ {\r
+ int iArgCount = pTok->Fun.argc;\r
+\r
+ // switch according to argument count\r
+ switch(iArgCount) \r
+ {\r
+ case 0: sidx += 1; Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)(); continue;\r
+ case 1: Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]); continue;\r
+ case 2: sidx -= 1; Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1]); continue;\r
+ case 3: sidx -= 2; Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue;\r
+ case 4: sidx -= 3; Stack[sidx] = (*(fun_type4)pTok->Fun.ptr)(Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue;\r
+ 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;\r
+ 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;\r
+ 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;\r
+ 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;\r
+ 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;\r
+ 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;\r
+ default:\r
+ if (iArgCount>0) // function with variable arguments store the number as a negative value\r
+ Error(ecINTERNAL_ERROR, 1);\r
+\r
+ sidx -= -iArgCount - 1;\r
+ Stack[sidx] =(*(multfun_type)pTok->Fun.ptr)(&Stack[sidx], -iArgCount);\r
+ continue;\r
+ }\r
+ }\r
+\r
+ // Next is treatment of string functions\r
+ case cmFUNC_STR:\r
+ {\r
+ sidx -= pTok->Fun.argc -1;\r
+\r
+ // The index of the string argument in the string table\r
+ int iIdxStack = pTok->Fun.idx; \r
+ MUP_ASSERT( iIdxStack>=0 && iIdxStack<(int)m_vStringBuf.size() );\r
+\r
+ switch(pTok->Fun.argc) // switch according to argument count\r
+ {\r
+ case 0: Stack[sidx] = (*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str()); continue;\r
+ case 1: Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx]); continue;\r
+ case 2: Stack[sidx] = (*(strfun_type3)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx+1]); continue;\r
+ }\r
+\r
+ continue;\r
+ }\r
+\r
+ case cmFUNC_BULK:\r
+ {\r
+ int iArgCount = pTok->Fun.argc;\r
+\r
+ // switch according to argument count\r
+ switch(iArgCount) \r
+ {\r
+ case 0: sidx += 1; Stack[sidx] = (*(bulkfun_type0 )pTok->Fun.ptr)(nOffset, nThreadID); continue;\r
+ case 1: Stack[sidx] = (*(bulkfun_type1 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx]); continue;\r
+ case 2: sidx -= 1; Stack[sidx] = (*(bulkfun_type2 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1]); continue;\r
+ case 3: sidx -= 2; Stack[sidx] = (*(bulkfun_type3 )pTok->Fun.ptr)(nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue;\r
+ 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;\r
+ 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;\r
+ 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;\r
+ 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;\r
+ 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;\r
+ 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;\r
+ 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;\r
+ default:\r
+ Error(ecINTERNAL_ERROR, 2);\r
+ continue;\r
+ }\r
+ }\r
+\r
+ //case cmSTRING:\r
+ //case cmOPRT_BIN:\r
+ //case cmOPRT_POSTFIX:\r
+ //case cmOPRT_INFIX:\r
+ // MUP_FAIL(INVALID_CODE_IN_BYTECODE);\r
+ // continue;\r
+\r
+ //case cmEND:\r
+ // return Stack[m_nFinalResultIdx]; \r
+\r
+ default:\r
+ Error(ecINTERNAL_ERROR, 3);\r
+ return 0;\r
+ } // switch CmdCode\r
+ } // for all bytecode tokens\r
+\r
+ return Stack[m_nFinalResultIdx]; \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserBase::CreateRPN() const\r
+ {\r
+ if (!m_pTokenReader->GetExpr().length())\r
+ Error(ecUNEXPECTED_EOF, 0);\r
+\r
+ ParserStack<token_type> stOpt, stVal;\r
+ ParserStack<int> stArgCount;\r
+ token_type opta, opt; // for storing operators\r
+ token_type val, tval; // for storing value\r
+ string_type strBuf; // buffer for string function arguments\r
+\r
+ ReInit();\r
+ \r
+ // The outermost counter counts the number of seperated items\r
+ // such as in "a=10,b=20,c=c+a"\r
+ stArgCount.push(1);\r
+ \r
+ for(;;)\r
+ {\r
+ opt = m_pTokenReader->ReadNextToken();\r
+\r
+ switch (opt.GetCode())\r
+ {\r
+ //\r
+ // Next three are different kind of value entries\r
+ //\r
+ case cmSTRING:\r
+ opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token \r
+ stVal.push(opt);\r
+ m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer\r
+ break;\r
+ \r
+ case cmVAR:\r
+ stVal.push(opt);\r
+ m_vRPN.AddVar( static_cast<value_type*>(opt.GetVar()) );\r
+ break;\r
+\r
+ case cmVAL:\r
+ stVal.push(opt);\r
+ m_vRPN.AddVal( opt.GetVal() );\r
+ break;\r
+\r
+ case cmELSE:\r
+ m_nIfElseCounter--;\r
+ if (m_nIfElseCounter<0)\r
+ Error(ecMISPLACED_COLON, m_pTokenReader->GetPos());\r
+\r
+ ApplyRemainingOprt(stOpt, stVal);\r
+ m_vRPN.AddIfElse(cmELSE);\r
+ stOpt.push(opt);\r
+ break;\r
+\r
+\r
+ case cmARG_SEP:\r
+ if (stArgCount.empty())\r
+ Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos());\r
+\r
+ ++stArgCount.top();\r
+ // fallthrough intentional (no break!)\r
+\r
+ case cmEND:\r
+ ApplyRemainingOprt(stOpt, stVal);\r
+ break;\r
+\r
+ case cmBC:\r
+ {\r
+ // The argument count for parameterless functions is zero\r
+ // by default an opening bracket sets parameter count to 1\r
+ // in preparation of arguments to come. If the last token\r
+ // was an opening bracket we know better...\r
+ if (opta.GetCode()==cmBO)\r
+ --stArgCount.top();\r
+ \r
+ ApplyRemainingOprt(stOpt, stVal);\r
+\r
+ // Check if the bracket content has been evaluated completely\r
+ if (stOpt.size() && stOpt.top().GetCode()==cmBO)\r
+ {\r
+ // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check\r
+ // if there is either a function or a sign pending\r
+ // neither the opening nor the closing bracket will be pushed back to\r
+ // the operator stack\r
+ // Check if a function is standing in front of the opening bracket, \r
+ // if yes evaluate it afterwards check for infix operators\r
+ assert(stArgCount.size());\r
+ int iArgCount = stArgCount.pop();\r
+ \r
+ stOpt.pop(); // Take opening bracket from stack\r
+\r
+ if (iArgCount>1 && ( stOpt.size()==0 || \r
+ (stOpt.top().GetCode()!=cmFUNC && \r
+ stOpt.top().GetCode()!=cmFUNC_BULK && \r
+ stOpt.top().GetCode()!=cmFUNC_STR) ) )\r
+ Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos());\r
+ \r
+ // The opening bracket was popped from the stack now check if there\r
+ // was a function before this bracket\r
+ if (stOpt.size() && \r
+ stOpt.top().GetCode()!=cmOPRT_INFIX && \r
+ stOpt.top().GetCode()!=cmOPRT_BIN && \r
+ stOpt.top().GetFuncAddr()!=0)\r
+ {\r
+ ApplyFunc(stOpt, stVal, iArgCount);\r
+ }\r
+ }\r
+ } // if bracket content is evaluated\r
+ break;\r
+\r
+ //\r
+ // Next are the binary operator entries\r
+ //\r
+ //case cmAND: // built in binary operators\r
+ //case cmOR:\r
+ //case cmXOR:\r
+ case cmIF:\r
+ m_nIfElseCounter++;\r
+ // fallthrough intentional (no break!)\r
+\r
+ case cmLAND:\r
+ case cmLOR:\r
+ case cmLT:\r
+ case cmGT:\r
+ case cmLE:\r
+ case cmGE:\r
+ case cmNEQ:\r
+ case cmEQ:\r
+ case cmADD:\r
+ case cmSUB:\r
+ case cmMUL:\r
+ case cmDIV:\r
+ case cmPOW:\r
+ case cmASSIGN:\r
+ case cmOPRT_BIN:\r
+\r
+ // A binary operator (user defined or built in) has been found. \r
+ while ( stOpt.size() && \r
+ stOpt.top().GetCode() != cmBO &&\r
+ stOpt.top().GetCode() != cmELSE &&\r
+ stOpt.top().GetCode() != cmIF)\r
+ {\r
+ int nPrec1 = GetOprtPrecedence(stOpt.top()),\r
+ nPrec2 = GetOprtPrecedence(opt);\r
+\r
+ if (stOpt.top().GetCode()==opt.GetCode())\r
+ {\r
+\r
+ // Deal with operator associativity\r
+ EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt);\r
+ if ( (eOprtAsct==oaRIGHT && (nPrec1 <= nPrec2)) || \r
+ (eOprtAsct==oaLEFT && (nPrec1 < nPrec2)) )\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ else if (nPrec1 < nPrec2)\r
+ {\r
+ // In case the operators are not equal the precedence decides alone...\r
+ break;\r
+ }\r
+ \r
+ if (stOpt.top().GetCode()==cmOPRT_INFIX)\r
+ ApplyFunc(stOpt, stVal, 1);\r
+ else\r
+ ApplyBinOprt(stOpt, stVal);\r
+ } // while ( ... )\r
+\r
+ if (opt.GetCode()==cmIF)\r
+ m_vRPN.AddIfElse(opt.GetCode());\r
+\r
+ // The operator can't be evaluated right now, push back to the operator stack\r
+ stOpt.push(opt);\r
+ break;\r
+\r
+ //\r
+ // Last section contains functions and operators implicitely mapped to functions\r
+ //\r
+ case cmBO:\r
+ stArgCount.push(1);\r
+ stOpt.push(opt);\r
+ break;\r
+\r
+ case cmOPRT_INFIX:\r
+ case cmFUNC:\r
+ case cmFUNC_BULK:\r
+ case cmFUNC_STR: \r
+ stOpt.push(opt);\r
+ break;\r
+\r
+ case cmOPRT_POSTFIX:\r
+ stOpt.push(opt);\r
+ ApplyFunc(stOpt, stVal, 1); // this is the postfix operator\r
+ break;\r
+\r
+ default: Error(ecINTERNAL_ERROR, 3);\r
+ } // end of switch operator-token\r
+\r
+ opta = opt;\r
+\r
+ if ( opt.GetCode() == cmEND )\r
+ {\r
+ m_vRPN.Finalize();\r
+ break;\r
+ }\r
+\r
+ if (ParserBase::g_DbgDumpStack)\r
+ {\r
+ StackDump(stVal, stOpt);\r
+ m_vRPN.AsciiDump();\r
+ }\r
+ } // while (true)\r
+\r
+ if (ParserBase::g_DbgDumpCmdCode)\r
+ m_vRPN.AsciiDump();\r
+\r
+ if (m_nIfElseCounter>0)\r
+ Error(ecMISSING_ELSE_CLAUSE);\r
+\r
+ // get the last value (= final result) from the stack\r
+ MUP_ASSERT(stArgCount.size()==1);\r
+ m_nFinalResultIdx = stArgCount.top();\r
+ if (m_nFinalResultIdx==0)\r
+ Error(ecINTERNAL_ERROR, 9);\r
+\r
+ if (stVal.size()==0)\r
+ Error(ecEMPTY_EXPRESSION);\r
+\r
+ if (stVal.top().GetType()!=tpDBL)\r
+ Error(ecSTR_RESULT);\r
+\r
+ m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief One of the two main parse functions.\r
+ \sa ParseCmdCode(...)\r
+\r
+ Parse expression from input string. Perform syntax checking and create \r
+ bytecode. After parsing the string and creating the bytecode the function \r
+ pointer #m_pParseFormula will be changed to the second parse routine the \r
+ uses bytecode instead of string parsing.\r
+ */\r
+ value_type ParserBase::ParseString() const\r
+ {\r
+ try\r
+ {\r
+ CreateRPN();\r
+ m_pParseFormula = &ParserBase::ParseCmdCode;\r
+ return (this->*m_pParseFormula)(); \r
+ }\r
+ catch(ParserError &exc)\r
+ {\r
+ exc.SetFormula(m_pTokenReader->GetExpr());\r
+ throw;\r
+ }\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Create an error containing the parse error position.\r
+\r
+ This function will create an Parser Exception object containing the error text and\r
+ its position.\r
+\r
+ \param a_iErrc [in] The error code of type #EErrorCodes.\r
+ \param a_iPos [in] The position where the error was detected.\r
+ \param a_strTok [in] The token string representation associated with the error.\r
+ \throw ParserException always throws thats the only purpose of this function.\r
+ */\r
+ void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const\r
+ {\r
+ throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos);\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Clear all user defined variables.\r
+ \throw nothrow\r
+\r
+ Resets the parser to string parsing mode by calling #ReInit.\r
+ */\r
+ void ParserBase::ClearVar()\r
+ {\r
+ m_VarDef.clear();\r
+ ReInit();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Remove a variable from internal storage.\r
+ \throw nothrow\r
+\r
+ Removes a variable if it exists. If the Variable does not exist nothing will be done.\r
+ */\r
+ void ParserBase::RemoveVar(const string_type &a_strVarName)\r
+ {\r
+ varmap_type::iterator item = m_VarDef.find(a_strVarName);\r
+ if (item!=m_VarDef.end())\r
+ {\r
+ m_VarDef.erase(item);\r
+ ReInit();\r
+ }\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Clear all functions.\r
+ \post Resets the parser to string parsing mode.\r
+ \throw nothrow\r
+ */\r
+ void ParserBase::ClearFun()\r
+ {\r
+ m_FunDef.clear();\r
+ ReInit();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Clear all user defined constants.\r
+\r
+ Both numeric and string constants will be removed from the internal storage.\r
+ \post Resets the parser to string parsing mode.\r
+ \throw nothrow\r
+ */\r
+ void ParserBase::ClearConst()\r
+ {\r
+ m_ConstDef.clear();\r
+ m_StrVarDef.clear();\r
+ ReInit();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Clear all user defined postfix operators.\r
+ \post Resets the parser to string parsing mode.\r
+ \throw nothrow\r
+ */\r
+ void ParserBase::ClearPostfixOprt()\r
+ {\r
+ m_PostOprtDef.clear();\r
+ ReInit();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Clear all user defined binary operators.\r
+ \post Resets the parser to string parsing mode.\r
+ \throw nothrow\r
+ */\r
+ void ParserBase::ClearOprt()\r
+ {\r
+ m_OprtDef.clear();\r
+ ReInit();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Clear the user defined Prefix operators. \r
+ \post Resets the parser to string parser mode.\r
+ \throw nothrow\r
+ */\r
+ void ParserBase::ClearInfixOprt()\r
+ {\r
+ m_InfixOprtDef.clear();\r
+ ReInit();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Enable or disable the formula optimization feature. \r
+ \post Resets the parser to string parser mode.\r
+ \throw nothrow\r
+ */\r
+ void ParserBase::EnableOptimizer(bool a_bIsOn)\r
+ {\r
+ m_vRPN.EnableOptimizer(a_bIsOn);\r
+ ReInit();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Enable the dumping of bytecode amd stack content on the console. \r
+ \param bDumpCmd Flag to enable dumping of the current bytecode to the console.\r
+ \param bDumpStack Flag to enable dumping of the stack content is written to the console.\r
+\r
+ This function is for debug purposes only!\r
+ */\r
+ void ParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack)\r
+ {\r
+ ParserBase::g_DbgDumpCmdCode = bDumpCmd;\r
+ ParserBase::g_DbgDumpStack = bDumpStack;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Enable or disable the built in binary operators.\r
+ \throw nothrow\r
+ \sa m_bBuiltInOp, ReInit()\r
+\r
+ If you disable the built in binary operators there will be no binary operators\r
+ defined. Thus you must add them manually one by one. It is not possible to\r
+ disable built in operators selectively. This function will Reinitialize the\r
+ parser by calling ReInit().\r
+ */\r
+ void ParserBase::EnableBuiltInOprt(bool a_bIsOn)\r
+ {\r
+ m_bBuiltInOp = a_bIsOn;\r
+ ReInit();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Query status of built in variables.\r
+ \return #m_bBuiltInOp; true if built in operators are enabled.\r
+ \throw nothrow\r
+ */\r
+ bool ParserBase::HasBuiltInOprt() const\r
+ {\r
+ return m_bBuiltInOp;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Get the argument separator character. \r
+ */\r
+ char_type ParserBase::GetArgSep() const\r
+ {\r
+ return m_pTokenReader->GetArgSep();\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Set argument separator. \r
+ \param cArgSep the argument separator character.\r
+ */\r
+ void ParserBase::SetArgSep(char_type cArgSep)\r
+ {\r
+ m_pTokenReader->SetArgSep(cArgSep);\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Dump stack content. \r
+\r
+ This function is used for debugging only.\r
+ */\r
+ void ParserBase::StackDump(const ParserStack<token_type> &a_stVal, \r
+ const ParserStack<token_type> &a_stOprt) const\r
+ {\r
+ ParserStack<token_type> stOprt(a_stOprt), \r
+ stVal(a_stVal);\r
+\r
+ mu::console() << _T("\nValue stack:\n");\r
+ while ( !stVal.empty() ) \r
+ {\r
+ token_type val = stVal.pop();\r
+ if (val.GetType()==tpSTR)\r
+ mu::console() << _T(" \"") << val.GetAsString() << _T("\" ");\r
+ else\r
+ mu::console() << _T(" ") << val.GetVal() << _T(" ");\r
+ }\r
+ mu::console() << "\nOperator stack:\n";\r
+\r
+ while ( !stOprt.empty() )\r
+ {\r
+ if (stOprt.top().GetCode()<=cmASSIGN) \r
+ {\r
+ mu::console() << _T("OPRT_INTRNL \"")\r
+ << ParserBase::c_DefaultOprt[stOprt.top().GetCode()] \r
+ << _T("\" \n");\r
+ }\r
+ else\r
+ {\r
+ switch(stOprt.top().GetCode())\r
+ {\r
+ case cmVAR: mu::console() << _T("VAR\n"); break;\r
+ case cmVAL: mu::console() << _T("VAL\n"); break;\r
+ case cmFUNC: mu::console() << _T("FUNC \"") \r
+ << stOprt.top().GetAsString() \r
+ << _T("\"\n"); break;\r
+ case cmFUNC_BULK: mu::console() << _T("FUNC_BULK \"") \r
+ << stOprt.top().GetAsString() \r
+ << _T("\"\n"); break;\r
+ case cmOPRT_INFIX: mu::console() << _T("OPRT_INFIX \"")\r
+ << stOprt.top().GetAsString() \r
+ << _T("\"\n"); break;\r
+ case cmOPRT_BIN: mu::console() << _T("OPRT_BIN \"") \r
+ << stOprt.top().GetAsString() \r
+ << _T("\"\n"); break;\r
+ case cmFUNC_STR: mu::console() << _T("FUNC_STR\n"); break;\r
+ case cmEND: mu::console() << _T("END\n"); break;\r
+ case cmUNKNOWN: mu::console() << _T("UNKNOWN\n"); break;\r
+ case cmBO: mu::console() << _T("BRACKET \"(\"\n"); break;\r
+ case cmBC: mu::console() << _T("BRACKET \")\"\n"); break;\r
+ case cmIF: mu::console() << _T("IF\n"); break;\r
+ case cmELSE: mu::console() << _T("ELSE\n"); break;\r
+ case cmENDIF: mu::console() << _T("ENDIF\n"); break;\r
+ default: mu::console() << stOprt.top().GetCode() << _T(" "); break;\r
+ }\r
+ } \r
+ stOprt.pop();\r
+ }\r
+\r
+ mu::console() << dec << endl;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Evaluate an expression containing comma seperated subexpressions \r
+ \param [out] nStackSize The total number of results available\r
+ \return Pointer to the array containing all expression results\r
+\r
+ This member function can be used to retriev all results of an expression\r
+ made up of multiple comma seperated subexpressions (i.e. "x+y,sin(x),cos(y)")\r
+ */\r
+ value_type* ParserBase::Eval(int &nStackSize) const\r
+ {\r
+ (this->*m_pParseFormula)(); \r
+ nStackSize = m_nFinalResultIdx;\r
+\r
+ // (for historic reasons the stack starts at position 1)\r
+ return &m_vStackBuffer[1];\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return the number of results on the calculation stack. \r
+ \r
+ If the expression contains comma seperated subexpressions (i.e. "sin(y), x+y"). \r
+ There mey be more than one return value. This function returns the number of \r
+ available results.\r
+ */\r
+ int ParserBase::GetNumResults() const\r
+ {\r
+ return m_nFinalResultIdx;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Calculate the result.\r
+\r
+ A note on const correctness: \r
+ I consider it important that Calc is a const function.\r
+ Due to caching operations Calc changes only the state of internal variables with one exception\r
+ m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making\r
+ Calc non const GetUsedVar is non const because it explicitely calls Eval() forcing this update. \r
+\r
+ \pre A formula must be set.\r
+ \pre Variables must have been set (if needed)\r
+\r
+ \sa #m_pParseFormula\r
+ \return The evaluation result\r
+ \throw ParseException if no Formula is set or in case of any other error related to the formula.\r
+ */\r
+ value_type ParserBase::Eval() const\r
+ {\r
+ return (this->*m_pParseFormula)(); \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserBase::Eval(value_type *results, int nBulkSize)\r
+ {\r
+ CreateRPN();\r
+\r
+ int i = 0;\r
+\r
+#ifdef MUP_USE_OPENMP\r
+//#define DEBUG_OMP_STUFF\r
+ #ifdef DEBUG_OMP_STUFF\r
+ int *pThread = new int[nBulkSize];\r
+ int *pIdx = new int[nBulkSize];\r
+ #endif\r
+\r
+ int nMaxThreads = std::min(omp_get_max_threads(), s_MaxNumOpenMPThreads);\r
+ int nThreadID, ct=0;\r
+ omp_set_num_threads(nMaxThreads);\r
+\r
+ #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID)\r
+ for (i=0; i<nBulkSize; ++i)\r
+ {\r
+ nThreadID = omp_get_thread_num();\r
+ results[i] = ParseCmdCodeBulk(i, nThreadID);\r
+\r
+ #ifdef DEBUG_OMP_STUFF\r
+ #pragma omp critical\r
+ {\r
+ pThread[ct] = nThreadID; \r
+ pIdx[ct] = i; \r
+ ct++;\r
+ }\r
+ #endif\r
+ }\r
+\r
+#ifdef DEBUG_OMP_STUFF\r
+ FILE *pFile = fopen("bulk_dbg.txt", "w");\r
+ for (i=0; i<nBulkSize; ++i)\r
+ {\r
+ fprintf(pFile, "idx: %d thread: %d \n", pIdx[i], pThread[i]);\r
+ }\r
+ \r
+ delete [] pIdx;\r
+ delete [] pThread;\r
+\r
+ fclose(pFile);\r
+#endif\r
+\r
+#else\r
+ for (i=0; i<nBulkSize; ++i)\r
+ {\r
+ results[i] = ParseCmdCodeBulk(i, 0);\r
+ }\r
+#endif\r
+\r
+ }\r
+} // namespace mu\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#include "muParserBytecode.h"\r
+\r
+#include <cassert>\r
+#include <string>\r
+#include <stack>\r
+#include <vector>\r
+#include <iostream>\r
+\r
+#include "muParserDef.h"\r
+#include "muParserError.h"\r
+#include "muParserToken.h"\r
+#include "muParserStack.h"\r
+#include "muParserTemplateMagic.h"\r
+\r
+\r
+namespace mu\r
+{\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Bytecode default constructor. */\r
+ ParserByteCode::ParserByteCode()\r
+ :m_iStackPos(0)\r
+ ,m_iMaxStackSize(0)\r
+ ,m_vRPN()\r
+ ,m_bEnableOptimizer(true)\r
+ {\r
+ m_vRPN.reserve(50);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Copy constructor. \r
+ \r
+ Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)\r
+ */\r
+ ParserByteCode::ParserByteCode(const ParserByteCode &a_ByteCode)\r
+ {\r
+ Assign(a_ByteCode);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Assignment operator.\r
+ \r
+ Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)\r
+ */\r
+ ParserByteCode& ParserByteCode::operator=(const ParserByteCode &a_ByteCode)\r
+ {\r
+ Assign(a_ByteCode);\r
+ return *this;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserByteCode::EnableOptimizer(bool bStat)\r
+ {\r
+ m_bEnableOptimizer = bStat;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Copy state of another object to this. \r
+ \r
+ \throw nowthrow\r
+ */\r
+ void ParserByteCode::Assign(const ParserByteCode &a_ByteCode)\r
+ {\r
+ if (this==&a_ByteCode) \r
+ return;\r
+\r
+ m_iStackPos = a_ByteCode.m_iStackPos;\r
+ m_vRPN = a_ByteCode.m_vRPN;\r
+ m_iMaxStackSize = a_ByteCode.m_iMaxStackSize;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add a Variable pointer to bytecode. \r
+ \param a_pVar Pointer to be added.\r
+ \throw nothrow\r
+ */\r
+ void ParserByteCode::AddVar(value_type *a_pVar)\r
+ {\r
+ ++m_iStackPos;\r
+ m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);\r
+\r
+ // optimization does not apply\r
+ SToken tok;\r
+ tok.Cmd = cmVAR;\r
+ tok.Val.ptr = a_pVar;\r
+ tok.Val.data = 1;\r
+ tok.Val.data2 = 0;\r
+ m_vRPN.push_back(tok);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add a Variable pointer to bytecode. \r
+\r
+ Value entries in byte code consist of:\r
+ <ul>\r
+ <li>value array position of the value</li>\r
+ <li>the operator code according to ParserToken::cmVAL</li>\r
+ <li>the value stored in #mc_iSizeVal number of bytecode entries.</li>\r
+ </ul>\r
+\r
+ \param a_pVal Value to be added.\r
+ \throw nothrow\r
+ */\r
+ void ParserByteCode::AddVal(value_type a_fVal)\r
+ {\r
+ ++m_iStackPos;\r
+ m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);\r
+\r
+ // If optimization does not apply\r
+ SToken tok;\r
+ tok.Cmd = cmVAL;\r
+ tok.Val.ptr = NULL;\r
+ tok.Val.data = 0;\r
+ tok.Val.data2 = a_fVal;\r
+ m_vRPN.push_back(tok);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserByteCode::ConstantFolding(ECmdCode a_Oprt)\r
+ {\r
+ std::size_t sz = m_vRPN.size();\r
+ value_type &x = m_vRPN[sz-2].Val.data2,\r
+ &y = m_vRPN[sz-1].Val.data2;\r
+ switch (a_Oprt)\r
+ {\r
+ case cmLAND: x = (int)x && (int)y; m_vRPN.pop_back(); break;\r
+ case cmLOR: x = (int)x || (int)y; m_vRPN.pop_back(); break;\r
+ case cmLT: x = x < y; m_vRPN.pop_back(); break;\r
+ case cmGT: x = x > y; m_vRPN.pop_back(); break;\r
+ case cmLE: x = x <= y; m_vRPN.pop_back(); break;\r
+ case cmGE: x = x >= y; m_vRPN.pop_back(); break;\r
+ case cmNEQ: x = x != y; m_vRPN.pop_back(); break;\r
+ case cmEQ: x = x == y; m_vRPN.pop_back(); break;\r
+ case cmADD: x = x + y; m_vRPN.pop_back(); break;\r
+ case cmSUB: x = x - y; m_vRPN.pop_back(); break;\r
+ case cmMUL: x = x * y; m_vRPN.pop_back(); break;\r
+ case cmDIV: \r
+\r
+#if defined(MUP_MATH_EXCEPTIONS)\r
+ if (y==0)\r
+ throw ParserError(ecDIV_BY_ZERO, _T("0"));\r
+#endif\r
+\r
+ x = x / y; \r
+ m_vRPN.pop_back();\r
+ break;\r
+\r
+ case cmPOW: x = MathImpl<value_type>::Pow(x, y); \r
+ m_vRPN.pop_back();\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ } // switch opcode\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add an operator identifier to bytecode. \r
+ \r
+ Operator entries in byte code consist of:\r
+ <ul>\r
+ <li>value array position of the result</li>\r
+ <li>the operator code according to ParserToken::ECmdCode</li>\r
+ </ul>\r
+\r
+ \sa ParserToken::ECmdCode\r
+ */\r
+ void ParserByteCode::AddOp(ECmdCode a_Oprt)\r
+ {\r
+ bool bOptimized = false;\r
+\r
+ if (m_bEnableOptimizer)\r
+ {\r
+ std::size_t sz = m_vRPN.size();\r
+\r
+ // Check for foldable constants like:\r
+ // cmVAL cmVAL cmADD \r
+ // where cmADD can stand fopr any binary operator applied to\r
+ // two constant values.\r
+ if (sz>=2 && m_vRPN[sz-2].Cmd == cmVAL && m_vRPN[sz-1].Cmd == cmVAL)\r
+ {\r
+ ConstantFolding(a_Oprt);\r
+ bOptimized = true;\r
+ }\r
+ else\r
+ {\r
+ switch(a_Oprt)\r
+ {\r
+ case cmPOW:\r
+ // Optimization for ploynomials of low order\r
+ if (m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-1].Cmd == cmVAL)\r
+ {\r
+ if (m_vRPN[sz-1].Val.data2==2)\r
+ m_vRPN[sz-2].Cmd = cmVARPOW2;\r
+ else if (m_vRPN[sz-1].Val.data2==3)\r
+ m_vRPN[sz-2].Cmd = cmVARPOW3;\r
+ else if (m_vRPN[sz-1].Val.data2==4)\r
+ m_vRPN[sz-2].Cmd = cmVARPOW4;\r
+ else\r
+ break;\r
+\r
+ m_vRPN.pop_back();\r
+ bOptimized = true;\r
+ }\r
+ break;\r
+\r
+ case cmSUB:\r
+ case cmADD:\r
+ // Simple optimization based on pattern recognition for a shitload of different\r
+ // bytecode combinations of addition/subtraction\r
+ if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) ||\r
+ (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) || \r
+ (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) ||\r
+ (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ||\r
+ (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||\r
+ (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||\r
+ (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ||\r
+ (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) )\r
+ {\r
+ assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) ||\r
+ (m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) || \r
+ (m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) );\r
+\r
+ m_vRPN[sz-2].Cmd = cmVARMUL;\r
+ 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\r
+ m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset\r
+ m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplikatior\r
+ m_vRPN.pop_back();\r
+ bOptimized = true;\r
+ } \r
+ break;\r
+\r
+ case cmMUL:\r
+ if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) ||\r
+ (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ) \r
+ {\r
+ m_vRPN[sz-2].Cmd = cmVARMUL;\r
+ m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr));\r
+ m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2;\r
+ m_vRPN[sz-2].Val.data2 = 0;\r
+ m_vRPN.pop_back();\r
+ bOptimized = true;\r
+ } \r
+ else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) ||\r
+ (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) )\r
+ {\r
+ // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2\r
+ m_vRPN[sz-2].Cmd = cmVARMUL;\r
+ m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr));\r
+ if (m_vRPN[sz-1].Cmd == cmVAL)\r
+ {\r
+ m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2;\r
+ m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2;\r
+ }\r
+ else\r
+ {\r
+ m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2;\r
+ m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2;\r
+ }\r
+ m_vRPN.pop_back();\r
+ bOptimized = true;\r
+ }\r
+ else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR &&\r
+ m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr)\r
+ {\r
+ // Optimization: a*a -> a^2\r
+ m_vRPN[sz-2].Cmd = cmVARPOW2;\r
+ m_vRPN.pop_back();\r
+ bOptimized = true;\r
+ }\r
+ break;\r
+\r
+ case cmDIV:\r
+ if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-1].Val.data2!=0)\r
+ {\r
+ // Optimization: 4*a/2 -> 2*a\r
+ m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2;\r
+ m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2;\r
+ m_vRPN.pop_back();\r
+ bOptimized = true;\r
+ }\r
+ break;\r
+ \r
+ } // switch a_Oprt\r
+ }\r
+ }\r
+\r
+ // If optimization can't be applied just write the value\r
+ if (!bOptimized)\r
+ {\r
+ --m_iStackPos;\r
+ SToken tok;\r
+ tok.Cmd = a_Oprt;\r
+ m_vRPN.push_back(tok);\r
+ }\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserByteCode::AddIfElse(ECmdCode a_Oprt)\r
+ {\r
+ SToken tok;\r
+ tok.Cmd = a_Oprt;\r
+ m_vRPN.push_back(tok);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add an assignement operator\r
+ \r
+ Operator entries in byte code consist of:\r
+ <ul>\r
+ <li>cmASSIGN code</li>\r
+ <li>the pointer of the destination variable</li>\r
+ </ul>\r
+\r
+ \sa ParserToken::ECmdCode\r
+ */\r
+ void ParserByteCode::AddAssignOp(value_type *a_pVar)\r
+ {\r
+ --m_iStackPos;\r
+\r
+ SToken tok;\r
+ tok.Cmd = cmASSIGN;\r
+ tok.Val.ptr = a_pVar;\r
+ m_vRPN.push_back(tok);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add function to bytecode. \r
+\r
+ \param a_iArgc Number of arguments, negative numbers indicate multiarg functions.\r
+ \param a_pFun Pointer to function callback.\r
+ */\r
+ void ParserByteCode::AddFun(generic_fun_type a_pFun, int a_iArgc)\r
+ {\r
+ if (a_iArgc>=0)\r
+ {\r
+ m_iStackPos = m_iStackPos - a_iArgc + 1; \r
+ }\r
+ else\r
+ {\r
+ // function with unlimited number of arguments\r
+ m_iStackPos = m_iStackPos + a_iArgc + 1; \r
+ }\r
+ m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);\r
+\r
+ SToken tok;\r
+ tok.Cmd = cmFUNC;\r
+ tok.Fun.argc = a_iArgc;\r
+ tok.Fun.ptr = a_pFun;\r
+ m_vRPN.push_back(tok);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add a bulk function to bytecode. \r
+\r
+ \param a_iArgc Number of arguments, negative numbers indicate multiarg functions.\r
+ \param a_pFun Pointer to function callback.\r
+ */\r
+ void ParserByteCode::AddBulkFun(generic_fun_type a_pFun, int a_iArgc)\r
+ {\r
+ m_iStackPos = m_iStackPos - a_iArgc + 1; \r
+ m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);\r
+\r
+ SToken tok;\r
+ tok.Cmd = cmFUNC_BULK;\r
+ tok.Fun.argc = a_iArgc;\r
+ tok.Fun.ptr = a_pFun;\r
+ m_vRPN.push_back(tok);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add Strung function entry to the parser bytecode. \r
+ \throw nothrow\r
+\r
+ A string function entry consists of the stack position of the return value,\r
+ followed by a cmSTRFUNC code, the function pointer and an index into the \r
+ string buffer maintained by the parser.\r
+ */\r
+ void ParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx)\r
+ {\r
+ m_iStackPos = m_iStackPos - a_iArgc + 1;\r
+\r
+ SToken tok;\r
+ tok.Cmd = cmFUNC_STR;\r
+ tok.Fun.argc = a_iArgc;\r
+ tok.Fun.idx = a_iIdx;\r
+ tok.Fun.ptr = a_pFun;\r
+ m_vRPN.push_back(tok);\r
+\r
+ m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Add end marker to bytecode.\r
+ \r
+ \throw nothrow \r
+ */\r
+ void ParserByteCode::Finalize()\r
+ {\r
+ SToken tok;\r
+ tok.Cmd = cmEND;\r
+ m_vRPN.push_back(tok);\r
+ rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit\r
+\r
+ // Determine the if-then-else jump offsets\r
+ ParserStack<int> stIf, stElse;\r
+ int idx;\r
+ for (int i=0; i<(int)m_vRPN.size(); ++i)\r
+ {\r
+ switch(m_vRPN[i].Cmd)\r
+ {\r
+ case cmIF:\r
+ stIf.push(i);\r
+ break;\r
+\r
+ case cmELSE:\r
+ stElse.push(i);\r
+ idx = stIf.pop();\r
+ m_vRPN[idx].Oprt.offset = i - idx;\r
+ break;\r
+ \r
+ case cmENDIF:\r
+ idx = stElse.pop();\r
+ m_vRPN[idx].Oprt.offset = i - idx;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ const SToken* ParserByteCode::GetBase() const\r
+ {\r
+ if (m_vRPN.size()==0)\r
+ throw ParserError(ecINTERNAL_ERROR);\r
+ else\r
+ return &m_vRPN[0];\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ std::size_t ParserByteCode::GetMaxStackSize() const\r
+ {\r
+ return m_iMaxStackSize+1;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Returns the number of entries in the bytecode. */\r
+ std::size_t ParserByteCode::GetSize() const\r
+ {\r
+ return m_vRPN.size();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Delete the bytecode. \r
+ \r
+ \throw nothrow\r
+\r
+ The name of this function is a violation of my own coding guidelines\r
+ but this way it's more in line with the STL functions thus more \r
+ intuitive.\r
+ */\r
+ void ParserByteCode::clear()\r
+ {\r
+ m_vRPN.clear();\r
+ m_iStackPos = 0;\r
+ m_iMaxStackSize = 0;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Dump bytecode (for debugging only!). */\r
+ void ParserByteCode::AsciiDump()\r
+ {\r
+ if (!m_vRPN.size()) \r
+ {\r
+ mu::console() << _T("No bytecode available\n");\r
+ return;\r
+ }\r
+\r
+ mu::console() << _T("Number of RPN tokens:") << (int)m_vRPN.size() << _T("\n");\r
+ for (std::size_t i=0; i<m_vRPN.size() && m_vRPN[i].Cmd!=cmEND; ++i)\r
+ {\r
+ mu::console() << std::dec << i << _T(" : \t");\r
+ switch (m_vRPN[i].Cmd)\r
+ {\r
+ case cmVAL: mu::console() << _T("VAL \t");\r
+ mu::console() << _T("[") << m_vRPN[i].Val.data2 << _T("]\n");\r
+ break;\r
+\r
+ case cmVAR: mu::console() << _T("VAR \t");\r
+ mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n"); \r
+ break;\r
+\r
+ case cmVARPOW2: mu::console() << _T("VARPOW2 \t");\r
+ mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n"); \r
+ break;\r
+\r
+ case cmVARPOW3: mu::console() << _T("VARPOW3 \t");\r
+ mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n"); \r
+ break;\r
+\r
+ case cmVARPOW4: mu::console() << _T("VARPOW4 \t");\r
+ mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]\n"); \r
+ break;\r
+\r
+ case cmVARMUL: mu::console() << _T("VARMUL \t");\r
+ mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Val.ptr << _T("]"); \r
+ mu::console() << _T(" * [") << m_vRPN[i].Val.data << _T("]");\r
+ mu::console() << _T(" + [") << m_vRPN[i].Val.data2 << _T("]\n");\r
+ break;\r
+\r
+ case cmFUNC: mu::console() << _T("CALL\t");\r
+ mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]"); \r
+ mu::console() << _T("[ADDR: 0x") << std::hex << m_vRPN[i].Fun.ptr << _T("]"); \r
+ mu::console() << _T("\n");\r
+ break;\r
+\r
+ case cmFUNC_STR:\r
+ mu::console() << _T("CALL STRFUNC\t");\r
+ mu::console() << _T("[ARG:") << std::dec << m_vRPN[i].Fun.argc << _T("]");\r
+ mu::console() << _T("[IDX:") << std::dec << m_vRPN[i].Fun.idx << _T("]");\r
+ mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Fun.ptr << _T("]\n"); \r
+ break;\r
+\r
+ case cmLT: mu::console() << _T("LT\n"); break;\r
+ case cmGT: mu::console() << _T("GT\n"); break;\r
+ case cmLE: mu::console() << _T("LE\n"); break;\r
+ case cmGE: mu::console() << _T("GE\n"); break;\r
+ case cmEQ: mu::console() << _T("EQ\n"); break;\r
+ case cmNEQ: mu::console() << _T("NEQ\n"); break;\r
+ case cmADD: mu::console() << _T("ADD\n"); break;\r
+ case cmLAND: mu::console() << _T("&&\n"); break;\r
+ case cmLOR: mu::console() << _T("||\n"); break;\r
+ case cmSUB: mu::console() << _T("SUB\n"); break;\r
+ case cmMUL: mu::console() << _T("MUL\n"); break;\r
+ case cmDIV: mu::console() << _T("DIV\n"); break;\r
+ case cmPOW: mu::console() << _T("POW\n"); break;\r
+\r
+ case cmIF: mu::console() << _T("IF\t");\r
+ mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");\r
+ break;\r
+\r
+ case cmELSE: mu::console() << _T("ELSE\t");\r
+ mu::console() << _T("[OFFSET:") << std::dec << m_vRPN[i].Oprt.offset << _T("]\n");\r
+ break;\r
+\r
+ case cmENDIF: mu::console() << _T("ENDIF\n"); break;\r
+\r
+ case cmASSIGN: \r
+ mu::console() << _T("ASSIGN\t");\r
+ mu::console() << _T("[ADDR: 0x") << m_vRPN[i].Oprt.ptr << _T("]\n"); \r
+ break; \r
+\r
+ default: mu::console() << _T("(unknown code: ") << m_vRPN[i].Cmd << _T(")\n"); \r
+ break;\r
+ } // switch cmdCode\r
+ } // while bytecode\r
+\r
+ mu::console() << _T("END") << std::endl;\r
+ }\r
+} // namespace mu\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2004-2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#include "muParserCallback.h"\r
+\r
+/** \file\r
+ \brief Implementation of the parser callback class.\r
+*/\r
+\r
+\r
+namespace mu\r
+{\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type0 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(0)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(1)\r
+ ,m_iPri(a_iPrec)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(a_iCode)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Constructor for constructing funcstion callbacks taking two arguments. \r
+ \throw nothrow\r
+ */\r
+ ParserCallback::ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(2)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Constructor for constructing binary operator callbacks. \r
+ \param a_pFun Pointer to a static function taking two arguments\r
+ \param a_bAllowOpti A flag indicating this funcation can be optimized\r
+ \param a_iPrec The operator precedence\r
+ \param a_eOprtAsct The operators associativity\r
+ \throw nothrow\r
+ */\r
+ ParserCallback::ParserCallback(fun_type2 a_pFun, \r
+ bool a_bAllowOpti, \r
+ int a_iPrec, \r
+ EOprtAssociativity a_eOprtAsct)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(2)\r
+ ,m_iPri(a_iPrec)\r
+ ,m_eOprtAsct(a_eOprtAsct)\r
+ ,m_iCode(cmOPRT_BIN)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(3)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(4)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(5)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type6 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(6)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type7 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(7)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type8 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(8)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type9 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(9)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(fun_type10 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(10)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(0)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(1)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Constructor for constructing funcstion callbacks taking two arguments. \r
+ \throw nothrow\r
+ */\r
+ ParserCallback::ParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(2)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(3)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(4)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(5)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(6)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(7)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(8)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(9)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(10)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_BULK)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(multfun_type a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(-1)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC)\r
+ ,m_iType(tpDBL)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(0)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_STR)\r
+ ,m_iType(tpSTR)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(1)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_STR)\r
+ ,m_iType(tpSTR)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserCallback::ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti)\r
+ :m_pFun((void*)a_pFun)\r
+ ,m_iArgc(2)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmFUNC_STR)\r
+ ,m_iType(tpSTR)\r
+ ,m_bAllowOpti(a_bAllowOpti)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Default constructor. \r
+ \throw nothrow\r
+ */\r
+ ParserCallback::ParserCallback()\r
+ :m_pFun(0)\r
+ ,m_iArgc(0)\r
+ ,m_iPri(-1)\r
+ ,m_eOprtAsct(oaNONE)\r
+ ,m_iCode(cmUNKNOWN)\r
+ ,m_iType(tpVOID)\r
+ ,m_bAllowOpti(0)\r
+ {}\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Copy constructor. \r
+ \throw nothrow\r
+ */\r
+ ParserCallback::ParserCallback(const ParserCallback &ref)\r
+ {\r
+ m_pFun = ref.m_pFun;\r
+ m_iArgc = ref.m_iArgc;\r
+ m_bAllowOpti = ref.m_bAllowOpti;\r
+ m_iCode = ref.m_iCode;\r
+ m_iType = ref.m_iType;\r
+ m_iPri = ref.m_iPri;\r
+ m_eOprtAsct = ref.m_eOprtAsct;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Clone this instance and return a pointer to the new instance. */\r
+ ParserCallback* ParserCallback::Clone() const\r
+ {\r
+ return new ParserCallback(*this);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return tru if the function is conservative.\r
+\r
+ Conservative functions return always the same result for the same argument.\r
+ \throw nothrow\r
+ */\r
+ bool ParserCallback::IsOptimizable() const \r
+ { \r
+ return m_bAllowOpti; \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Get the callback address for the parser function. \r
+ \r
+ The type of the address is void. It needs to be recasted according to the\r
+ argument number to the right type.\r
+\r
+ \throw nothrow\r
+ \return #pFun\r
+ */\r
+ void* ParserCallback::GetAddr() const \r
+ { \r
+ return m_pFun; \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return the callback code. */\r
+ ECmdCode ParserCallback::GetCode() const \r
+ { \r
+ return m_iCode; \r
+ }\r
+ \r
+ //---------------------------------------------------------------------------\r
+ ETypeCode ParserCallback::GetType() const \r
+ { \r
+ return m_iType; \r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return the operator precedence. \r
+ \throw nothrown\r
+\r
+ Only valid if the callback token is an operator token (binary or infix).\r
+ */\r
+ int ParserCallback::GetPri() const \r
+ { \r
+ return m_iPri; \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return the operators associativity. \r
+ \throw nothrown\r
+\r
+ Only valid if the callback token is a binary operator token.\r
+ */\r
+ EOprtAssociativity ParserCallback::GetAssociativity() const\r
+ {\r
+ return m_eOprtAsct;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Returns the number of function Arguments. */\r
+ int ParserCallback::GetArgc() const \r
+ { \r
+ return m_iArgc; \r
+ }\r
+} // namespace mu\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2004-2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+#if defined(MUPARSER_DLL) \r
+\r
+#if defined(_WIN32)\r
+ #define WIN32_LEAN_AND_MEAN\r
+ #include <windows.h>\r
+#endif\r
+\r
+#include "muParserDLL.h"\r
+#include "muParser.h"\r
+#include "muParserInt.h"\r
+#include "muParserError.h"\r
+\r
+\r
+#define MU_TRY \\r
+ try \\r
+ {\r
+\r
+#define MU_CATCH \\r
+ } \\r
+ catch(muError_t &e) \\r
+ { \\r
+ ParserTag *pTag = static_cast<ParserTag*>(a_hParser); \\r
+ pTag->exc = e; \\r
+ pTag->bError = true; \\r
+ if (pTag->errHandler) \\r
+ (pTag->errHandler)(a_hParser); \\r
+ } \\r
+ catch(...) \\r
+ { \\r
+ ParserTag *pTag = static_cast<ParserTag*>(a_hParser); \\r
+ pTag->exc = muError_t(mu::ecINTERNAL_ERROR); \\r
+ pTag->bError = true; \\r
+ if (pTag->errHandler) \\r
+ (pTag->errHandler)(a_hParser); \\r
+ }\r
+\r
+/** \file \r
+ \brief This file contains the implementation of the DLL interface of muparser.\r
+*/\r
+\r
+//---------------------------------------------------------------------------\r
+// private types\r
+typedef mu::ParserBase::exception_type muError_t;\r
+typedef mu::ParserBase muParser_t;\r
+\r
+int g_nBulkSize;\r
+\r
+//---------------------------------------------------------------------------\r
+class ParserTag\r
+{\r
+public:\r
+ ParserTag(int nType)\r
+ :pParser( (nType==muBASETYPE_FLOAT) ? (mu::ParserBase*)new mu::Parser() : \r
+ (nType==muBASETYPE_INT) ? (mu::ParserBase*)new mu::ParserInt() : NULL)\r
+ ,exc()\r
+ ,errHandler(NULL)\r
+ ,bError(false)\r
+ ,m_nParserType(nType)\r
+ {}\r
+ \r
+ ~ParserTag()\r
+ {\r
+ delete pParser;\r
+ }\r
+\r
+ mu::ParserBase *pParser;\r
+ mu::ParserBase::exception_type exc;\r
+ muErrorHandler_t errHandler;\r
+ bool bError;\r
+\r
+private:\r
+ ParserTag(const ParserTag &ref);\r
+ ParserTag& operator=(const ParserTag &ref);\r
+\r
+ int m_nParserType;\r
+};\r
+\r
+static muChar_t s_tmpOutBuf[2048];\r
+\r
+//---------------------------------------------------------------------------\r
+//\r
+//\r
+// unexported functions\r
+//\r
+//\r
+//---------------------------------------------------------------------------\r
+\r
+//---------------------------------------------------------------------------\r
+muParser_t* AsParser(muParserHandle_t a_hParser)\r
+{\r
+ return static_cast<ParserTag*>(a_hParser)->pParser;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+ParserTag* AsParserTag(muParserHandle_t a_hParser)\r
+{\r
+ return static_cast<ParserTag*>(a_hParser);\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+#if defined(_WIN32)\r
+ #define _CRT_SECURE_NO_DEPRECATE\r
+\r
+ BOOL APIENTRY DllMain( HANDLE /*hModule*/, \r
+ DWORD ul_reason_for_call, \r
+ LPVOID /*lpReserved*/ )\r
+ {\r
+ switch (ul_reason_for_call)\r
+ {\r
+ case DLL_PROCESS_ATTACH:\r
+ break;\r
+\r
+ case DLL_THREAD_ATTACH:\r
+ case DLL_THREAD_DETACH:\r
+ case DLL_PROCESS_DETACH:\r
+ break;\r
+ }\r
+\r
+ return TRUE;\r
+ }\r
+\r
+#endif\r
+\r
+//---------------------------------------------------------------------------\r
+//\r
+//\r
+// exported functions\r
+//\r
+//\r
+//---------------------------------------------------------------------------\r
+\r
+API_EXPORT(void) mupSetVarFactory(muParserHandle_t a_hParser, muFacFun_t a_pFactory, void *pUserData)\r
+{\r
+ MU_TRY\r
+ muParser_t* p(AsParser(a_hParser));\r
+ p->SetVarFactory(a_pFactory, pUserData);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Create a new Parser instance and return its handle.\r
+*/\r
+API_EXPORT(muParserHandle_t) mupCreate(int nBaseType)\r
+{\r
+ switch(nBaseType)\r
+ {\r
+ case muBASETYPE_FLOAT: return (void*)(new ParserTag(muBASETYPE_FLOAT));\r
+ case muBASETYPE_INT: return (void*)(new ParserTag(muBASETYPE_INT));\r
+ default: return NULL;\r
+ }\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Release the parser instance related with a parser handle.\r
+*/\r
+API_EXPORT(void) mupRelease(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ ParserTag* p = static_cast<ParserTag*>(a_hParser);\r
+ delete p;\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(const muChar_t*) mupGetVersion(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ sprintf(s_tmpOutBuf, "%s", p->GetVersion().c_str());\r
+ return s_tmpOutBuf;\r
+ MU_CATCH\r
+\r
+ return "";\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Evaluate the expression.\r
+*/\r
+API_EXPORT(muFloat_t) mupEval(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ return p->Eval();\r
+ MU_CATCH\r
+\r
+ return 0;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(muFloat_t*) mupEvalMulti(muParserHandle_t a_hParser, int *nNum)\r
+{\r
+ MU_TRY\r
+ assert(nNum!=NULL);\r
+\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ return p->Eval(*nNum);\r
+ MU_CATCH\r
+\r
+ return 0;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupEvalBulk(muParserHandle_t a_hParser, muFloat_t *a_res, int nSize)\r
+{\r
+ MU_TRY\r
+ muParser_t* p(AsParser(a_hParser));\r
+ p->Eval(a_res, nSize);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupSetExpr(muParserHandle_t a_hParser, const muChar_t* a_szExpr)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->SetExpr(a_szExpr);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupRemoveVar(muParserHandle_t a_hParser, const muChar_t* a_szName)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->RemoveVar( a_szName );\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Release all parser variables.\r
+ \param a_hParser Handle to the parser instance.\r
+*/\r
+API_EXPORT(void) mupClearVar(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->ClearVar();\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Release all parser variables.\r
+ \param a_hParser Handle to the parser instance.\r
+*/\r
+API_EXPORT(void) mupClearConst(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->ClearConst();\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Clear all user defined operators.\r
+ \param a_hParser Handle to the parser instance.\r
+*/\r
+API_EXPORT(void) mupClearOprt(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->ClearOprt();\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupClearFun(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->ClearFun();\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun0( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFun0_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun1( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFun1_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun2( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFun2_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun3( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFun3_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun4( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFun4_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun5( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFun5_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun6( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFun6_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun7( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFun7_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun8( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFun8_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun9( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFun9_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineFun10( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFun10_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun0(muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muBulkFun0_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun1(muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muBulkFun1_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun2(muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muBulkFun2_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun3(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muBulkFun3_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun4(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muBulkFun4_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun5(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muBulkFun5_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun6(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muBulkFun6_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun7(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muBulkFun7_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun8(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muBulkFun8_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun9(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muBulkFun9_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkFun10( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muBulkFun10_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineStrFun1( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muStrFun1_t a_pFun )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineStrFun2( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muStrFun2_t a_pFun )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineStrFun3( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muStrFun3_t a_pFun )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, false);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineMultFun( muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muMultFun_t a_pFun, \r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineOprt( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szName, \r
+ muFun2_t a_pFun, \r
+ muInt_t a_nPrec, \r
+ muInt_t a_nOprtAsct,\r
+ muBool_t a_bAllowOpt)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineOprt(a_szName, \r
+ a_pFun, \r
+ a_nPrec, \r
+ (mu::EOprtAssociativity)a_nOprtAsct, \r
+ a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineVar(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFloat_t *a_pVar)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineVar(a_szName, a_pVar);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineBulkVar(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFloat_t *a_pVar)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineVar(a_szName, a_pVar);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineConst(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ muFloat_t a_fVal)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineConst(a_szName, a_fVal);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineStrConst(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szName, \r
+ const muChar_t *a_szVal)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineStrConst(a_szName, a_szVal);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(const muChar_t*) mupGetExpr(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+\r
+ // C# explodes when pMsg is returned directly. For some reason it can't access\r
+ // the memory where the message lies directly.\r
+ sprintf(s_tmpOutBuf, "%s", p->GetExpr().c_str());\r
+ return s_tmpOutBuf;\r
+ \r
+ MU_CATCH\r
+\r
+ return "";\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefinePostfixOprt( muParserHandle_t a_hParser,\r
+ const muChar_t* a_szName,\r
+ muFun1_t a_pOprt,\r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefinePostfixOprt(a_szName, a_pOprt, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineInfixOprt( muParserHandle_t a_hParser,\r
+ const muChar_t* a_szName,\r
+ muFun1_t a_pOprt,\r
+ muBool_t a_bAllowOpt )\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineInfixOprt(a_szName, a_pOprt, a_bAllowOpt!=0);\r
+ MU_CATCH\r
+}\r
+\r
+// Define character sets for identifiers\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineNameChars( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szCharset )\r
+{\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineNameChars(a_szCharset);\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineOprtChars( muParserHandle_t a_hParser, \r
+ const muChar_t* a_szCharset )\r
+{\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineOprtChars(a_szCharset);\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupDefineInfixOprtChars(muParserHandle_t a_hParser, \r
+ const muChar_t *a_szCharset)\r
+{\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->DefineInfixOprtChars(a_szCharset);\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Get the number of variables defined in the parser.\r
+ \param a_hParser [in] Must be a valid parser handle.\r
+ \return The number of used variables.\r
+ \sa mupGetExprVar\r
+*/\r
+API_EXPORT(int) mupGetVarNum(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ const mu::varmap_type VarMap = p->GetVar();\r
+ return (int)VarMap.size();\r
+ MU_CATCH\r
+\r
+ return 0; // never reached\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Return a variable that is used in an expression.\r
+ \param a_hParser [in] A valid parser handle.\r
+ \param a_iVar [in] The index of the variable to return.\r
+ \param a_szName [out] Pointer to the variable name.\r
+ \param a_pVar [out] Pointer to the variable.\r
+ \throw nothrow\r
+\r
+ Prior to calling this function call mupGetExprVarNum in order to get the\r
+ number of variables in the expression. If the parameter a_iVar is greater\r
+ than the number of variables both a_szName and a_pVar will be set to zero.\r
+ As a side effect this function will trigger an internal calculation of the\r
+ expression undefined variables will be set to zero during this calculation.\r
+ During the calculation user defined callback functions present in the expression\r
+ will be called, this is unavoidable.\r
+*/\r
+API_EXPORT(void) mupGetVar(muParserHandle_t a_hParser, \r
+ unsigned a_iVar, \r
+ const muChar_t **a_szName, \r
+ muFloat_t **a_pVar)\r
+{\r
+ // A static buffer is needed for the name since i cant return the\r
+ // pointer from the map.\r
+ static muChar_t szName[1024];\r
+\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ const mu::varmap_type VarMap = p->GetVar();\r
+\r
+ if (a_iVar>=VarMap.size())\r
+ {\r
+ *a_szName = 0;\r
+ *a_pVar = 0;\r
+ return;\r
+ }\r
+ mu::varmap_type::const_iterator item;\r
+\r
+ item = VarMap.begin();\r
+ for (unsigned i=0; i<a_iVar; ++i)\r
+ item++;\r
+\r
+ strncpy(szName, item->first.c_str(), sizeof(szName));\r
+ szName[sizeof(szName)-1] = 0;\r
+\r
+ *a_szName = &szName[0];\r
+ *a_pVar = item->second;\r
+ return;\r
+\r
+ MU_CATCH\r
+\r
+ *a_szName = 0;\r
+ *a_pVar = 0;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Get the number of variables used in the expression currently set in the parser.\r
+ \param a_hParser [in] Must be a valid parser handle.\r
+ \return The number of used variables.\r
+ \sa mupGetExprVar\r
+*/\r
+API_EXPORT(int) mupGetExprVarNum(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ const mu::varmap_type VarMap = p->GetUsedVar();\r
+ return (int)VarMap.size();\r
+ MU_CATCH\r
+\r
+ return 0; // never reached\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Return a variable that is used in an expression.\r
+\r
+ Prior to calling this function call mupGetExprVarNum in order to get the\r
+ number of variables in the expression. If the parameter a_iVar is greater\r
+ than the number of variables both a_szName and a_pVar will be set to zero.\r
+ As a side effect this function will trigger an internal calculation of the\r
+ expression undefined variables will be set to zero during this calculation.\r
+ During the calculation user defined callback functions present in the expression\r
+ will be called, this is unavoidable.\r
+\r
+ \param a_hParser [in] A valid parser handle.\r
+ \param a_iVar [in] The index of the variable to return.\r
+ \param a_szName [out] Pointer to the variable name.\r
+ \param a_pVar [out] Pointer to the variable.\r
+ \throw nothrow\r
+*/\r
+API_EXPORT(void) mupGetExprVar(muParserHandle_t a_hParser, \r
+ unsigned a_iVar, \r
+ const muChar_t **a_szName, \r
+ muFloat_t **a_pVar)\r
+{\r
+ // A static buffer is needed for the name since i cant return the\r
+ // pointer from the map.\r
+ static muChar_t szName[1024];\r
+\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ const mu::varmap_type VarMap = p->GetUsedVar();\r
+\r
+ if (a_iVar>=VarMap.size())\r
+ {\r
+ *a_szName = 0;\r
+ *a_pVar = 0;\r
+ return;\r
+ }\r
+ mu::varmap_type::const_iterator item;\r
+\r
+ item = VarMap.begin();\r
+ for (unsigned i=0; i<a_iVar; ++i)\r
+ item++;\r
+\r
+ strncpy(szName, item->first.c_str(), sizeof(szName));\r
+ szName[sizeof(szName)-1] = 0;\r
+\r
+ *a_szName = &szName[0];\r
+ *a_pVar = item->second;\r
+ return;\r
+\r
+ MU_CATCH\r
+\r
+ *a_szName = 0;\r
+ *a_pVar = 0;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Return the number of constants defined in a parser. */\r
+API_EXPORT(int) mupGetConstNum(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ const mu::valmap_type ValMap = p->GetConst();\r
+ return (int)ValMap.size();\r
+ MU_CATCH\r
+\r
+ return 0; // never reached\r
+}\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+API_EXPORT(void) mupSetArgSep(muParserHandle_t a_hParser, const muChar_t cArgSep)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->SetArgSep(cArgSep);\r
+ MU_CATCH\r
+}\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+API_EXPORT(void) mupResetLocale(muParserHandle_t a_hParser)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->ResetLocale();\r
+ MU_CATCH\r
+}\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+API_EXPORT(void) mupSetDecSep(muParserHandle_t a_hParser, const muChar_t cDecSep)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->SetDecSep(cDecSep);\r
+ MU_CATCH\r
+}\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+API_EXPORT(void) mupSetThousandsSep(muParserHandle_t a_hParser, const muChar_t cThousandsSep)\r
+{\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ p->SetThousandsSep(cThousandsSep);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Retrieve name and value of a single parser constant.\r
+ \param a_hParser [in] a valid parser handle\r
+ \param a_iVar [in] Index of the constant to query\r
+ \param a_pszName [out] pointer to a null terminated string with the constant name\r
+ \param [out] The constant value\r
+*/\r
+API_EXPORT(void) mupGetConst( muParserHandle_t a_hParser, \r
+ unsigned a_iVar,\r
+ const muChar_t **a_pszName, \r
+ muFloat_t *a_fVal)\r
+{\r
+ // A static buffer is needed for the name since i cant return the\r
+ // pointer from the map.\r
+ static muChar_t szName[1024];\r
+\r
+ MU_TRY\r
+ muParser_t* const p(AsParser(a_hParser));\r
+ const mu::valmap_type ValMap = p->GetConst();\r
+\r
+ if (a_iVar>=ValMap.size())\r
+ {\r
+ *a_pszName = 0;\r
+ *a_fVal = 0;\r
+ return;\r
+ }\r
+\r
+ mu::valmap_type::const_iterator item;\r
+ item = ValMap.begin();\r
+ for (unsigned i=0; i<a_iVar; ++i)\r
+ item++;\r
+\r
+ strncpy(szName, item->first.c_str(), sizeof(szName));\r
+ szName[sizeof(szName)-1] = 0;\r
+\r
+ *a_pszName = &szName[0];\r
+ *a_fVal = item->second;\r
+ return;\r
+\r
+ MU_CATCH\r
+\r
+ *a_pszName = 0;\r
+ *a_fVal = 0;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Add a custom value regognition function.\r
+*/\r
+API_EXPORT(void) mupAddValIdent(muParserHandle_t a_hParser, \r
+ muIdentFun_t a_pFun)\r
+{\r
+ MU_TRY\r
+ muParser_t* p(AsParser(a_hParser));\r
+ p->AddValIdent(a_pFun);\r
+ MU_CATCH\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Query if an error occured.\r
+\r
+ After querying the internal error bit will be reset. So a consecutive call\r
+ will return false.\r
+*/\r
+API_EXPORT(muBool_t) mupError(muParserHandle_t a_hParser)\r
+{\r
+ bool bError( AsParserTag(a_hParser)->bError );\r
+ AsParserTag(a_hParser)->bError = false;\r
+ return bError;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Reset the internal error flag.\r
+*/\r
+API_EXPORT(void) mupErrorReset(muParserHandle_t a_hParser)\r
+{\r
+ AsParserTag(a_hParser)->bError = false;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+API_EXPORT(void) mupSetErrorHandler(muParserHandle_t a_hParser, muErrorHandler_t a_pHandler)\r
+{\r
+ AsParserTag(a_hParser)->errHandler = a_pHandler;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Return the message associated with the last error.\r
+*/\r
+API_EXPORT(const muChar_t*) mupGetErrorMsg(muParserHandle_t a_hParser)\r
+{\r
+ ParserTag* const p(AsParserTag(a_hParser));\r
+ const muChar_t *pMsg = p->exc.GetMsg().c_str();\r
+\r
+ // C# explodes when pMsg is returned directly. For some reason it can't access\r
+ // the memory where the message lies directly.\r
+ sprintf(s_tmpOutBuf, "%s", pMsg);\r
+ return s_tmpOutBuf;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Return the message associated with the last error.\r
+*/\r
+API_EXPORT(const muChar_t*) mupGetErrorToken(muParserHandle_t a_hParser)\r
+{\r
+ ParserTag* const p(AsParserTag(a_hParser));\r
+ const muChar_t *pToken = p->exc.GetToken().c_str();\r
+\r
+ // C# explodes when pMsg is returned directly. For some reason it can't access\r
+ // the memory where the message lies directly.\r
+ sprintf(s_tmpOutBuf, "%s", pToken);\r
+ return s_tmpOutBuf;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Return the code associated with the last error.\r
+*/\r
+API_EXPORT(int) mupGetErrorCode(muParserHandle_t a_hParser)\r
+{\r
+ return AsParserTag(a_hParser)->exc.GetCode();\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Return the postion associated with the last error. */\r
+API_EXPORT(int) mupGetErrorPos(muParserHandle_t a_hParser)\r
+{\r
+ return (int)AsParserTag(a_hParser)->exc.GetPos();\r
+}\r
+\r
+////-----------------------------------------------------------------------------------------------------\r
+//API_EXPORT(const muChar_t*) mupGetErrorExpr(muParserHandle_t a_hParser)\r
+//{\r
+// return AsParserTag(a_hParser)->exc.GetExpr().c_str();\r
+//}\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+API_EXPORT(muFloat_t*) mupCreateVar()\r
+{\r
+ return new muFloat_t(0);\r
+}\r
+\r
+//-----------------------------------------------------------------------------------------------------\r
+API_EXPORT(void) mupReleaseVar(muFloat_t *ptr)\r
+{\r
+ delete ptr;\r
+}\r
+\r
+#endif // MUPARSER_DLL\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+#include "muParserError.h"\r
+\r
+\r
+namespace mu\r
+{\r
+ const ParserErrorMsg ParserErrorMsg::m_Instance;\r
+\r
+ //------------------------------------------------------------------------------\r
+ const ParserErrorMsg& ParserErrorMsg::Instance()\r
+ {\r
+ return m_Instance;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ string_type ParserErrorMsg::operator[](unsigned a_iIdx) const\r
+ {\r
+ return (a_iIdx<m_vErrMsg.size()) ? m_vErrMsg[a_iIdx] : string_type();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserErrorMsg::~ParserErrorMsg()\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Assignement operator is deactivated.\r
+ */\r
+ ParserErrorMsg& ParserErrorMsg::operator=(const ParserErrorMsg& )\r
+ {\r
+ assert(false);\r
+ return *this;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserErrorMsg::ParserErrorMsg(const ParserErrorMsg&)\r
+ {}\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserErrorMsg::ParserErrorMsg()\r
+ :m_vErrMsg(0)\r
+ {\r
+ m_vErrMsg.resize(ecCOUNT);\r
+\r
+ m_vErrMsg[ecUNASSIGNABLE_TOKEN] = _T("Unexpected token \"$TOK$\" found at position $POS$.");\r
+ m_vErrMsg[ecINTERNAL_ERROR] = _T("Internal error");\r
+ m_vErrMsg[ecINVALID_NAME] = _T("Invalid function-, variable- or constant name: \"$TOK$\".");\r
+ m_vErrMsg[ecINVALID_BINOP_IDENT] = _T("Invalid binary operator identifier: \"$TOK$\".");\r
+ m_vErrMsg[ecINVALID_INFIX_IDENT] = _T("Invalid infix operator identifier: \"$TOK$\".");\r
+ m_vErrMsg[ecINVALID_POSTFIX_IDENT] = _T("Invalid postfix operator identifier: \"$TOK$\".");\r
+ m_vErrMsg[ecINVALID_FUN_PTR] = _T("Invalid pointer to callback function.");\r
+ m_vErrMsg[ecEMPTY_EXPRESSION] = _T("Expression is empty.");\r
+ m_vErrMsg[ecINVALID_VAR_PTR] = _T("Invalid pointer to variable.");\r
+ m_vErrMsg[ecUNEXPECTED_OPERATOR] = _T("Unexpected operator \"$TOK$\" found at position $POS$");\r
+ m_vErrMsg[ecUNEXPECTED_EOF] = _T("Unexpected end of expression at position $POS$");\r
+ m_vErrMsg[ecUNEXPECTED_ARG_SEP] = _T("Unexpected argument separator at position $POS$");\r
+ m_vErrMsg[ecUNEXPECTED_PARENS] = _T("Unexpected parenthesis \"$TOK$\" at position $POS$");\r
+ m_vErrMsg[ecUNEXPECTED_FUN] = _T("Unexpected function \"$TOK$\" at position $POS$");\r
+ m_vErrMsg[ecUNEXPECTED_VAL] = _T("Unexpected value \"$TOK$\" found at position $POS$");\r
+ m_vErrMsg[ecUNEXPECTED_VAR] = _T("Unexpected variable \"$TOK$\" found at position $POS$");\r
+ m_vErrMsg[ecUNEXPECTED_ARG] = _T("Function arguments used without a function (position: $POS$)");\r
+ m_vErrMsg[ecMISSING_PARENS] = _T("Missing parenthesis");\r
+ m_vErrMsg[ecTOO_MANY_PARAMS] = _T("Too many parameters for function \"$TOK$\" at expression position $POS$");\r
+ m_vErrMsg[ecTOO_FEW_PARAMS] = _T("Too few parameters for function \"$TOK$\" at expression position $POS$");\r
+ m_vErrMsg[ecDIV_BY_ZERO] = _T("Divide by zero");\r
+ m_vErrMsg[ecDOMAIN_ERROR] = _T("Domain error");\r
+ m_vErrMsg[ecNAME_CONFLICT] = _T("Name conflict");\r
+ m_vErrMsg[ecOPT_PRI] = _T("Invalid value for operator priority (must be greater or equal to zero).");\r
+ m_vErrMsg[ecBUILTIN_OVERLOAD] = _T("user defined binary operator \"$TOK$\" conflicts with a built in operator.");\r
+ m_vErrMsg[ecUNEXPECTED_STR] = _T("Unexpected string token found at position $POS$.");\r
+ m_vErrMsg[ecUNTERMINATED_STRING] = _T("Unterminated string starting at position $POS$.");\r
+ m_vErrMsg[ecSTRING_EXPECTED] = _T("String function called with a non string type of argument.");\r
+ m_vErrMsg[ecVAL_EXPECTED] = _T("String value used where a numerical argument is expected.");\r
+ m_vErrMsg[ecOPRT_TYPE_CONFLICT] = _T("No suitable overload for operator \"$TOK$\" at position $POS$.");\r
+ m_vErrMsg[ecSTR_RESULT] = _T("Function result is a string.");\r
+ m_vErrMsg[ecGENERIC] = _T("Parser error.");\r
+ m_vErrMsg[ecLOCALE] = _T("Decimal separator is identic to function argument separator.");\r
+ m_vErrMsg[ecUNEXPECTED_CONDITIONAL] = _T("The \"$TOK$\" operator must be preceeded by a closing bracket.");\r
+ m_vErrMsg[ecMISSING_ELSE_CLAUSE] = _T("If-then-else operator is missing an else clause");\r
+ m_vErrMsg[ecMISPLACED_COLON] = _T("Misplaced colon at position $POS$");\r
+\r
+ #if defined(_DEBUG)\r
+ for (int i=0; i<ecCOUNT; ++i)\r
+ if (!m_vErrMsg[i].length())\r
+ assert(false);\r
+ #endif\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ //\r
+ // ParserError class\r
+ //\r
+ //---------------------------------------------------------------------------\r
+\r
+ /** \brief Default constructor. */\r
+ ParserError::ParserError()\r
+ :m_strMsg()\r
+ ,m_strFormula()\r
+ ,m_strTok()\r
+ ,m_iPos(-1)\r
+ ,m_iErrc(ecUNDEFINED)\r
+ ,m_ErrMsg(ParserErrorMsg::Instance())\r
+ {\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief This Constructor is used for internal exceptions only. \r
+ \r
+ It does not contain any information but the error code.\r
+ */\r
+ ParserError::ParserError(EErrorCodes a_iErrc) \r
+ :m_strMsg()\r
+ ,m_strFormula()\r
+ ,m_strTok()\r
+ ,m_iPos(-1)\r
+ ,m_iErrc(a_iErrc)\r
+ ,m_ErrMsg(ParserErrorMsg::Instance())\r
+ {\r
+ m_strMsg = m_ErrMsg[m_iErrc];\r
+ stringstream_type stream;\r
+ stream << (int)m_iPos;\r
+ ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());\r
+ ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Construct an error from a message text. */\r
+ ParserError::ParserError(const string_type &sMsg) \r
+ :m_ErrMsg(ParserErrorMsg::Instance())\r
+ {\r
+ Reset();\r
+ m_strMsg = sMsg;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Construct an error object. \r
+ \param [in] a_iErrc the error code.\r
+ \param [in] sTok The token string related to this error.\r
+ \param [in] sExpr The expression related to the error.\r
+ \param [in] a_iPos the position in the expression where the error occured. \r
+ */\r
+ ParserError::ParserError( EErrorCodes iErrc,\r
+ const string_type &sTok,\r
+ const string_type &sExpr,\r
+ int iPos )\r
+ :m_strMsg()\r
+ ,m_strFormula(sExpr)\r
+ ,m_strTok(sTok)\r
+ ,m_iPos(iPos)\r
+ ,m_iErrc(iErrc)\r
+ ,m_ErrMsg(ParserErrorMsg::Instance())\r
+ {\r
+ m_strMsg = m_ErrMsg[m_iErrc];\r
+ stringstream_type stream;\r
+ stream << (int)m_iPos;\r
+ ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());\r
+ ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Construct an error object. \r
+ \param [in] iErrc the error code.\r
+ \param [in] iPos the position in the expression where the error occured. \r
+ \param [in] sTok The token string related to this error.\r
+ */\r
+ ParserError::ParserError(EErrorCodes iErrc, int iPos, const string_type &sTok) \r
+ :m_strMsg()\r
+ ,m_strFormula()\r
+ ,m_strTok(sTok)\r
+ ,m_iPos(iPos)\r
+ ,m_iErrc(iErrc)\r
+ ,m_ErrMsg(ParserErrorMsg::Instance())\r
+ {\r
+ m_strMsg = m_ErrMsg[m_iErrc];\r
+ stringstream_type stream;\r
+ stream << (int)m_iPos;\r
+ ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());\r
+ ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Construct an error object. \r
+ \param [in] szMsg The error message text.\r
+ \param [in] iPos the position related to the error.\r
+ \param [in] sTok The token string related to this error.\r
+ */\r
+ ParserError::ParserError(const char_type *szMsg, int iPos, const string_type &sTok) \r
+ :m_strMsg(szMsg)\r
+ ,m_strFormula()\r
+ ,m_strTok(sTok)\r
+ ,m_iPos(iPos)\r
+ ,m_iErrc(ecGENERIC)\r
+ ,m_ErrMsg(ParserErrorMsg::Instance())\r
+ {\r
+ stringstream_type stream;\r
+ stream << (int)m_iPos;\r
+ ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());\r
+ ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Copy constructor. */\r
+ ParserError::ParserError(const ParserError &a_Obj)\r
+ :m_strMsg(a_Obj.m_strMsg)\r
+ ,m_strFormula(a_Obj.m_strFormula)\r
+ ,m_strTok(a_Obj.m_strTok)\r
+ ,m_iPos(a_Obj.m_iPos)\r
+ ,m_iErrc(a_Obj.m_iErrc)\r
+ ,m_ErrMsg(ParserErrorMsg::Instance())\r
+ {\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Assignment operator. */\r
+ ParserError& ParserError::operator=(const ParserError &a_Obj)\r
+ {\r
+ if (this==&a_Obj)\r
+ return *this;\r
+\r
+ m_strMsg = a_Obj.m_strMsg;\r
+ m_strFormula = a_Obj.m_strFormula;\r
+ m_strTok = a_Obj.m_strTok;\r
+ m_iPos = a_Obj.m_iPos;\r
+ m_iErrc = a_Obj.m_iErrc;\r
+ return *this;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ ParserError::~ParserError()\r
+ {}\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Replace all ocuurences of a substring with another string. \r
+ \param strFind The string that shall be replaced.\r
+ \param strReplaceWith The string that should be inserted instead of strFind\r
+ */\r
+ void ParserError::ReplaceSubString( string_type &strSource,\r
+ const string_type &strFind,\r
+ const string_type &strReplaceWith)\r
+ {\r
+ string_type strResult;\r
+ string_type::size_type iPos(0), iNext(0);\r
+\r
+ for(;;)\r
+ {\r
+ iNext = strSource.find(strFind, iPos);\r
+ strResult.append(strSource, iPos, iNext-iPos);\r
+\r
+ if( iNext==string_type::npos )\r
+ break;\r
+\r
+ strResult.append(strReplaceWith);\r
+ iPos = iNext + strFind.length();\r
+ } \r
+\r
+ strSource.swap(strResult);\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Reset the erro object. */\r
+ void ParserError::Reset()\r
+ {\r
+ m_strMsg = _T("");\r
+ m_strFormula = _T("");\r
+ m_strTok = _T("");\r
+ m_iPos = -1;\r
+ m_iErrc = ecUNDEFINED;\r
+ }\r
+ \r
+ //------------------------------------------------------------------------------\r
+ /** \brief Set the expression related to this error. */\r
+ void ParserError::SetFormula(const string_type &a_strFormula)\r
+ {\r
+ m_strFormula = a_strFormula;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief gets the expression related tp this error.*/\r
+ const string_type& ParserError::GetExpr() const \r
+ {\r
+ return m_strFormula;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Returns the message string for this error. */\r
+ const string_type& ParserError::GetMsg() const\r
+ {\r
+ return m_strMsg;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Return the formula position related to the error. \r
+\r
+ If the error is not related to a distinct position this will return -1\r
+ */\r
+ std::size_t ParserError::GetPos() const\r
+ {\r
+ return m_iPos;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Return string related with this token (if available). */\r
+ const string_type& ParserError::GetToken() const\r
+ {\r
+ return m_strTok;\r
+ }\r
+\r
+ //------------------------------------------------------------------------------\r
+ /** \brief Return the error code. */\r
+ EErrorCodes ParserError::GetCode() const\r
+ {\r
+ return m_iErrc;\r
+ }\r
+} // namespace mu\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2011 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#include "muParserInt.h"\r
+\r
+#include <cmath>\r
+#include <algorithm>\r
+#include <numeric>\r
+\r
+using namespace std;\r
+\r
+/** \file\r
+ \brief Implementation of a parser using integer value.\r
+*/\r
+\r
+/** \brief Namespace for mathematical applications. */\r
+namespace mu\r
+{\r
+value_type ParserInt::Abs(value_type v) { return (value_type)Round(fabs((double)v)); }\r
+value_type ParserInt::Sign(value_type v) { return (Round(v)<0) ? -1 : (Round(v)>0) ? 1 : 0; }\r
+value_type ParserInt::Ite(value_type v1, \r
+ value_type v2, \r
+ value_type v3) { return (Round(v1)==1) ? Round(v2) : Round(v3); }\r
+value_type ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); }\r
+value_type ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); }\r
+value_type ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); }\r
+value_type ParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); }\r
+value_type ParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); }\r
+value_type ParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); }\r
+value_type ParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); }\r
+value_type ParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); }\r
+value_type ParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); }\r
+value_type ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); }\r
+value_type ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); }\r
+value_type ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); }\r
+value_type ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); }\r
+value_type ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); }\r
+value_type ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); }\r
+value_type ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); }\r
+value_type ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); }\r
+value_type ParserInt::Not(value_type v) { return !Round(v); }\r
+\r
+value_type ParserInt::Pow(value_type v1, value_type v2) \r
+{ \r
+ return std::pow((double)Round(v1), (double)Round(v2)); \r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+// Unary operator Callbacks: Infix operators\r
+value_type ParserInt::UnaryMinus(value_type v) \r
+{ \r
+ return -Round(v); \r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+value_type ParserInt::Sum(const value_type* a_afArg, int a_iArgc)\r
+{ \r
+ if (!a_iArgc) \r
+ throw ParserError(_T("too few arguments for function sum."));\r
+\r
+ value_type fRes=0;\r
+ for (int i=0; i<a_iArgc; ++i) \r
+ fRes += a_afArg[i];\r
+\r
+ return fRes;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+value_type ParserInt::Min(const value_type* a_afArg, int a_iArgc)\r
+{ \r
+ if (!a_iArgc) \r
+ throw ParserError( _T("too few arguments for function min.") );\r
+\r
+ value_type fRes=a_afArg[0];\r
+ for (int i=0; i<a_iArgc; ++i) \r
+ fRes = std::min(fRes, a_afArg[i]);\r
+\r
+ return fRes;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+value_type ParserInt::Max(const value_type* a_afArg, int a_iArgc)\r
+{ \r
+ if (!a_iArgc) \r
+ throw ParserError(_T("too few arguments for function min."));\r
+\r
+ value_type fRes=a_afArg[0];\r
+ for (int i=0; i<a_iArgc; ++i) \r
+ fRes = std::max(fRes, a_afArg[i]);\r
+\r
+ return fRes;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+// Default value recognition callback\r
+int ParserInt::IsVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)\r
+{\r
+ string_type buf(a_szExpr);\r
+ std::size_t pos = buf.find_first_not_of(_T("0123456789"));\r
+\r
+ if (pos==std::string::npos)\r
+ return 0;\r
+\r
+ stringstream_type stream( buf.substr(0, pos ) );\r
+ int iVal(0);\r
+\r
+ stream >> iVal;\r
+ if (stream.fail())\r
+ return 0;\r
+ \r
+ stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading\r
+ if (stream.fail())\r
+ iEnd = stream.str().length(); \r
+\r
+ if (iEnd==(stringstream_type::pos_type)-1)\r
+ return 0;\r
+\r
+ *a_iPos += (int)iEnd;\r
+ *a_fVal = (value_type)iVal;\r
+ return 1;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Check a given position in the expression for the presence of \r
+ a hex value. \r
+ \param a_szExpr Pointer to the expression string\r
+ \param [in/out] a_iPos Pointer to an interger value holding the current parsing \r
+ position in the expression.\r
+ \param [out] a_fVal Pointer to the position where the detected value shall be stored.\r
+\r
+ Hey values must be prefixed with "0x" in order to be detected properly.\r
+*/\r
+int ParserInt::IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)\r
+{\r
+ if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') ) \r
+ return 0;\r
+\r
+ unsigned iVal(0);\r
+\r
+ // New code based on streams for UNICODE compliance:\r
+ stringstream_type::pos_type nPos(0);\r
+ stringstream_type ss(a_szExpr + 2);\r
+ ss >> std::hex >> iVal;\r
+ nPos = ss.tellg();\r
+\r
+ if (nPos==(stringstream_type::pos_type)0)\r
+ return 1;\r
+\r
+ *a_iPos += (int)(2 + nPos);\r
+ *a_fVal = (value_type)iVal;\r
+ return 1;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+int ParserInt::IsBinVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)\r
+{\r
+ if (a_szExpr[0]!='#') \r
+ return 0;\r
+\r
+ unsigned iVal(0), \r
+ iBits(sizeof(iVal)*8),\r
+ i(0);\r
+\r
+ for (i=0; (a_szExpr[i+1]=='0' || a_szExpr[i+1]=='1') && i<iBits; ++i)\r
+ iVal |= (int)(a_szExpr[i+1]=='1') << ((iBits-1)-i);\r
+\r
+ if (i==0) \r
+ return 0;\r
+\r
+ if (i==iBits)\r
+ throw exception_type(_T("Binary to integer conversion error (overflow)."));\r
+\r
+ *a_fVal = (unsigned)(iVal >> (iBits-i) );\r
+ *a_iPos += i+1;\r
+\r
+ return 1;\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Constructor. \r
+\r
+ Call ParserBase class constructor and trigger Function, Operator and Constant initialization.\r
+*/\r
+ParserInt::ParserInt()\r
+ :ParserBase()\r
+{\r
+ AddValIdent(IsVal); // lowest priority\r
+ AddValIdent(IsBinVal);\r
+ AddValIdent(IsHexVal); // highest priority\r
+\r
+ InitCharSets();\r
+ InitFun();\r
+ InitOprt();\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+void ParserInt::InitConst()\r
+{\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+void ParserInt::InitCharSets()\r
+{\r
+ DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") );\r
+ DefineOprtChars( _T("+-*^/?<>=!%&|~'_") );\r
+ DefineInfixOprtChars( _T("/+-*^?<>=!%&|~'_") );\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Initialize the default functions. */\r
+void ParserInt::InitFun()\r
+{\r
+ DefineFun( _T("sign"), Sign);\r
+ DefineFun( _T("abs"), Abs);\r
+ DefineFun( _T("if"), Ite);\r
+ DefineFun( _T("sum"), Sum);\r
+ DefineFun( _T("min"), Min);\r
+ DefineFun( _T("max"), Max);\r
+}\r
+\r
+//---------------------------------------------------------------------------\r
+/** \brief Initialize operators. */\r
+void ParserInt::InitOprt()\r
+{\r
+ // disable all built in operators, not all of them usefull for integer numbers\r
+ // (they don't do rounding of values)\r
+ EnableBuiltInOprt(false);\r
+\r
+ // Disable all built in operators, they wont work with integer numbers\r
+ // since they are designed for floating point numbers\r
+ DefineInfixOprt( _T("-"), UnaryMinus);\r
+ DefineInfixOprt( _T("!"), Not);\r
+\r
+ DefineOprt( _T("&"), LogAnd, prLOGIC);\r
+ DefineOprt( _T("|"), LogOr, prLOGIC);\r
+ DefineOprt( _T("&&"), And, prLOGIC);\r
+ DefineOprt( _T("||"), Or, prLOGIC);\r
+\r
+ DefineOprt( _T("<"), Less, prCMP);\r
+ DefineOprt( _T(">"), Greater, prCMP);\r
+ DefineOprt( _T("<="), LessEq, prCMP);\r
+ DefineOprt( _T(">="), GreaterEq, prCMP);\r
+ DefineOprt( _T("=="), Equal, prCMP);\r
+ DefineOprt( _T("!="), NotEqual, prCMP);\r
+\r
+ DefineOprt( _T("+"), Add, prADD_SUB);\r
+ DefineOprt( _T("-"), Sub, prADD_SUB);\r
+\r
+ DefineOprt( _T("*"), Mul, prMUL_DIV);\r
+ DefineOprt( _T("/"), Div, prMUL_DIV);\r
+ DefineOprt( _T("%"), Mod, prMUL_DIV);\r
+\r
+ DefineOprt( _T("^"), Pow, prPOW, oaRIGHT);\r
+ DefineOprt( _T(">>"), Shr, prMUL_DIV+1);\r
+ DefineOprt( _T("<<"), Shl, prMUL_DIV+1);\r
+}\r
+\r
+} // namespace mu\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+\r
+#include "muParserTest.h"\r
+\r
+#include <cstdio>\r
+#include <cmath>\r
+#include <iostream>\r
+#include <limits>\r
+\r
+#define PARSER_CONST_PI 3.141592653589793238462643\r
+#define PARSER_CONST_E 2.718281828459045235360287\r
+\r
+using namespace std;\r
+\r
+/** \file\r
+ \brief This file contains the implementation of parser test cases.\r
+*/\r
+\r
+namespace mu\r
+{\r
+ namespace Test\r
+ {\r
+ int ParserTester::c_iCount = 0;\r
+\r
+ //---------------------------------------------------------------------------------------------\r
+ ParserTester::ParserTester()\r
+ :m_vTestFun()\r
+ {\r
+ AddTest(&ParserTester::TestNames);\r
+ AddTest(&ParserTester::TestSyntax);\r
+ AddTest(&ParserTester::TestPostFix);\r
+ AddTest(&ParserTester::TestInfixOprt);\r
+ AddTest(&ParserTester::TestVarConst);\r
+ AddTest(&ParserTester::TestMultiArg);\r
+ AddTest(&ParserTester::TestExpression);\r
+ AddTest(&ParserTester::TestIfThenElse);\r
+ AddTest(&ParserTester::TestInterface);\r
+ AddTest(&ParserTester::TestBinOprt);\r
+ AddTest(&ParserTester::TestException);\r
+ AddTest(&ParserTester::TestStrArg);\r
+\r
+ ParserTester::c_iCount = 0;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------------------------\r
+ int ParserTester::IsHexVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal)\r
+ {\r
+ if (a_szExpr[1]==0 || (a_szExpr[0]!='0' || a_szExpr[1]!='x') ) \r
+ return 0;\r
+\r
+ unsigned iVal(0);\r
+\r
+ // New code based on streams for UNICODE compliance:\r
+ stringstream_type::pos_type nPos(0);\r
+ stringstream_type ss(a_szExpr + 2);\r
+ ss >> std::hex >> iVal;\r
+ nPos = ss.tellg();\r
+\r
+ if (nPos==(stringstream_type::pos_type)0)\r
+ return 1;\r
+\r
+ *a_iPos += (int)(2 + nPos);\r
+ *a_fVal = (value_type)iVal;\r
+ return 1;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------------------------\r
+ int ParserTester::TestInterface()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing member functions...");\r
+ \r
+ // Test RemoveVar\r
+ value_type afVal[3] = {1,2,3};\r
+ Parser p;\r
+ \r
+ try\r
+ {\r
+ p.DefineVar( _T("a"), &afVal[0]);\r
+ p.DefineVar( _T("b"), &afVal[1]);\r
+ p.DefineVar( _T("c"), &afVal[2]);\r
+ p.SetExpr( _T("a+b+c") );\r
+ p.Eval();\r
+ }\r
+ catch(...)\r
+ {\r
+ iStat += 1; // this is not supposed to happen \r
+ }\r
+\r
+ try\r
+ {\r
+ p.RemoveVar( _T("c") );\r
+ p.Eval();\r
+ iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted...\r
+ }\r
+ catch(...)\r
+ {\r
+ // failure is expected...\r
+ }\r
+\r
+ if (iStat==0) \r
+ mu::console() << _T("passed") << endl;\r
+ else \r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------------------------\r
+ int ParserTester::TestStrArg()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing string arguments...");\r
+ \r
+ iStat += EqnTest(_T("valueof(\"\")"), 123, true); // empty string arguments caused a crash\r
+ iStat += EqnTest(_T("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true);\r
+ iStat += EqnTest(_T("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true);\r
+ // use in expressions with variables\r
+ iStat += EqnTest(_T("a*(atof(\"10\")-b)"), 8, true);\r
+ iStat += EqnTest(_T("a-(atof(\"10\")*b)"), -19, true);\r
+ // string + numeric arguments\r
+ iStat += EqnTest(_T("strfun1(\"100\")"), 100, true);\r
+ iStat += EqnTest(_T("strfun2(\"100\",1)"), 101, true);\r
+ iStat += EqnTest(_T("strfun3(\"99\",1,2)"), 102, true);\r
+\r
+ if (iStat==0)\r
+ mu::console() << _T("passed") << endl;\r
+ else \r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------------------------\r
+ int ParserTester::TestBinOprt()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing binary operators...");\r
+ \r
+ // built in operators\r
+ // xor operator\r
+ //iStat += EqnTest(_T("1 xor 2"), 3, true); \r
+ //iStat += EqnTest(_T("a xor b"), 3, true); // with a=1 and b=2\r
+ //iStat += EqnTest(_T("1 xor 2 xor 3"), 0, true); \r
+ //iStat += EqnTest(_T("a xor b xor 3"), 0, true); // with a=1 and b=2\r
+ //iStat += EqnTest(_T("a xor b xor c"), 0, true); // with a=1 and b=2\r
+ //iStat += EqnTest(_T("(1 xor 2) xor 3"), 0, true); \r
+ //iStat += EqnTest(_T("(a xor b) xor c"), 0, true); // with a=1 and b=2\r
+ //iStat += EqnTest(_T("(a) xor (b) xor c"), 0, true); // with a=1 and b=2\r
+ //iStat += EqnTest(_T("1 or 2"), 3, true); \r
+ //iStat += EqnTest(_T("a or b"), 3, true); // with a=1 and b=2\r
+ iStat += EqnTest(_T("a++b"), 3, true);\r
+ iStat += EqnTest(_T("a ++ b"), 3, true);\r
+ iStat += EqnTest(_T("1++2"), 3, true);\r
+ iStat += EqnTest(_T("1 ++ 2"), 3, true);\r
+ iStat += EqnTest(_T("a add b"), 3, true);\r
+ iStat += EqnTest(_T("1 add 2"), 3, true);\r
+ iStat += EqnTest(_T("a<b"), 1, true);\r
+ iStat += EqnTest(_T("b>a"), 1, true);\r
+ iStat += EqnTest(_T("a>a"), 0, true);\r
+ iStat += EqnTest(_T("a<a"), 0, true);\r
+ iStat += EqnTest(_T("a>a"), 0, true);\r
+ iStat += EqnTest(_T("a<=a"), 1, true);\r
+ iStat += EqnTest(_T("a<=b"), 1, true);\r
+ iStat += EqnTest(_T("b<=a"), 0, true);\r
+ iStat += EqnTest(_T("a>=a"), 1, true);\r
+ iStat += EqnTest(_T("b>=a"), 1, true);\r
+ iStat += EqnTest(_T("a>=b"), 0, true);\r
+\r
+ // Test logical operators, expecially if user defined "&" and the internal "&&" collide\r
+ iStat += EqnTest(_T("1 && 1"), 1, true); \r
+ iStat += EqnTest(_T("1 && 0"), 0, true); \r
+ iStat += EqnTest(_T("(a<b) && (b>a)"), 1, true); \r
+ iStat += EqnTest(_T("(a<b) && (a>b)"), 0, true); \r
+ //iStat += EqnTest(_T("12 and 255"), 12, true); \r
+ //iStat += EqnTest(_T("12 and 0"), 0, true); \r
+ iStat += EqnTest(_T("12 & 255"), 12, true); \r
+ iStat += EqnTest(_T("12 & 0"), 0, true); \r
+ iStat += EqnTest(_T("12&255"), 12, true); \r
+ iStat += EqnTest(_T("12&0"), 0, true); \r
+\r
+ // Assignement operator\r
+ iStat += EqnTest(_T("a = b"), 2, true); \r
+ iStat += EqnTest(_T("a = sin(b)"), 0.909297, true); \r
+ iStat += EqnTest(_T("a = 1+sin(b)"), 1.909297, true);\r
+ iStat += EqnTest(_T("(a=b)*2"), 4, true);\r
+ iStat += EqnTest(_T("2*(a=b)"), 4, true);\r
+ iStat += EqnTest(_T("2*(a=b+1)"), 6, true);\r
+ iStat += EqnTest(_T("(a=b+1)*2"), 6, true);\r
+\r
+ iStat += EqnTest(_T("2^2^3"), 256, true); \r
+ iStat += EqnTest(_T("1/2/3"), 1.0/6.0, true); \r
+\r
+ // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3\r
+ iStat += EqnTest(_T("3+4*2/(1-5)^2^3"), 3.0001220703125, true); \r
+\r
+ // Test user defined binary operators\r
+ iStat += EqnTestInt(_T("1 | 2"), 3, true); \r
+ iStat += EqnTestInt(_T("1 || 2"), 1, true); \r
+ iStat += EqnTestInt(_T("123 & 456"), 72, true); \r
+ iStat += EqnTestInt(_T("(123 & 456) % 10"), 2, true);\r
+ iStat += EqnTestInt(_T("1 && 0"), 0, true); \r
+ iStat += EqnTestInt(_T("123 && 456"), 1, true); \r
+ iStat += EqnTestInt(_T("1 << 3"), 8, true); \r
+ iStat += EqnTestInt(_T("8 >> 3"), 1, true); \r
+ iStat += EqnTestInt(_T("9 / 4"), 2, true); \r
+ iStat += EqnTestInt(_T("9 % 4"), 1, true); \r
+ iStat += EqnTestInt(_T("if(5%2,1,0)"), 1, true);\r
+ iStat += EqnTestInt(_T("if(4%2,1,0)"), 0, true);\r
+ iStat += EqnTestInt(_T("-10+1"), -9, true);\r
+ iStat += EqnTestInt(_T("1+2*3"), 7, true);\r
+ iStat += EqnTestInt(_T("const1 != const2"), 1, true);\r
+ iStat += EqnTestInt(_T("const1 != const2"), 0, false);\r
+ iStat += EqnTestInt(_T("const1 == const2"), 0, true);\r
+ iStat += EqnTestInt(_T("const1 == 1"), 1, true);\r
+ iStat += EqnTestInt(_T("10*(const1 == 1)"), 10, true);\r
+ iStat += EqnTestInt(_T("2*(const1 | const2)"), 6, true);\r
+ iStat += EqnTestInt(_T("2*(const1 | const2)"), 7, false);\r
+ iStat += EqnTestInt(_T("const1 < const2"), 1, true);\r
+ iStat += EqnTestInt(_T("const2 > const1"), 1, true);\r
+ iStat += EqnTestInt(_T("const1 <= 1"), 1, true);\r
+ iStat += EqnTestInt(_T("const2 >= 2"), 1, true);\r
+ iStat += EqnTestInt(_T("2*(const1 + const2)"), 6, true);\r
+ iStat += EqnTestInt(_T("2*(const1 - const2)"), -2, true);\r
+ iStat += EqnTestInt(_T("a != b"), 1, true);\r
+ iStat += EqnTestInt(_T("a != b"), 0, false);\r
+ iStat += EqnTestInt(_T("a == b"), 0, true);\r
+ iStat += EqnTestInt(_T("a == 1"), 1, true);\r
+ iStat += EqnTestInt(_T("10*(a == 1)"), 10, true);\r
+ iStat += EqnTestInt(_T("2*(a | b)"), 6, true);\r
+ iStat += EqnTestInt(_T("2*(a | b)"), 7, false);\r
+ iStat += EqnTestInt(_T("a < b"), 1, true);\r
+ iStat += EqnTestInt(_T("b > a"), 1, true);\r
+ iStat += EqnTestInt(_T("a <= 1"), 1, true);\r
+ iStat += EqnTestInt(_T("b >= 2"), 1, true);\r
+ iStat += EqnTestInt(_T("2*(a + b)"), 6, true);\r
+ iStat += EqnTestInt(_T("2*(a - b)"), -2, true);\r
+ iStat += EqnTestInt(_T("a + (a << b)"), 5, true);\r
+ iStat += EqnTestInt(_T("-2^2"), -4, true);\r
+ iStat += EqnTestInt(_T("3--a"), 4, true);\r
+ iStat += EqnTestInt(_T("3+-3^2"), -6, true);\r
+\r
+ // Test reading of hex values:\r
+ iStat += EqnTestInt(_T("0xff"), 255, true);\r
+ iStat += EqnTestInt(_T("10+0xff"), 265, true);\r
+ iStat += EqnTestInt(_T("0xff+10"), 265, true);\r
+ iStat += EqnTestInt(_T("10*0xff"), 2550, true);\r
+ iStat += EqnTestInt(_T("0xff*10"), 2550, true);\r
+ iStat += EqnTestInt(_T("10+0xff+1"), 266, true);\r
+ iStat += EqnTestInt(_T("1+0xff+10"), 266, true);\r
+\r
+// incorrect: '^' is yor here, not power\r
+// iStat += EqnTestInt("-(1+2)^2", -9, true);\r
+// iStat += EqnTestInt("-1^3", -1, true); \r
+\r
+ // Test precedence\r
+ // a=1, b=2, c=3\r
+ iStat += EqnTestInt(_T("a + b * c"), 7, true);\r
+ iStat += EqnTestInt(_T("a * b + c"), 5, true);\r
+ iStat += EqnTestInt(_T("a<b && b>10"), 0, true);\r
+ iStat += EqnTestInt(_T("a<b && b<10"), 1, true);\r
+\r
+ iStat += EqnTestInt(_T("a + b << c"), 17, true);\r
+ iStat += EqnTestInt(_T("a << b + c"), 7, true);\r
+ iStat += EqnTestInt(_T("c * b < a"), 0, true);\r
+ iStat += EqnTestInt(_T("c * b == 6 * a"), 1, true);\r
+ iStat += EqnTestInt(_T("2^2^3"), 256, true); \r
+\r
+\r
+ if (iStat==0)\r
+ mu::console() << _T("passed") << endl;\r
+ else \r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------------------------\r
+ /** \brief Check muParser name restriction enforcement. */\r
+ int ParserTester::TestNames()\r
+ {\r
+ int iStat= 0,\r
+ iErr = 0;\r
+\r
+ mu::console() << "testing name restriction enforcement...";\r
+ \r
+ Parser p;\r
+\r
+ #define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG) \\r
+ iErr = 0; \\r
+ ParserTester::c_iCount++; \\r
+ try \\r
+ { \\r
+ p.Define##DOMAIN(EXPR, ARG); \\r
+ } \\r
+ catch(Parser::exception_type&) \\r
+ { \\r
+ iErr = (FAIL==false) ? 0 : 1; \\r
+ } \\r
+ iStat += iErr; \r
+ \r
+ // constant names\r
+ PARSER_THROWCHECK(Const, false, _T("0a"), 1)\r
+ PARSER_THROWCHECK(Const, false, _T("9a"), 1)\r
+ PARSER_THROWCHECK(Const, false, _T("+a"), 1)\r
+ PARSER_THROWCHECK(Const, false, _T("-a"), 1)\r
+ PARSER_THROWCHECK(Const, false, _T("a-"), 1)\r
+ PARSER_THROWCHECK(Const, false, _T("a*"), 1)\r
+ PARSER_THROWCHECK(Const, false, _T("a?"), 1)\r
+ PARSER_THROWCHECK(Const, true, _T("a"), 1)\r
+ PARSER_THROWCHECK(Const, true, _T("a_min"), 1)\r
+ PARSER_THROWCHECK(Const, true, _T("a_min0"), 1)\r
+ PARSER_THROWCHECK(Const, true, _T("a_min9"), 1)\r
+ // variable names\r
+ value_type a;\r
+ p.ClearConst();\r
+ PARSER_THROWCHECK(Var, false, _T("123abc"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("9a"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("0a"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("+a"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("-a"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("?a"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("!a"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("a+"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("a-"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("a*"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("a?"), &a)\r
+ PARSER_THROWCHECK(Var, true, _T("a"), &a)\r
+ PARSER_THROWCHECK(Var, true, _T("a_min"), &a)\r
+ PARSER_THROWCHECK(Var, true, _T("a_min0"), &a)\r
+ PARSER_THROWCHECK(Var, true, _T("a_min9"), &a)\r
+ PARSER_THROWCHECK(Var, false, _T("a_min9"), 0)\r
+ // Postfix operators\r
+ // fail\r
+ PARSER_THROWCHECK(PostfixOprt, false, _T("(k"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, false, _T("9+"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, false, _T("+"), 0)\r
+ // pass\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("-a"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("?a"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("_"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("#"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("&&"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("||"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("&"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("|"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("++"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("--"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("?>"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1)\r
+ PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1)\r
+ // Binary operator\r
+ // The following must fail with builtin operators activated\r
+ // p.EnableBuiltInOp(true); -> this is the default\r
+ p.ClearPostfixOprt();\r
+ PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, false, _T("^"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, false, _T("&&"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, false, _T("||"), f1of2)\r
+ // without activated built in operators it should work\r
+ p.EnableBuiltInOprt(false);\r
+ PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, true, _T("^"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, true, _T("&&"), f1of2)\r
+ PARSER_THROWCHECK(Oprt, true, _T("||"), f1of2)\r
+ #undef PARSER_THROWCHECK\r
+\r
+ if (iStat==0) \r
+ mu::console() << _T("passed") << endl;\r
+ else \r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::TestSyntax()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing syntax engine...");\r
+\r
+ iStat += ThrowTest(_T("1,"), ecUNEXPECTED_EOF); // incomplete hex definition\r
+ iStat += ThrowTest(_T("a,"), ecUNEXPECTED_EOF); // incomplete hex definition\r
+ iStat += ThrowTest(_T("sin(8),"), ecUNEXPECTED_EOF); // incomplete hex definition\r
+ iStat += ThrowTest(_T("(sin(8)),"), ecUNEXPECTED_EOF); // incomplete hex definition\r
+ iStat += ThrowTest(_T("a{m},"), ecUNEXPECTED_EOF); // incomplete hex definition\r
+\r
+ iStat += EqnTest(_T("(1+ 2*a)"), 3, true); // Spaces within formula\r
+ iStat += EqnTest(_T("sqrt((4))"), 2, true); // Multiple brackets\r
+ iStat += EqnTest(_T("sqrt((2)+2)"), 2, true);// Multiple brackets\r
+ iStat += EqnTest(_T("sqrt(2+(2))"), 2, true);// Multiple brackets\r
+ iStat += EqnTest(_T("sqrt(a+(3))"), 2, true);// Multiple brackets\r
+ iStat += EqnTest(_T("sqrt((3)+a)"), 2, true);// Multiple brackets\r
+ iStat += EqnTest(_T("order(1,2)"), 1, true); // May not cause name collision with operator "or"\r
+ iStat += EqnTest(_T("(2+"), 0, false); // missing closing bracket \r
+ iStat += EqnTest(_T("2++4"), 0, false); // unexpected operator\r
+ iStat += EqnTest(_T("2+-4"), 0, false); // unexpected operator\r
+ iStat += EqnTest(_T("(2+)"), 0, false); // unexpected closing bracket\r
+ iStat += EqnTest(_T("--2"), 0, false); // double sign\r
+ iStat += EqnTest(_T("ksdfj"), 0, false); // unknown token\r
+ iStat += EqnTest(_T("()"), 0, false); // empty bracket without a function\r
+ iStat += EqnTest(_T("5+()"), 0, false); // empty bracket without a function\r
+ iStat += EqnTest(_T("sin(cos)"), 0, false); // unexpected function\r
+ iStat += EqnTest(_T("5t6"), 0, false); // unknown token\r
+ iStat += EqnTest(_T("5 t 6"), 0, false); // unknown token\r
+ iStat += EqnTest(_T("8*"), 0, false); // unexpected end of formula\r
+ iStat += EqnTest(_T(",3"), 0, false); // unexpected comma\r
+ iStat += EqnTest(_T("3,5"), 0, false); // unexpected comma\r
+ iStat += EqnTest(_T("sin(8,8)"), 0, false); // too many function args\r
+ iStat += EqnTest(_T("(7,8)"), 0, false); // too many function args\r
+ iStat += EqnTest(_T("sin)"), 0, false); // unexpected closing bracket\r
+ iStat += EqnTest(_T("a)"), 0, false); // unexpected closing bracket\r
+ iStat += EqnTest(_T("pi)"), 0, false); // unexpected closing bracket\r
+ iStat += EqnTest(_T("sin(())"), 0, false); // unexpected closing bracket\r
+ iStat += EqnTest(_T("sin()"), 0, false); // unexpected closing bracket\r
+\r
+ if (iStat==0)\r
+ mu::console() << _T("passed") << endl;\r
+ else \r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::TestVarConst()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing variable/constant detection...");\r
+\r
+ // Test if the result changes when a variable changes\r
+ iStat += EqnTestWithVarChange( _T("a"), 1, 1, 2, 2 );\r
+ iStat += EqnTestWithVarChange( _T("2*a"), 2, 4, 3, 6 );\r
+\r
+ // distinguish constants with same basename\r
+ iStat += EqnTest( _T("const"), 1, true);\r
+ iStat += EqnTest( _T("const1"), 2, true);\r
+ iStat += EqnTest( _T("const2"), 3, true);\r
+ iStat += EqnTest( _T("2*const"), 2, true);\r
+ iStat += EqnTest( _T("2*const1"), 4, true);\r
+ iStat += EqnTest( _T("2*const2"), 6, true);\r
+ iStat += EqnTest( _T("2*const+1"), 3, true);\r
+ iStat += EqnTest( _T("2*const1+1"), 5, true);\r
+ iStat += EqnTest( _T("2*const2+1"), 7, true);\r
+ iStat += EqnTest( _T("const"), 0, false);\r
+ iStat += EqnTest( _T("const1"), 0, false);\r
+ iStat += EqnTest( _T("const2"), 0, false);\r
+\r
+ // distinguish variables with same basename\r
+ iStat += EqnTest( _T("a"), 1, true);\r
+ iStat += EqnTest( _T("aa"), 2, true);\r
+ iStat += EqnTest( _T("2*a"), 2, true);\r
+ iStat += EqnTest( _T("2*aa"), 4, true);\r
+ iStat += EqnTest( _T("2*a-1"), 1, true);\r
+ iStat += EqnTest( _T("2*aa-1"), 3, true);\r
+\r
+ // custom value recognition\r
+ iStat += EqnTest( _T("0xff"), 255, true);\r
+ iStat += EqnTest( _T("0x97 + 0xff"), 406, true);\r
+\r
+ // Finally test querying of used variables\r
+ try\r
+ {\r
+ int idx;\r
+ mu::Parser p;\r
+ mu::value_type vVarVal[] = { 1, 2, 3, 4, 5};\r
+ p.DefineVar( _T("a"), &vVarVal[0]);\r
+ p.DefineVar( _T("b"), &vVarVal[1]);\r
+ p.DefineVar( _T("c"), &vVarVal[2]);\r
+ p.DefineVar( _T("d"), &vVarVal[3]);\r
+ p.DefineVar( _T("e"), &vVarVal[4]);\r
+\r
+ // Test lookup of defined variables\r
+ // 4 used variables\r
+ p.SetExpr( _T("a+b+c+d") );\r
+ mu::varmap_type UsedVar = p.GetUsedVar();\r
+ int iCount = (int)UsedVar.size();\r
+ if (iCount!=4) \r
+ throw false;\r
+ \r
+ // the next check will fail if the parser \r
+ // erroneousely creates new variables internally\r
+ if (p.GetVar().size()!=5)\r
+ throw false;\r
+\r
+ mu::varmap_type::const_iterator item = UsedVar.begin();\r
+ for (idx=0; item!=UsedVar.end(); ++item)\r
+ {\r
+ if (&vVarVal[idx++]!=item->second) \r
+ throw false;\r
+ }\r
+\r
+ // Test lookup of undefined variables\r
+ p.SetExpr( _T("undef1+undef2+undef3") );\r
+ UsedVar = p.GetUsedVar();\r
+ iCount = (int)UsedVar.size();\r
+ if (iCount!=3) \r
+ throw false;\r
+\r
+ // the next check will fail if the parser \r
+ // erroneousely creates new variables internally\r
+ if (p.GetVar().size()!=5)\r
+ throw false;\r
+\r
+ for (item = UsedVar.begin(); item!=UsedVar.end(); ++item)\r
+ {\r
+ if (item->second!=0) \r
+ throw false; // all pointers to undefined variables must be null\r
+ }\r
+\r
+ // 1 used variables\r
+ p.SetExpr( _T("a+b") );\r
+ UsedVar = p.GetUsedVar();\r
+ iCount = (int)UsedVar.size();\r
+ if (iCount!=2) throw false;\r
+ item = UsedVar.begin();\r
+ for (idx=0; item!=UsedVar.end(); ++item)\r
+ if (&vVarVal[idx++]!=item->second) throw false;\r
+\r
+ }\r
+ catch(...)\r
+ {\r
+ iStat += 1;\r
+ }\r
+\r
+ if (iStat==0) \r
+ mu::console() << _T("passed") << endl;\r
+ else\r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::TestMultiArg()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing multiarg functions...");\r
+ \r
+ // Compound expressions\r
+ iStat += EqnTest( _T("1,2,3"), 3, true);\r
+ iStat += EqnTest( _T("a,b,c"), 3, true);\r
+ iStat += EqnTest( _T("a=10,b=20,c=a*b"), 200, true);\r
+ iStat += EqnTest( _T("1,\n2,\n3"), 3, true);\r
+ iStat += EqnTest( _T("a,\nb,\nc"), 3, true);\r
+ iStat += EqnTest( _T("a=10,\nb=20,\nc=a*b"), 200, true);\r
+ iStat += EqnTest( _T("1,\r\n2,\r\n3"), 3, true);\r
+ iStat += EqnTest( _T("a,\r\nb,\r\nc"), 3, true);\r
+ iStat += EqnTest( _T("a=10,\r\nb=20,\r\nc=a*b"), 200, true);\r
+\r
+ // picking the right argument\r
+ iStat += EqnTest( _T("f1of1(1)"), 1, true);\r
+ iStat += EqnTest( _T("f1of2(1, 2)"), 1, true);\r
+ iStat += EqnTest( _T("f2of2(1, 2)"), 2, true);\r
+ iStat += EqnTest( _T("f1of3(1, 2, 3)"), 1, true);\r
+ iStat += EqnTest( _T("f2of3(1, 2, 3)"), 2, true);\r
+ iStat += EqnTest( _T("f3of3(1, 2, 3)"), 3, true);\r
+ iStat += EqnTest( _T("f1of4(1, 2, 3, 4)"), 1, true);\r
+ iStat += EqnTest( _T("f2of4(1, 2, 3, 4)"), 2, true);\r
+ iStat += EqnTest( _T("f3of4(1, 2, 3, 4)"), 3, true);\r
+ iStat += EqnTest( _T("f4of4(1, 2, 3, 4)"), 4, true);\r
+ iStat += EqnTest( _T("f1of5(1, 2, 3, 4, 5)"), 1, true);\r
+ iStat += EqnTest( _T("f2of5(1, 2, 3, 4, 5)"), 2, true);\r
+ iStat += EqnTest( _T("f3of5(1, 2, 3, 4, 5)"), 3, true);\r
+ iStat += EqnTest( _T("f4of5(1, 2, 3, 4, 5)"), 4, true);\r
+ iStat += EqnTest( _T("f5of5(1, 2, 3, 4, 5)"), 5, true);\r
+ // Too few arguments / Too many arguments\r
+ iStat += EqnTest( _T("1+ping()"), 11, true);\r
+ iStat += EqnTest( _T("ping()+1"), 11, true);\r
+ iStat += EqnTest( _T("2*ping()"), 20, true);\r
+ iStat += EqnTest( _T("ping()*2"), 20, true);\r
+ iStat += EqnTest( _T("ping(1,2)"), 0, false);\r
+ iStat += EqnTest( _T("1+ping(1,2)"), 0, false);\r
+ iStat += EqnTest( _T("f1of1(1,2)"), 0, false);\r
+ iStat += EqnTest( _T("f1of1()"), 0, false);\r
+ iStat += EqnTest( _T("f1of2(1, 2, 3)"), 0, false);\r
+ iStat += EqnTest( _T("f1of2(1)"), 0, false);\r
+ iStat += EqnTest( _T("f1of3(1, 2, 3, 4)"), 0, false);\r
+ iStat += EqnTest( _T("f1of3(1)"), 0, false);\r
+ iStat += EqnTest( _T("f1of4(1, 2, 3, 4, 5)"), 0, false);\r
+ iStat += EqnTest( _T("f1of4(1)"), 0, false);\r
+ iStat += EqnTest( _T("(1,2,3)"), 0, false);\r
+ iStat += EqnTest( _T("1,2,3"), 0, false);\r
+ iStat += EqnTest( _T("(1*a,2,3)"), 0, false);\r
+ iStat += EqnTest( _T("1,2*a,3"), 0, false);\r
+ \r
+ // correct calculation of arguments\r
+ iStat += EqnTest( _T("min(a, 1)"), 1, true);\r
+ iStat += EqnTest( _T("min(3*2, 1)"), 1, true);\r
+ iStat += EqnTest( _T("min(3*2, 1)"), 6, false);\r
+ iStat += EqnTest( _T("firstArg(2,3,4)"), 2, true);\r
+ iStat += EqnTest( _T("lastArg(2,3,4)"), 4, true);\r
+ iStat += EqnTest( _T("min(3*a+1, 1)"), 1, true);\r
+ iStat += EqnTest( _T("max(3*a+1, 1)"), 4, true);\r
+ iStat += EqnTest( _T("max(3*a+1, 1)*2"), 8, true);\r
+ iStat += EqnTest( _T("2*max(3*a+1, 1)+2"), 10, true);\r
+\r
+ // functions with Variable argument count\r
+ iStat += EqnTest( _T("sum(a)"), 1, true);\r
+ iStat += EqnTest( _T("sum(1,2,3)"), 6, true);\r
+ iStat += EqnTest( _T("sum(a,b,c)"), 6, true);\r
+ iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true);\r
+ iStat += EqnTest( _T("2*sum(1,2,3)"), 12, true);\r
+ iStat += EqnTest( _T("2*sum(1,2,3)+2"), 14, true);\r
+ iStat += EqnTest( _T("2*sum(-1,2,3)+2"), 10, true);\r
+ iStat += EqnTest( _T("2*sum(-1,2,-(-a))+2"), 6, true);\r
+ iStat += EqnTest( _T("2*sum(-1,10,-a)+2"), 18, true);\r
+ iStat += EqnTest( _T("2*sum(1,2,3)*2"), 24, true);\r
+ iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true);\r
+ iStat += EqnTest( _T("sum(1*3, 4, a+2)"), 10, true);\r
+ iStat += EqnTest( _T("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true);\r
+ 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);\r
+\r
+ // some failures\r
+ iStat += EqnTest( _T("sum()"), 0, false);\r
+ iStat += EqnTest( _T("sum(,)"), 0, false);\r
+ iStat += EqnTest( _T("sum(1,2,)"), 0, false);\r
+ iStat += EqnTest( _T("sum(,1,2)"), 0, false);\r
+\r
+ if (iStat==0) \r
+ mu::console() << _T("passed") << endl;\r
+ else\r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+ \r
+ return iStat;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::TestInfixOprt()\r
+ {\r
+ int iStat(0);\r
+ mu::console() << "testing infix operators...";\r
+\r
+ iStat += EqnTest( _T("-1"), -1, true);\r
+ iStat += EqnTest( _T("-(-1)"), 1, true);\r
+ iStat += EqnTest( _T("-(-1)*2"), 2, true);\r
+ iStat += EqnTest( _T("-(-2)*sqrt(4)"), 4, true);\r
+ iStat += EqnTest( _T("-_pi"), -PARSER_CONST_PI, true);\r
+ iStat += EqnTest( _T("-a"), -1, true);\r
+ iStat += EqnTest( _T("-(a)"), -1, true);\r
+ iStat += EqnTest( _T("-(-a)"), 1, true);\r
+ iStat += EqnTest( _T("-(-a)*2"), 2, true);\r
+ iStat += EqnTest( _T("-(8)"), -8, true);\r
+ iStat += EqnTest( _T("-8"), -8, true);\r
+ iStat += EqnTest( _T("-(2+1)"), -3, true);\r
+ iStat += EqnTest( _T("-(f1of1(1+2*3)+1*2)"), -9, true);\r
+ iStat += EqnTest( _T("-(-f1of1(1+2*3)+1*2)"), 5, true);\r
+ iStat += EqnTest( _T("-sin(8)"), -0.989358, true);\r
+ iStat += EqnTest( _T("3-(-a)"), 4, true);\r
+ iStat += EqnTest( _T("3--a"), 4, true);\r
+ iStat += EqnTest( _T("-1*3"), -3, true);\r
+\r
+ // Postfix / infix priorities\r
+ iStat += EqnTest( _T("~2#"), 8, true);\r
+ iStat += EqnTest( _T("~f1of1(2)#"), 8, true);\r
+ iStat += EqnTest( _T("~(b)#"), 8, true);\r
+ iStat += EqnTest( _T("(~b)#"), 12, true);\r
+ iStat += EqnTest( _T("~(2#)"), 8, true);\r
+ iStat += EqnTest( _T("~(f1of1(2)#)"), 8, true);\r
+ //\r
+ iStat += EqnTest( _T("-2^2"),-4, true);\r
+ iStat += EqnTest( _T("-(a+b)^2"),-9, true);\r
+ iStat += EqnTest( _T("(-3)^2"),9, true);\r
+ iStat += EqnTest( _T("-(-2^2)"),4, true);\r
+ iStat += EqnTest( _T("3+-3^2"),-6, true);\r
+ // The following assumes use of sqr as postfix operator ("§") together\r
+ // with a sign operator of low priority:\r
+ iStat += EqnTest( _T("-2'"), -4, true);\r
+ iStat += EqnTest( _T("-(1+1)'"),-4, true);\r
+ iStat += EqnTest( _T("2+-(1+1)'"),-2, true);\r
+ iStat += EqnTest( _T("2+-2'"), -2, true);\r
+ // This is the classic behaviour of the infix sign operator (here: "$") which is\r
+ // now deprecated:\r
+ iStat += EqnTest( _T("$2^2"),4, true);\r
+ iStat += EqnTest( _T("$(a+b)^2"),9, true);\r
+ iStat += EqnTest( _T("($3)^2"),9, true);\r
+ iStat += EqnTest( _T("$($2^2)"),-4, true);\r
+ iStat += EqnTest( _T("3+$3^2"),12, true);\r
+\r
+ // infix operators sharing the first few characters\r
+ iStat += EqnTest( _T("~ 123"), 123+2, true);\r
+ iStat += EqnTest( _T("~~ 123"), 123+2, true);\r
+\r
+ if (iStat==0)\r
+ mu::console() << _T("passed") << endl;\r
+ else\r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::TestPostFix()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing postfix operators...");\r
+\r
+ // application\r
+ iStat += EqnTest( _T("3{m}+5"), 5.003, true);\r
+ iStat += EqnTest( _T("1000{m}"), 1, true);\r
+ iStat += EqnTest( _T("1000 {m}"), 1, true);\r
+ iStat += EqnTest( _T("(a){m}"), 1e-3, true);\r
+ iStat += EqnTest( _T("a{m}"), 1e-3, true);\r
+ iStat += EqnTest( _T("a {m}"), 1e-3, true);\r
+ iStat += EqnTest( _T("-(a){m}"), -1e-3, true);\r
+ iStat += EqnTest( _T("-2{m}"), -2e-3, true);\r
+ iStat += EqnTest( _T("-2 {m}"), -2e-3, true);\r
+ iStat += EqnTest( _T("f1of1(1000){m}"), 1, true);\r
+ iStat += EqnTest( _T("-f1of1(1000){m}"), -1, true);\r
+ iStat += EqnTest( _T("-f1of1(-1000){m}"), 1, true);\r
+ iStat += EqnTest( _T("f4of4(0,0,0,1000){m}"), 1, true);\r
+ iStat += EqnTest( _T("2+(a*1000){m}"), 3, true);\r
+\r
+ // can postfix operators "m" und "meg" be told apart properly?\r
+ iStat += EqnTest( _T("2*3000meg+2"), 2*3e9+2, true); \r
+\r
+ // some incorrect results\r
+ iStat += EqnTest( _T("1000{m}"), 0.1, false);\r
+ iStat += EqnTest( _T("(a){m}"), 2, false);\r
+ // failure due to syntax checking\r
+ iStat += ThrowTest(_T("0x"), ecUNASSIGNABLE_TOKEN); // incomplete hex definition\r
+ iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF);\r
+ iStat += ThrowTest( _T("4 + {m}"), ecUNASSIGNABLE_TOKEN);\r
+ iStat += ThrowTest( _T("{m}4"), ecUNASSIGNABLE_TOKEN);\r
+ iStat += ThrowTest( _T("sin({m})"), ecUNASSIGNABLE_TOKEN);\r
+ iStat += ThrowTest( _T("{m} {m}"), ecUNASSIGNABLE_TOKEN);\r
+ iStat += ThrowTest( _T("{m}(8)"), ecUNASSIGNABLE_TOKEN);\r
+ iStat += ThrowTest( _T("4,{m}"), ecUNASSIGNABLE_TOKEN);\r
+ iStat += ThrowTest( _T("-{m}"), ecUNASSIGNABLE_TOKEN);\r
+ iStat += ThrowTest( _T("2(-{m})"), ecUNEXPECTED_PARENS);\r
+ iStat += ThrowTest( _T("2({m})"), ecUNEXPECTED_PARENS);\r
+ \r
+ iStat += ThrowTest( _T("multi*1.0"), ecUNASSIGNABLE_TOKEN);\r
+\r
+ if (iStat==0)\r
+ mu::console() << _T("passed") << endl;\r
+ else\r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::TestExpression()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing expression samples...");\r
+\r
+ value_type b = 2;\r
+\r
+ // Optimization\r
+ iStat += EqnTest( _T("2*b*5"), 20, true);\r
+ iStat += EqnTest( _T("2*b*5 + 4*b"), 28, true);\r
+ iStat += EqnTest( _T("2*a/3"), 2.0/3.0, true);\r
+\r
+ // Addition auf cmVARMUL \r
+ iStat += EqnTest( _T("3+b"), b+3, true);\r
+ iStat += EqnTest( _T("b+3"), b+3, true);\r
+ iStat += EqnTest( _T("b*3+2"), b*3+2, true);\r
+ iStat += EqnTest( _T("3*b+2"), b*3+2, true);\r
+ iStat += EqnTest( _T("2+b*3"), b*3+2, true);\r
+ iStat += EqnTest( _T("2+3*b"), b*3+2, true);\r
+ iStat += EqnTest( _T("b+3*b"), b+3*b, true);\r
+ iStat += EqnTest( _T("3*b+b"), b+3*b, true);\r
+\r
+ iStat += EqnTest( _T("2+b*3+b"), 2+b*3+b, true);\r
+ iStat += EqnTest( _T("b+2+b*3"), b+2+b*3, true);\r
+\r
+ iStat += EqnTest( _T("(2*b+1)*4"), (2*b+1)*4, true);\r
+ iStat += EqnTest( _T("4*(2*b+1)"), (2*b+1)*4, true);\r
+\r
+ // operator precedencs\r
+ iStat += EqnTest( _T("1+2-3*4/5^6"), 2.99923, true);\r
+ iStat += EqnTest( _T("1^2/3*4-5+6"), 2.33333333, true);\r
+ iStat += EqnTest( _T("1+2*3"), 7, true);\r
+ iStat += EqnTest( _T("1+2*3"), 7, true);\r
+ iStat += EqnTest( _T("(1+2)*3"), 9, true);\r
+ iStat += EqnTest( _T("(1+2)*(-3)"), -9, true);\r
+ iStat += EqnTest( _T("2/4"), 0.5, true);\r
+\r
+ iStat += EqnTest( _T("exp(ln(7))"), 7, true);\r
+ iStat += EqnTest( _T("e^ln(7)"), 7, true);\r
+ iStat += EqnTest( _T("e^(ln(7))"), 7, true);\r
+ iStat += EqnTest( _T("(e^(ln(7)))"), 7, true);\r
+ iStat += EqnTest( _T("1-(e^(ln(7)))"), -6, true);\r
+ iStat += EqnTest( _T("2*(e^(ln(7)))"), 14, true);\r
+ iStat += EqnTest( _T("10^log(5)"), 5, true);\r
+ iStat += EqnTest( _T("10^log10(5)"), 5, true);\r
+ iStat += EqnTest( _T("2^log2(4)"), 4, true);\r
+ iStat += EqnTest( _T("-(sin(0)+1)"), -1, true);\r
+ iStat += EqnTest( _T("-(2^1.1)"), -2.14354692, true);\r
+\r
+ iStat += EqnTest( _T("(cos(2.41)/b)"), -0.372056, true);\r
+ iStat += EqnTest( _T("(1*(2*(3*(4*(5*(6*(a+b)))))))"), 2160, true);\r
+ iStat += EqnTest( _T("(1*(2*(3*(4*(5*(6*(7*(a+b))))))))"), 15120, true);\r
+ 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);\r
+\r
+ // long formula (Reference: Matlab)\r
+ iStat += EqnTest(\r
+ _T("(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))")\r
+ _T("/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/")\r
+ _T("((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-")\r
+ _T("e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6")\r
+ _T("+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e")\r
+ _T("*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)"), -12.23016549, true);\r
+\r
+ // long formula (Reference: Matlab)\r
+ iStat += EqnTest(\r
+ _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")\r
+ _T(")+a)))*2.77)"), -2.16995656, true);\r
+\r
+ // long formula (Reference: Matlab)\r
+ iStat += EqnTest( _T("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true);\r
+ \r
+ if (iStat==0) \r
+ mu::console() << _T("passed") << endl; \r
+ else \r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::TestIfThenElse()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing if-then-else operator...");\r
+\r
+ // Test error detection\r
+ iStat += ThrowTest(_T(":3"), ecUNEXPECTED_CONDITIONAL); \r
+ iStat += ThrowTest(_T("? 1 : 2"), ecUNEXPECTED_CONDITIONAL); \r
+ iStat += ThrowTest(_T("(a<b) ? (b<c) ? 1 : 2"), ecMISSING_ELSE_CLAUSE); \r
+ iStat += ThrowTest(_T("(a<b) ? 1"), ecMISSING_ELSE_CLAUSE); \r
+ iStat += ThrowTest(_T("(a<b) ? a"), ecMISSING_ELSE_CLAUSE); \r
+ iStat += ThrowTest(_T("(a<b) ? a+b"), ecMISSING_ELSE_CLAUSE); \r
+ iStat += ThrowTest(_T("a : b"), ecMISPLACED_COLON); \r
+ iStat += ThrowTest(_T("1 : 2"), ecMISPLACED_COLON); \r
+ iStat += ThrowTest(_T("(1) ? 1 : 2 : 3"), ecMISPLACED_COLON); \r
+ iStat += ThrowTest(_T("(true) ? 1 : 2 : 3"), ecUNASSIGNABLE_TOKEN); \r
+\r
+ iStat += EqnTest(_T("1 ? 128 : 255"), 128, true);\r
+ iStat += EqnTest(_T("1<2 ? 128 : 255"), 128, true);\r
+ iStat += EqnTest(_T("a<b ? 128 : 255"), 128, true);\r
+ iStat += EqnTest(_T("(a<b) ? 128 : 255"), 128, true);\r
+ iStat += EqnTest(_T("(1) ? 10 : 11"), 10, true);\r
+ iStat += EqnTest(_T("(0) ? 10 : 11"), 11, true);\r
+ iStat += EqnTest(_T("(1) ? a+b : c+d"), 3, true);\r
+ iStat += EqnTest(_T("(0) ? a+b : c+d"), 1, true);\r
+ iStat += EqnTest(_T("(1) ? 0 : 1"), 0, true);\r
+ iStat += EqnTest(_T("(0) ? 0 : 1"), 1, true);\r
+ iStat += EqnTest(_T("(a<b) ? 10 : 11"), 10, true);\r
+ iStat += EqnTest(_T("(a>b) ? 10 : 11"), 11, true);\r
+ iStat += EqnTest(_T("(a<b) ? c : d"), 3, true);\r
+ iStat += EqnTest(_T("(a>b) ? c : d"), -2, true);\r
+\r
+ iStat += EqnTest(_T("(a>b) ? 1 : 0"), 0, true);\r
+ iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : 2"), 2, true);\r
+ iStat += EqnTest(_T("((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)"), 2, true);\r
+ iStat += EqnTest(_T("((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)"), 1, true);\r
+\r
+ iStat += EqnTest(_T("sum((a>b) ? 1 : 2)"), 2, true);\r
+ iStat += EqnTest(_T("sum((1) ? 1 : 2)"), 1, true);\r
+ iStat += EqnTest(_T("sum((a>b) ? 1 : 2, 100)"), 102, true);\r
+ iStat += EqnTest(_T("sum((1) ? 1 : 2, 100)"), 101, true);\r
+ iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)"), 13, true);\r
+ iStat += EqnTest(_T("sum(3, (a<b) ? 3 : 10)"), 6, true);\r
+ iStat += EqnTest(_T("10*sum(3, (a>b) ? 3 : 10)"), 130, true);\r
+ iStat += EqnTest(_T("10*sum(3, (a<b) ? 3 : 10)"), 60, true);\r
+ iStat += EqnTest(_T("sum(3, (a>b) ? 3 : 10)*10"), 130, true);\r
+ iStat += EqnTest(_T("sum(3, (a<b) ? 3 : 10)*10"), 60, true);\r
+ iStat += EqnTest(_T("(a<b) ? sum(3, (a<b) ? 3 : 10)*10 : 99"), 60, true);\r
+ iStat += EqnTest(_T("(a>b) ? sum(3, (a<b) ? 3 : 10)*10 : 99"), 99, true);\r
+ iStat += EqnTest(_T("(a<b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : 99"), 360, true);\r
+ iStat += EqnTest(_T("(a>b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : 99"), 99, true);\r
+ iStat += EqnTest(_T("(a>b) ? sum(3, (a<b) ? 3 : 10,10,20)*10 : sum(3, (a<b) ? 3 : 10)*10"), 60, true);\r
+\r
+ // todo: auch für muParserX hinzufügen!\r
+ iStat += EqnTest(_T("(a<b)&&(a<b) ? 128 : 255"), 128, true);\r
+ iStat += EqnTest(_T("(a>b)&&(a<b) ? 128 : 255"), 255, true);\r
+ iStat += EqnTest(_T("(1<2)&&(1<2) ? 128 : 255"), 128, true);\r
+ iStat += EqnTest(_T("(1>2)&&(1<2) ? 128 : 255"), 255, true);\r
+ iStat += EqnTest(_T("((1<2)&&(1<2)) ? 128 : 255"), 128, true);\r
+ iStat += EqnTest(_T("((1>2)&&(1<2)) ? 128 : 255"), 255, true);\r
+ iStat += EqnTest(_T("((a<b)&&(a<b)) ? 128 : 255"), 128, true);\r
+ iStat += EqnTest(_T("((a>b)&&(a<b)) ? 128 : 255"), 255, true);\r
+\r
+ iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 255, true);\r
+ iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)"), 255, true);\r
+ iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 128, true);\r
+ iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)"), 128, true);\r
+ iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64"), 32, true);\r
+ iStat += EqnTest(_T("1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64"), 64, true);\r
+ iStat += EqnTest(_T("1>0 ? 50 : 1>0 ? 128 : 255"), 50, true);\r
+ iStat += EqnTest(_T("1>0 ? 50 : (1>0 ? 128 : 255)"), 50, true);\r
+ iStat += EqnTest(_T("1>0 ? 1>0 ? 128 : 255 : 50"), 128, true);\r
+ iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16"), 32, true);\r
+ iStat += EqnTest(_T("1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)"), 32, true);\r
+ iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16"), 255, true);\r
+ iStat += EqnTest(_T("1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)"), 255, true);\r
+ iStat += EqnTest(_T("1 ? 0 ? 128 : 255 : 1 ? 32 : 64"), 255, true);\r
+\r
+ // assignment operators\r
+ iStat += EqnTest(_T("a= 0 ? 128 : 255, a"), 255, true);\r
+ iStat += EqnTest(_T("a=((a>b)&&(a<b)) ? 128 : 255, a"), 255, true);\r
+ iStat += EqnTest(_T("c=(a<b)&&(a<b) ? 128 : 255, c"), 128, true);\r
+ iStat += EqnTest(_T("0 ? a=a+1 : 666, a"), 1, true);\r
+ iStat += EqnTest(_T("1?a=10:a=20, a"), 10, true);\r
+ iStat += EqnTest(_T("0?a=10:a=20, a"), 20, true);\r
+ iStat += EqnTest(_T("0?a=sum(3,4):10, a"), 1, true); // a should not change its value due to lazy calculation\r
+ \r
+ iStat += EqnTest(_T("a=1?b=1?3:4:5, a"), 3, true);\r
+ iStat += EqnTest(_T("a=1?b=1?3:4:5, b"), 3, true);\r
+ iStat += EqnTest(_T("a=0?b=1?3:4:5, a"), 5, true);\r
+ iStat += EqnTest(_T("a=0?b=1?3:4:5, b"), 2, true);\r
+\r
+ iStat += EqnTest(_T("a=1?5:b=1?3:4, a"), 5, true);\r
+ iStat += EqnTest(_T("a=1?5:b=1?3:4, b"), 2, true);\r
+ iStat += EqnTest(_T("a=0?5:b=1?3:4, a"), 3, true);\r
+ iStat += EqnTest(_T("a=0?5:b=1?3:4, b"), 3, true);\r
+\r
+ if (iStat==0) \r
+ mu::console() << _T("passed") << endl; \r
+ else \r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::TestException()\r
+ {\r
+ int iStat = 0;\r
+ mu::console() << _T("testing error codes...");\r
+\r
+ iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF);\r
+ iStat += ThrowTest(_T("3+)"), ecUNEXPECTED_PARENS);\r
+ iStat += ThrowTest(_T("()"), ecUNEXPECTED_PARENS);\r
+ iStat += ThrowTest(_T("3+()"), ecUNEXPECTED_PARENS);\r
+ iStat += ThrowTest(_T("sin(3,4)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest(_T("sin()"), ecTOO_FEW_PARAMS);\r
+ iStat += ThrowTest(_T("(1+2"), ecMISSING_PARENS);\r
+ iStat += ThrowTest(_T("sin(3)3"), ecUNEXPECTED_VAL);\r
+ iStat += ThrowTest(_T("sin(3)xyz"), ecUNASSIGNABLE_TOKEN);\r
+ iStat += ThrowTest(_T("sin(3)cos(3)"), ecUNEXPECTED_FUN);\r
+ iStat += ThrowTest(_T("a+b+c=10"), ecUNEXPECTED_OPERATOR);\r
+ iStat += ThrowTest(_T("a=b=3"), ecUNEXPECTED_OPERATOR);\r
+\r
+#if defined(MUP_MATH_EXCEPTIONS)\r
+ // divide by zero whilst constant folding\r
+ iStat += ThrowTest(_T("1/0"), ecDIV_BY_ZERO);\r
+ // square root of a negative number\r
+ iStat += ThrowTest(_T("sqrt(-1)"), ecDOMAIN_ERROR);\r
+ // logarithms of zero\r
+ iStat += ThrowTest(_T("ln(0)"), ecDOMAIN_ERROR);\r
+ iStat += ThrowTest(_T("log2(0)"), ecDOMAIN_ERROR);\r
+ iStat += ThrowTest(_T("log10(0)"), ecDOMAIN_ERROR);\r
+ iStat += ThrowTest(_T("log(0)"), ecDOMAIN_ERROR);\r
+ // logarithms of negative values\r
+ iStat += ThrowTest(_T("ln(-1)"), ecDOMAIN_ERROR);\r
+ iStat += ThrowTest(_T("log2(-1)"), ecDOMAIN_ERROR);\r
+ iStat += ThrowTest(_T("log10(-1)"), ecDOMAIN_ERROR);\r
+ iStat += ThrowTest(_T("log(-1)"), ecDOMAIN_ERROR);\r
+#endif\r
+\r
+ // functions without parameter\r
+ iStat += ThrowTest( _T("3+ping(2)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest( _T("3+ping(a+2)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest( _T("3+ping(sin(a)+2)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest( _T("3+ping(1+sin(a))"), ecTOO_MANY_PARAMS);\r
+\r
+ // String function related\r
+ iStat += ThrowTest( _T("valueof(\"xxx\")"), 999, false);\r
+ iStat += ThrowTest( _T("valueof()"), ecUNEXPECTED_PARENS);\r
+ iStat += ThrowTest( _T("1+valueof(\"abc\""), ecMISSING_PARENS);\r
+ iStat += ThrowTest( _T("valueof(\"abc\""), ecMISSING_PARENS);\r
+ iStat += ThrowTest( _T("valueof(\"abc"), ecUNTERMINATED_STRING);\r
+ iStat += ThrowTest( _T("valueof(\"abc\",3)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest( _T("valueof(3)"), ecSTRING_EXPECTED);\r
+ iStat += ThrowTest( _T("sin(\"abc\")"), ecVAL_EXPECTED);\r
+ iStat += ThrowTest( _T("valueof(\"\\\"abc\\\"\")"), 999, false);\r
+ iStat += ThrowTest( _T("\"hello world\""), ecSTR_RESULT);\r
+ iStat += ThrowTest( _T("(\"hello world\")"), ecSTR_RESULT);\r
+ iStat += ThrowTest( _T("\"abcd\"+100"), ecOPRT_TYPE_CONFLICT);\r
+ iStat += ThrowTest( _T("\"a\"+\"b\""), ecOPRT_TYPE_CONFLICT);\r
+ iStat += ThrowTest( _T("strfun1(\"100\",3)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest( _T("strfun2(\"100\",3,5)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest( _T("strfun3(\"100\",3,5,6)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest( _T("strfun2(\"100\")"), ecTOO_FEW_PARAMS);\r
+ iStat += ThrowTest( _T("strfun3(\"100\",6)"), ecTOO_FEW_PARAMS);\r
+ iStat += ThrowTest( _T("strfun2(1,1)"), ecSTRING_EXPECTED);\r
+ iStat += ThrowTest( _T("strfun2(a,1)"), ecSTRING_EXPECTED);\r
+ iStat += ThrowTest( _T("strfun2(1,1,1)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest( _T("strfun2(a,1,1)"), ecTOO_MANY_PARAMS);\r
+ iStat += ThrowTest( _T("strfun3(1,2,3)"), ecSTRING_EXPECTED);\r
+ iStat += ThrowTest( _T("strfun3(1, \"100\",3)"), ecSTRING_EXPECTED);\r
+ iStat += ThrowTest( _T("strfun3(\"1\", \"100\",3)"), ecVAL_EXPECTED);\r
+ iStat += ThrowTest( _T("strfun3(\"1\", 3, \"100\")"), ecVAL_EXPECTED);\r
+ iStat += ThrowTest( _T("strfun3(\"1\", \"100\", \"100\", \"100\")"), ecTOO_MANY_PARAMS);\r
+\r
+ // assignement operator\r
+ iStat += ThrowTest( _T("3=4"), ecUNEXPECTED_OPERATOR);\r
+ iStat += ThrowTest( _T("sin(8)=4"), ecUNEXPECTED_OPERATOR);\r
+ iStat += ThrowTest( _T("\"test\"=a"), ecUNEXPECTED_OPERATOR);\r
+\r
+ // <ibg 20090529>\r
+ // this is now legal, for reference see:\r
+ // https://sourceforge.net/forum/message.php?msg_id=7411373\r
+ // iStat += ThrowTest( _T("sin=9"), ecUNEXPECTED_OPERATOR); \r
+ // </ibg>\r
+\r
+ iStat += ThrowTest( _T("(8)=5"), ecUNEXPECTED_OPERATOR);\r
+ iStat += ThrowTest( _T("(a)=5"), ecUNEXPECTED_OPERATOR);\r
+ iStat += ThrowTest( _T("a=\"tttt\""), ecOPRT_TYPE_CONFLICT);\r
+\r
+ if (iStat==0) \r
+ mu::console() << _T("passed") << endl;\r
+ else \r
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;\r
+\r
+ return iStat;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserTester::AddTest(testfun_type a_pFun)\r
+ {\r
+ m_vTestFun.push_back(a_pFun);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserTester::Run()\r
+ {\r
+ int iStat = 0;\r
+ try\r
+ {\r
+ for (int i=0; i<(int)m_vTestFun.size(); ++i)\r
+ iStat += (this->*m_vTestFun[i])();\r
+ }\r
+ catch(Parser::exception_type &e)\r
+ {\r
+ mu::console() << "\n" << e.GetMsg() << endl;\r
+ mu::console() << e.GetToken() << endl;\r
+ Abort();\r
+ }\r
+ catch(std::exception &e)\r
+ {\r
+ mu::console() << e.what() << endl;\r
+ Abort();\r
+ }\r
+ catch(...)\r
+ {\r
+ mu::console() << "Internal error";\r
+ Abort();\r
+ }\r
+\r
+ if (iStat==0) \r
+ {\r
+ mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl;\r
+ }\r
+ else \r
+ {\r
+ mu::console() << "Test failed with " << iStat \r
+ << " errors (" << ParserTester::c_iCount \r
+ << " expressions)" << endl;\r
+ }\r
+ ParserTester::c_iCount = 0;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail)\r
+ {\r
+ ParserTester::c_iCount++;\r
+\r
+ try\r
+ {\r
+ value_type fVal[] = {1,1,1};\r
+ Parser p;\r
+\r
+ p.DefineVar( _T("a"), &fVal[0]);\r
+ p.DefineVar( _T("b"), &fVal[1]);\r
+ p.DefineVar( _T("c"), &fVal[2]);\r
+ p.DefinePostfixOprt( _T("{m}"), Milli);\r
+ p.DefinePostfixOprt( _T("m"), Milli);\r
+ p.DefineFun( _T("ping"), Ping);\r
+ p.DefineFun( _T("valueof"), ValueOf);\r
+ p.DefineFun( _T("strfun1"), StrFun1);\r
+ p.DefineFun( _T("strfun2"), StrFun2);\r
+ p.DefineFun( _T("strfun3"), StrFun3);\r
+ p.SetExpr(a_str);\r
+ p.Eval();\r
+ }\r
+ catch(ParserError &e)\r
+ {\r
+ // output the formula in case of an failed test\r
+ if (a_bFail==false || (a_bFail==true && a_iErrc!=e.GetCode()) )\r
+ {\r
+ mu::console() << _T("\n ") \r
+ << _T("Expression: ") << a_str \r
+ << _T(" Code:") << e.GetCode() << _T("(") << e.GetMsg() << _T(")")\r
+ << _T(" Expected:") << a_iErrc;\r
+ }\r
+\r
+ return (a_iErrc==e.GetCode()) ? 0 : 1;\r
+ }\r
+\r
+ // if a_bFail==false no exception is expected\r
+ bool bRet((a_bFail==false) ? 0 : 1);\r
+ if (bRet==1)\r
+ {\r
+ mu::console() << _T("\n ") \r
+ << _T("Expression: ") << a_str \r
+ << _T(" did evaluate; Expected error:") << a_iErrc;\r
+ }\r
+\r
+ return bRet; \r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Evaluate a tet expression. \r
+\r
+ \return 1 in case of a failure, 0 otherwise.\r
+ */\r
+ int ParserTester::EqnTestWithVarChange(const string_type &a_str, \r
+ double a_fVar1, \r
+ double a_fRes1, \r
+ double a_fVar2, \r
+ double a_fRes2)\r
+ {\r
+ ParserTester::c_iCount++;\r
+ value_type fVal[2] = {-999, -999 }; // should be equalinitially\r
+\r
+ try\r
+ {\r
+ Parser p;\r
+\r
+ // variable\r
+ value_type var = 0;\r
+ p.DefineVar( _T("a"), &var);\r
+ p.SetExpr(a_str);\r
+\r
+ var = a_fVar1;\r
+ fVal[0] = p.Eval();\r
+\r
+ var = a_fVar2;\r
+ fVal[1] = p.Eval();\r
+ \r
+ if ( fabs(a_fRes1-fVal[0]) > 0.0000000001)\r
+ throw std::runtime_error("incorrect result (first pass)");\r
+\r
+ if ( fabs(a_fRes2-fVal[1]) > 0.0000000001)\r
+ throw std::runtime_error("incorrect result (second pass)");\r
+ }\r
+ catch(Parser::exception_type &e)\r
+ {\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")");\r
+ return 1;\r
+ }\r
+ catch(std::exception &e)\r
+ {\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")");\r
+ return 1; // always return a failure since this exception is not expected\r
+ }\r
+ catch(...)\r
+ {\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");\r
+ return 1; // exceptions other than ParserException are not allowed\r
+ }\r
+\r
+ return 0;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Evaluate a tet expression. \r
+\r
+ \return 1 in case of a failure, 0 otherwise.\r
+ */\r
+ int ParserTester::EqnTest(const string_type &a_str, double a_fRes, bool a_fPass)\r
+ {\r
+ ParserTester::c_iCount++;\r
+ int iRet(0);\r
+ value_type fVal[5] = {-999, -998, -997, -996, -995}; // initially should be different\r
+\r
+ try\r
+ {\r
+ std::auto_ptr<Parser> p1;\r
+ Parser p2, p3; // three parser objects\r
+ // they will be used for testing copy and assihnment operators\r
+ // p1 is a pointer since i'm going to delete it in order to test if\r
+ // parsers after copy construction still refer to members of it.\r
+ // !! If this is the case this function will crash !!\r
+ \r
+ p1.reset(new mu::Parser()); \r
+ // Add constants\r
+ p1->DefineConst( _T("pi"), (value_type)PARSER_CONST_PI);\r
+ p1->DefineConst( _T("e"), (value_type)PARSER_CONST_E);\r
+ p1->DefineConst( _T("const"), 1);\r
+ p1->DefineConst( _T("const1"), 2);\r
+ p1->DefineConst( _T("const2"), 3);\r
+ // variables\r
+ value_type vVarVal[] = { 1, 2, 3, -2};\r
+ p1->DefineVar( _T("a"), &vVarVal[0]);\r
+ p1->DefineVar( _T("aa"), &vVarVal[1]);\r
+ p1->DefineVar( _T("b"), &vVarVal[1]);\r
+ p1->DefineVar( _T("c"), &vVarVal[2]);\r
+ p1->DefineVar( _T("d"), &vVarVal[3]);\r
+ \r
+ // custom value ident functions\r
+ p1->AddValIdent(&ParserTester::IsHexVal); \r
+\r
+ // functions\r
+ p1->DefineFun( _T("ping"), Ping);\r
+ p1->DefineFun( _T("f1of1"), f1of1); // one parameter\r
+ p1->DefineFun( _T("f1of2"), f1of2); // two parameter\r
+ p1->DefineFun( _T("f2of2"), f2of2);\r
+ p1->DefineFun( _T("f1of3"), f1of3); // three parameter\r
+ p1->DefineFun( _T("f2of3"), f2of3);\r
+ p1->DefineFun( _T("f3of3"), f3of3);\r
+ p1->DefineFun( _T("f1of4"), f1of4); // four parameter\r
+ p1->DefineFun( _T("f2of4"), f2of4);\r
+ p1->DefineFun( _T("f3of4"), f3of4);\r
+ p1->DefineFun( _T("f4of4"), f4of4);\r
+ p1->DefineFun( _T("f1of5"), f1of5); // five parameter\r
+ p1->DefineFun( _T("f2of5"), f2of5);\r
+ p1->DefineFun( _T("f3of5"), f3of5);\r
+ p1->DefineFun( _T("f4of5"), f4of5);\r
+ p1->DefineFun( _T("f5of5"), f5of5);\r
+\r
+ // binary operators\r
+ p1->DefineOprt( _T("add"), add, 0);\r
+ p1->DefineOprt( _T("++"), add, 0);\r
+ p1->DefineOprt( _T("&"), land, prLAND);\r
+\r
+ // sample functions\r
+ p1->DefineFun( _T("min"), Min);\r
+ p1->DefineFun( _T("max"), Max);\r
+ p1->DefineFun( _T("sum"), Sum);\r
+ p1->DefineFun( _T("valueof"), ValueOf);\r
+ p1->DefineFun( _T("atof"), StrToFloat);\r
+ p1->DefineFun( _T("strfun1"), StrFun1);\r
+ p1->DefineFun( _T("strfun2"), StrFun2);\r
+ p1->DefineFun( _T("strfun3"), StrFun3);\r
+ p1->DefineFun( _T("lastArg"), LastArg);\r
+ p1->DefineFun( _T("firstArg"), FirstArg);\r
+ p1->DefineFun( _T("order"), FirstArg);\r
+\r
+ // infix / postfix operator\r
+ // Note: Identifiers used here do not have any meaning \r
+ // they are mere placeholders to test certain features.\r
+ p1->DefineInfixOprt( _T("$"), sign, prPOW+1); // sign with high priority\r
+ p1->DefineInfixOprt( _T("~"), plus2); // high priority\r
+ p1->DefineInfixOprt( _T("~~"), plus2);\r
+ p1->DefinePostfixOprt( _T("{m}"), Milli);\r
+ p1->DefinePostfixOprt( _T("{M}"), Mega);\r
+ p1->DefinePostfixOprt( _T("m"), Milli);\r
+ p1->DefinePostfixOprt( _T("meg"), Mega);\r
+ p1->DefinePostfixOprt( _T("#"), times3);\r
+ p1->DefinePostfixOprt( _T("'"), sqr); \r
+ p1->SetExpr(a_str);\r
+\r
+ // Test bytecode integrity\r
+ // String parsing and bytecode parsing must yield the same result\r
+ fVal[0] = p1->Eval(); // result from stringparsing\r
+ fVal[1] = p1->Eval(); // result from bytecode\r
+ if (fVal[0]!=fVal[1])\r
+ throw Parser::exception_type( _T("Bytecode / string parsing mismatch.") );\r
+\r
+ // Test copy and assignement operators\r
+ try\r
+ {\r
+ // Test copy constructor\r
+ std::vector<mu::Parser> vParser;\r
+ vParser.push_back(*(p1.get()));\r
+ mu::Parser p2 = vParser[0]; // take parser from vector\r
+ \r
+ // destroy the originals from p2\r
+ vParser.clear(); // delete the vector\r
+ p1.reset(0);\r
+\r
+ fVal[2] = p2.Eval();\r
+\r
+ // Test assignement operator\r
+ // additionally disable Optimizer this time\r
+ mu::Parser p3;\r
+ p3 = p2;\r
+ p3.EnableOptimizer(false);\r
+ fVal[3] = p3.Eval();\r
+\r
+ // Test Eval function for multiple return values\r
+ // use p2 since it has the optimizer enabled!\r
+ int nNum;\r
+ value_type *v = p2.Eval(nNum);\r
+ fVal[4] = v[nNum-1];\r
+ }\r
+ catch(std::exception &e)\r
+ {\r
+ mu::console() << _T("\n ") << e.what() << _T("\n");\r
+ }\r
+\r
+ // limited floating point accuracy requires the following test\r
+ bool bCloseEnough(true);\r
+ for (unsigned i=0; i<sizeof(fVal)/sizeof(value_type); ++i)\r
+ {\r
+ bCloseEnough &= (fabs(a_fRes-fVal[i]) <= fabs(fVal[i]*0.00001));\r
+\r
+ // The tests equations never result in infinity, if they do thats a bug.\r
+ // reference:\r
+ // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825\r
+ if (numeric_limits<value_type>::has_infinity)\r
+ bCloseEnough &= (fabs(fVal[i]) != numeric_limits<value_type>::infinity());\r
+ }\r
+\r
+ iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;\r
+ \r
+ \r
+ if (iRet==1)\r
+ {\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() \r
+ << _T(" (incorrect result; expected: ") << a_fRes\r
+ << _T(" ;calculated: ") << fVal[0] << _T(",") \r
+ << fVal[1] << _T(",")\r
+ << fVal[2] << _T(",")\r
+ << fVal[3] << _T(",")\r
+ << fVal[4] << _T(").");\r
+ }\r
+ }\r
+ catch(Parser::exception_type &e)\r
+ {\r
+ if (a_fPass)\r
+ {\r
+ if (fVal[0]!=fVal[2] && fVal[0]!=-999 && fVal[1]!=-998)\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (copy construction)");\r
+ else\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")");\r
+ return 1;\r
+ }\r
+ }\r
+ catch(std::exception &e)\r
+ {\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")");\r
+ return 1; // always return a failure since this exception is not expected\r
+ }\r
+ catch(...)\r
+ {\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");\r
+ return 1; // exceptions other than ParserException are not allowed\r
+ }\r
+\r
+ return iRet;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ int ParserTester::EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass)\r
+ {\r
+ ParserTester::c_iCount++;\r
+\r
+ value_type vVarVal[] = {1, 2, 3}; // variable values\r
+ value_type fVal[2] = {-99, -999}; // results: initially should be different\r
+ int iRet(0);\r
+\r
+ try\r
+ {\r
+ ParserInt p;\r
+ p.DefineConst( _T("const1"), 1);\r
+ p.DefineConst( _T("const2"), 2);\r
+ p.DefineVar( _T("a"), &vVarVal[0]);\r
+ p.DefineVar( _T("b"), &vVarVal[1]);\r
+ p.DefineVar( _T("c"), &vVarVal[2]);\r
+\r
+ p.SetExpr(a_str);\r
+ fVal[0] = p.Eval(); // result from stringparsing\r
+ fVal[1] = p.Eval(); // result from bytecode\r
+\r
+ if (fVal[0]!=fVal[1])\r
+ throw Parser::exception_type( _T("Bytecode corrupt.") );\r
+\r
+ iRet = ( (a_fRes==fVal[0] && a_fPass) || \r
+ (a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1;\r
+ if (iRet==1)\r
+ {\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() \r
+ << _T(" (incorrect result; expected: ") << a_fRes \r
+ << _T(" ;calculated: ") << fVal[0]<< _T(").");\r
+ }\r
+ }\r
+ catch(Parser::exception_type &e)\r
+ {\r
+ if (a_fPass)\r
+ {\r
+ mu::console() << _T("\n fail: ") << e.GetExpr() << _T(" : ") << e.GetMsg();\r
+ iRet = 1;\r
+ }\r
+ }\r
+ catch(...)\r
+ {\r
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");\r
+ iRet = 1; // exceptions other than ParserException are not allowed\r
+ }\r
+\r
+ return iRet;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Internal error in test class Test is going to be aborted. */\r
+ void ParserTester::Abort() const\r
+ {\r
+ mu::console() << _T("Test failed (internal error in test class)") << endl;\r
+ while (!getchar());\r
+ exit(-1);\r
+ }\r
+ } // namespace test\r
+} // namespace mu\r
--- /dev/null
+/*\r
+ __________ \r
+ _____ __ __\______ \_____ _______ ______ ____ _______ \r
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \\r
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/\r
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| \r
+ \/ \/ \/ \/ \r
+ Copyright (C) 2013 Ingo Berg\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this \r
+ software and associated documentation files (the "Software"), to deal in the Software\r
+ without restriction, including without limitation the rights to use, copy, modify, \r
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to \r
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be included in all copies or \r
+ substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\r
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \r
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \r
+*/\r
+#include <cassert>\r
+#include <cstdio>\r
+#include <cstring>\r
+#include <map>\r
+#include <stack>\r
+#include <string>\r
+\r
+#include "muParserTokenReader.h"\r
+#include "muParserBase.h"\r
+\r
+/** \file\r
+ \brief This file contains the parser token reader implementation.\r
+*/\r
+\r
+\r
+namespace mu\r
+{\r
+\r
+ // Forward declaration\r
+ class ParserBase;\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Copy constructor.\r
+\r
+ \sa Assign\r
+ \throw nothrow\r
+ */\r
+ ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader) \r
+ { \r
+ Assign(a_Reader);\r
+ }\r
+ \r
+ //---------------------------------------------------------------------------\r
+ /** \brief Assignement operator.\r
+\r
+ Self assignement will be suppressed otherwise #Assign is called.\r
+\r
+ \param a_Reader Object to copy to this token reader.\r
+ \throw nothrow\r
+ */\r
+ ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader) \r
+ {\r
+ if (&a_Reader!=this)\r
+ Assign(a_Reader);\r
+\r
+ return *this;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Assign state of a token reader to this token reader. \r
+ \r
+ \param a_Reader Object from which the state should be copied.\r
+ \throw nothrow\r
+ */\r
+ void ParserTokenReader::Assign(const ParserTokenReader &a_Reader)\r
+ {\r
+ m_pParser = a_Reader.m_pParser;\r
+ m_strFormula = a_Reader.m_strFormula;\r
+ m_iPos = a_Reader.m_iPos;\r
+ m_iSynFlags = a_Reader.m_iSynFlags;\r
+ \r
+ m_UsedVar = a_Reader.m_UsedVar;\r
+ m_pFunDef = a_Reader.m_pFunDef;\r
+ m_pConstDef = a_Reader.m_pConstDef;\r
+ m_pVarDef = a_Reader.m_pVarDef;\r
+ m_pStrVarDef = a_Reader.m_pStrVarDef;\r
+ m_pPostOprtDef = a_Reader.m_pPostOprtDef;\r
+ m_pInfixOprtDef = a_Reader.m_pInfixOprtDef;\r
+ m_pOprtDef = a_Reader.m_pOprtDef;\r
+ m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar;\r
+ m_vIdentFun = a_Reader.m_vIdentFun;\r
+ m_pFactory = a_Reader.m_pFactory;\r
+ m_pFactoryData = a_Reader.m_pFactoryData;\r
+ m_iBrackets = a_Reader.m_iBrackets;\r
+ m_cArgSep = a_Reader.m_cArgSep;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Constructor. \r
+ \r
+ Create a Token reader and bind it to a parser object. \r
+\r
+ \pre [assert] a_pParser may not be NULL\r
+ \post #m_pParser==a_pParser\r
+ \param a_pParent Parent parser object of the token reader.\r
+ */\r
+ ParserTokenReader::ParserTokenReader(ParserBase *a_pParent)\r
+ :m_pParser(a_pParent)\r
+ ,m_strFormula()\r
+ ,m_iPos(0)\r
+ ,m_iSynFlags(0)\r
+ ,m_bIgnoreUndefVar(false)\r
+ ,m_pFunDef(NULL)\r
+ ,m_pPostOprtDef(NULL)\r
+ ,m_pInfixOprtDef(NULL)\r
+ ,m_pOprtDef(NULL)\r
+ ,m_pConstDef(NULL)\r
+ ,m_pStrVarDef(NULL)\r
+ ,m_pVarDef(NULL)\r
+ ,m_pFactory(NULL)\r
+ ,m_pFactoryData(NULL)\r
+ ,m_vIdentFun()\r
+ ,m_UsedVar()\r
+ ,m_fZero(0)\r
+ ,m_iBrackets(0)\r
+ ,m_lastTok()\r
+ ,m_cArgSep(',')\r
+ {\r
+ assert(m_pParser);\r
+ SetParent(m_pParser);\r
+ }\r
+ \r
+ //---------------------------------------------------------------------------\r
+ /** \brief Create instance of a ParserTokenReader identical with this \r
+ and return its pointer. \r
+\r
+ This is a factory method the calling function must take care of the object destruction.\r
+\r
+ \return A new ParserTokenReader object.\r
+ \throw nothrow\r
+ */\r
+ ParserTokenReader* ParserTokenReader::Clone(ParserBase *a_pParent) const\r
+ {\r
+ std::auto_ptr<ParserTokenReader> ptr(new ParserTokenReader(*this));\r
+ ptr->SetParent(a_pParent);\r
+ return ptr.release();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type &tok)\r
+ {\r
+ m_lastTok = tok;\r
+ return m_lastTok;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserTokenReader::AddValIdent(identfun_type a_pCallback)\r
+ {\r
+ // Use push_front is used to give user defined callbacks a higher priority than\r
+ // the built in ones. Otherwise reading hex numbers would not work\r
+ // since the "0" in "0xff" would always be read first making parsing of \r
+ // the rest impossible.\r
+ // reference:\r
+ // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956\r
+ m_vIdentFun.push_front(a_pCallback);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData)\r
+ {\r
+ m_pFactory = a_pFactory;\r
+ m_pFactoryData = pUserData;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return the current position of the token reader in the formula string. \r
+\r
+ \return #m_iPos\r
+ \throw nothrow\r
+ */\r
+ int ParserTokenReader::GetPos() const\r
+ {\r
+ return m_iPos;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return a reference to the formula. \r
+\r
+ \return #m_strFormula\r
+ \throw nothrow\r
+ */\r
+ const string_type& ParserTokenReader::GetExpr() const\r
+ {\r
+ return m_strFormula;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Return a map containing the used variables only. */\r
+ varmap_type& ParserTokenReader::GetUsedVar() \r
+ {\r
+ return m_UsedVar;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Initialize the token Reader. \r
+ \r
+ Sets the formula position index to zero and set Syntax flags to default for initial formula parsing.\r
+ \pre [assert] triggered if a_szFormula==0\r
+ */\r
+ void ParserTokenReader::SetFormula(const string_type &a_strFormula)\r
+ {\r
+ m_strFormula = a_strFormula;\r
+ ReInit();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Set Flag that contronls behaviour in case of undefined variables beeing found. \r
+ \r
+ If true, the parser does not throw an exception if an undefined variable is found. \r
+ otherwise it does. This variable is used internally only!\r
+ It supresses a "undefined variable" exception in GetUsedVar(). \r
+ Those function should return a complete list of variables including \r
+ those the are not defined by the time of it's call.\r
+ */\r
+ void ParserTokenReader::IgnoreUndefVar(bool bIgnore)\r
+ {\r
+ m_bIgnoreUndefVar = bIgnore;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Reset the token reader to the start of the formula. \r
+\r
+ The syntax flags will be reset to a value appropriate for the \r
+ start of a formula.\r
+ \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR\r
+ \throw nothrow\r
+ \sa ESynCodes\r
+ */\r
+ void ParserTokenReader::ReInit()\r
+ {\r
+ m_iPos = 0;\r
+ m_iSynFlags = sfSTART_OF_LINE;\r
+ m_iBrackets = 0;\r
+ m_UsedVar.clear();\r
+ m_lastTok = token_type();\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Read the next token from the string. */ \r
+ ParserTokenReader::token_type ParserTokenReader::ReadNextToken()\r
+ {\r
+ assert(m_pParser);\r
+\r
+ std::stack<int> FunArgs;\r
+ const char_type *szFormula = m_strFormula.c_str();\r
+ token_type tok;\r
+\r
+ // Ignore all non printable characters when reading the expression\r
+ while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20) \r
+ ++m_iPos;\r
+\r
+ if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula\r
+ if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator\r
+ if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token\r
+ if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens\r
+ if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators\r
+ if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens\r
+ if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens\r
+ if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables\r
+ if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens\r
+ if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators\r
+ if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators\r
+\r
+ // Check String for undefined variable token. Done only if a \r
+ // flag is set indicating to ignore undefined variables.\r
+ // This is a way to conditionally avoid an error if \r
+ // undefined variables occur. \r
+ // (The GetUsedVar function must suppress the error for\r
+ // undefined variables in order to collect all variable \r
+ // names including the undefined ones.)\r
+ if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) \r
+ return SaveBeforeReturn(tok);\r
+\r
+ // Check for unknown token\r
+ // \r
+ // !!! From this point on there is no exit without an exception possible...\r
+ // \r
+ string_type strTok;\r
+ int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);\r
+ if (iEnd!=m_iPos)\r
+ Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok);\r
+\r
+ Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos));\r
+ return token_type(); // never reached\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserTokenReader::SetParent(ParserBase *a_pParent)\r
+ {\r
+ m_pParser = a_pParent; \r
+ m_pFunDef = &a_pParent->m_FunDef;\r
+ m_pOprtDef = &a_pParent->m_OprtDef;\r
+ m_pInfixOprtDef = &a_pParent->m_InfixOprtDef;\r
+ m_pPostOprtDef = &a_pParent->m_PostOprtDef;\r
+ m_pVarDef = &a_pParent->m_VarDef;\r
+ m_pStrVarDef = &a_pParent->m_StrVarDef;\r
+ m_pConstDef = &a_pParent->m_ConstDef;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Extract all characters that belong to a certain charset.\r
+\r
+ \param a_szCharSet [in] Const char array of the characters allowed in the token. \r
+ \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet.\r
+ \param a_iPos [in] Position in the string from where to start reading.\r
+ \return The Position of the first character not listed in a_szCharSet.\r
+ \throw nothrow\r
+ */\r
+ int ParserTokenReader::ExtractToken(const char_type *a_szCharSet, \r
+ string_type &a_sTok, \r
+ int a_iPos) const\r
+ {\r
+ int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos);\r
+\r
+ if (iEnd==(int)string_type::npos)\r
+ iEnd = (int)m_strFormula.length();\r
+ \r
+ // Assign token string if there was something found\r
+ if (a_iPos!=iEnd)\r
+ a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd);\r
+\r
+ return iEnd;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check Expression for the presence of a binary operator token.\r
+ \r
+ Userdefined binary operator "++" gives inconsistent parsing result for\r
+ the equations "a++b" and "a ++ b" if alphabetic characters are allowed\r
+ in operator tokens. To avoid this this function checks specifically\r
+ for operator tokens.\r
+ */\r
+ int ParserTokenReader::ExtractOperatorToken(string_type &a_sTok, \r
+ int a_iPos) const\r
+ {\r
+ int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidInfixOprtChars(), a_iPos);\r
+ if (iEnd==(int)string_type::npos)\r
+ iEnd = (int)m_strFormula.length();\r
+\r
+ // Assign token string if there was something found\r
+ if (a_iPos!=iEnd)\r
+ {\r
+ a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);\r
+ return iEnd;\r
+ }\r
+ else\r
+ {\r
+ // There is still the chance of having to deal with an operator consisting exclusively\r
+ // of alphabetic characters.\r
+ return ExtractToken(MUP_CHARS, a_sTok, a_iPos);\r
+ }\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check if a built in operator or other token can be found\r
+ \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token.\r
+ \return true if an operator token has been found.\r
+ */\r
+ bool ParserTokenReader::IsBuiltIn(token_type &a_Tok)\r
+ {\r
+ const char_type **const pOprtDef = m_pParser->GetOprtDef(),\r
+ *const szFormula = m_strFormula.c_str();\r
+\r
+ // Compare token with function and operator strings\r
+ // check string for operator/function\r
+ for (int i=0; pOprtDef[i]; i++)\r
+ {\r
+ std::size_t len( std::char_traits<char_type>::length(pOprtDef[i]) );\r
+ if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) )\r
+ {\r
+ switch(i)\r
+ {\r
+ //case cmAND:\r
+ //case cmOR:\r
+ //case cmXOR:\r
+ case cmLAND:\r
+ case cmLOR:\r
+ case cmLT:\r
+ case cmGT:\r
+ case cmLE:\r
+ case cmGE:\r
+ case cmNEQ: \r
+ case cmEQ:\r
+ case cmADD:\r
+ case cmSUB:\r
+ case cmMUL:\r
+ case cmDIV:\r
+ case cmPOW:\r
+ case cmASSIGN:\r
+ //if (len!=sTok.length())\r
+ // continue;\r
+\r
+ // The assignement operator need special treatment\r
+ if (i==cmASSIGN && m_iSynFlags & noASSIGN)\r
+ Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);\r
+\r
+ if (!m_pParser->HasBuiltInOprt()) continue;\r
+ if (m_iSynFlags & noOPT) \r
+ {\r
+ // Maybe its an infix operator not an operator\r
+ // Both operator types can share characters in \r
+ // their identifiers\r
+ if ( IsInfixOpTok(a_Tok) ) \r
+ return true;\r
+\r
+ Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);\r
+ }\r
+\r
+ m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;\r
+ m_iSynFlags |= ( (i != cmEND) && ( i != cmBC) ) ? noEND : 0;\r
+ break;\r
+\r
+ case cmBO:\r
+ if (m_iSynFlags & noBO)\r
+ Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);\r
+ \r
+ if (m_lastTok.GetCode()==cmFUNC)\r
+ m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE;\r
+ else\r
+ m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN| noIF | noELSE;\r
+\r
+ ++m_iBrackets;\r
+ break;\r
+\r
+ case cmBC:\r
+ if (m_iSynFlags & noBC)\r
+ Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);\r
+\r
+ m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN;\r
+\r
+ if (--m_iBrackets<0)\r
+ Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);\r
+ break;\r
+\r
+ case cmELSE:\r
+ if (m_iSynFlags & noELSE)\r
+ Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);\r
+\r
+ m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE;\r
+ break;\r
+\r
+ case cmIF:\r
+ if (m_iSynFlags & noIF)\r
+ Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);\r
+\r
+ m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE;\r
+ break;\r
+\r
+ default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing...\r
+ Error(ecINTERNAL_ERROR);\r
+ } // switch operator id\r
+\r
+ m_iPos += (int)len;\r
+ a_Tok.Set( (ECmdCode)i, pOprtDef[i] );\r
+ return true;\r
+ } // if operator string found\r
+ } // end of for all operator strings\r
+ \r
+ return false;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ bool ParserTokenReader::IsArgSep(token_type &a_Tok)\r
+ {\r
+ const char_type* szFormula = m_strFormula.c_str();\r
+\r
+ if (szFormula[m_iPos]==m_cArgSep)\r
+ {\r
+ // copy the separator into null terminated string\r
+ char_type szSep[2];\r
+ szSep[0] = m_cArgSep;\r
+ szSep[1] = 0;\r
+\r
+ if (m_iSynFlags & noARG_SEP)\r
+ Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep);\r
+\r
+ m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN;\r
+ m_iPos++;\r
+ a_Tok.Set(cmARG_SEP, szSep);\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check for End of Formula.\r
+\r
+ \return true if an end of formula is found false otherwise.\r
+ \param a_Tok [out] If an eof is found the corresponding token will be stored there.\r
+ \throw nothrow\r
+ \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok\r
+ */\r
+ bool ParserTokenReader::IsEOF(token_type &a_Tok)\r
+ {\r
+ const char_type* szFormula = m_strFormula.c_str();\r
+\r
+ // check for EOF\r
+ if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/)\r
+ {\r
+ if ( m_iSynFlags & noEND )\r
+ Error(ecUNEXPECTED_EOF, m_iPos);\r
+\r
+ if (m_iBrackets>0)\r
+ Error(ecMISSING_PARENS, m_iPos, _T(")"));\r
+\r
+ m_iSynFlags = 0;\r
+ a_Tok.Set(cmEND);\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check if a string position contains a unary infix operator. \r
+ \return true if a function token has been found false otherwise.\r
+ */\r
+ bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok)\r
+ {\r
+ string_type sTok;\r
+ int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos);\r
+ if (iEnd==m_iPos)\r
+ return false;\r
+\r
+ // iteraterate over all postfix operator strings\r
+ funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin();\r
+ for ( ; it!=m_pInfixOprtDef->rend(); ++it)\r
+ {\r
+ if (sTok.find(it->first)!=0)\r
+ continue;\r
+\r
+ a_Tok.Set(it->second, it->first);\r
+ m_iPos += (int)it->first.length();\r
+\r
+ if (m_iSynFlags & noINFIXOP) \r
+ Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());\r
+\r
+ m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN;\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+\r
+/*\r
+ a_Tok.Set(item->second, sTok);\r
+ m_iPos = (int)iEnd;\r
+\r
+ if (m_iSynFlags & noINFIXOP) \r
+ Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());\r
+\r
+ m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; \r
+ return true;\r
+*/\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check whether the token at a given position is a function token.\r
+ \param a_Tok [out] If a value token is found it will be placed here.\r
+ \throw ParserException if Syntaxflags do not allow a function at a_iPos\r
+ \return true if a function token has been found false otherwise.\r
+ \pre [assert] m_pParser!=0\r
+ */\r
+ bool ParserTokenReader::IsFunTok(token_type &a_Tok)\r
+ {\r
+ string_type strTok;\r
+ int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);\r
+ if (iEnd==m_iPos)\r
+ return false;\r
+\r
+ funmap_type::const_iterator item = m_pFunDef->find(strTok);\r
+ if (item==m_pFunDef->end())\r
+ return false;\r
+\r
+ // Check if the next sign is an opening bracket\r
+ const char_type *szFormula = m_strFormula.c_str();\r
+ if (szFormula[iEnd]!='(')\r
+ return false;\r
+\r
+ a_Tok.Set(item->second, strTok);\r
+\r
+ m_iPos = (int)iEnd;\r
+ if (m_iSynFlags & noFUN)\r
+ Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString());\r
+\r
+ m_iSynFlags = noANY ^ noBO;\r
+ return true;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check if a string position contains a binary operator.\r
+ \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token.\r
+ \return true if an operator token has been found.\r
+ */\r
+ bool ParserTokenReader::IsOprt(token_type &a_Tok)\r
+ {\r
+ const char_type *const szExpr = m_strFormula.c_str();\r
+ string_type strTok;\r
+\r
+ int iEnd = ExtractOperatorToken(strTok, m_iPos);\r
+ if (iEnd==m_iPos)\r
+ return false;\r
+\r
+ // Check if the operator is a built in operator, if so ignore it here\r
+ const char_type **const pOprtDef = m_pParser->GetOprtDef();\r
+ for (int i=0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i)\r
+ {\r
+ if (string_type(pOprtDef[i])==strTok)\r
+ return false;\r
+ }\r
+\r
+ // Note:\r
+ // All tokens in oprt_bin_maptype are have been sorted by their length\r
+ // Long operators must come first! Otherwise short names (like: "add") that\r
+ // are part of long token names (like: "add123") will be found instead \r
+ // of the long ones.\r
+ // Length sorting is done with ascending length so we use a reverse iterator here.\r
+ funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin();\r
+ for ( ; it!=m_pOprtDef->rend(); ++it)\r
+ {\r
+ const string_type &sID = it->first;\r
+ if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) )\r
+ {\r
+ a_Tok.Set(it->second, strTok);\r
+\r
+ // operator was found\r
+ if (m_iSynFlags & noOPT) \r
+ {\r
+ // An operator was found but is not expected to occur at\r
+ // this position of the formula, maybe it is an infix \r
+ // operator, not a binary operator. Both operator types\r
+ // can share characters in their identifiers.\r
+ if ( IsInfixOpTok(a_Tok) ) \r
+ return true;\r
+ else\r
+ {\r
+ // nope, no infix operator\r
+ return false;\r
+ //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); \r
+ }\r
+\r
+ }\r
+\r
+ m_iPos += (int)sID.length();\r
+ m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noBC | noASSIGN;\r
+ return true;\r
+ }\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check if a string position contains a unary post value operator. */\r
+ bool ParserTokenReader::IsPostOpTok(token_type &a_Tok)\r
+ {\r
+ // <ibg 20110629> Do not check for postfix operators if they are not allowed at\r
+ // the current expression index.\r
+ //\r
+ // This will fix the bug reported here: \r
+ //\r
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979\r
+ //\r
+ if (m_iSynFlags & noPOSTOP)\r
+ return false;\r
+ // </ibg>\r
+\r
+ // Tricky problem with equations like "3m+5":\r
+ // m is a postfix operator, + is a valid sign for postfix operators and \r
+ // for binary operators parser detects "m+" as operator string and \r
+ // finds no matching postfix operator.\r
+ // \r
+ // This is a special case so this routine slightly differs from the other\r
+ // token readers.\r
+ \r
+ // Test if there could be a postfix operator\r
+ string_type sTok;\r
+ int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos);\r
+ if (iEnd==m_iPos)\r
+ return false;\r
+\r
+ // iteraterate over all postfix operator strings\r
+ funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin();\r
+ for ( ; it!=m_pPostOprtDef->rend(); ++it)\r
+ {\r
+ if (sTok.find(it->first)!=0)\r
+ continue;\r
+\r
+ a_Tok.Set(it->second, sTok);\r
+ m_iPos += (int)it->first.length();\r
+\r
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN;\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check whether the token at a given position is a value token.\r
+\r
+ Value tokens are either values or constants.\r
+\r
+ \param a_Tok [out] If a value token is found it will be placed here.\r
+ \return true if a value token has been found.\r
+ */\r
+ bool ParserTokenReader::IsValTok(token_type &a_Tok)\r
+ {\r
+ assert(m_pConstDef);\r
+ assert(m_pParser);\r
+\r
+ string_type strTok;\r
+ value_type fVal(0);\r
+ int iEnd(0);\r
+ \r
+ // 2.) Check for user defined constant\r
+ // Read everything that could be a constant name\r
+ iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);\r
+ if (iEnd!=m_iPos)\r
+ {\r
+ valmap_type::const_iterator item = m_pConstDef->find(strTok);\r
+ if (item!=m_pConstDef->end())\r
+ {\r
+ m_iPos = iEnd;\r
+ a_Tok.SetVal(item->second, strTok);\r
+\r
+ if (m_iSynFlags & noVAL)\r
+ Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);\r
+\r
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; \r
+ return true;\r
+ }\r
+ }\r
+\r
+ // 3.call the value recognition functions provided by the user\r
+ // Call user defined value recognition functions\r
+ std::list<identfun_type>::const_iterator item = m_vIdentFun.begin();\r
+ for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item)\r
+ {\r
+ int iStart = m_iPos;\r
+ if ( (*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 )\r
+ {\r
+ strTok.assign(m_strFormula.c_str(), iStart, m_iPos);\r
+ if (m_iSynFlags & noVAL)\r
+ Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);\r
+\r
+ a_Tok.SetVal(fVal, strTok);\r
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;\r
+ return true;\r
+ }\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check wheter a token at a given position is a variable token. \r
+ \param a_Tok [out] If a variable token has been found it will be placed here.\r
+ \return true if a variable token has been found.\r
+ */\r
+ bool ParserTokenReader::IsVarTok(token_type &a_Tok)\r
+ {\r
+ if (!m_pVarDef->size())\r
+ return false;\r
+\r
+ string_type strTok;\r
+ int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);\r
+ if (iEnd==m_iPos)\r
+ return false;\r
+\r
+ varmap_type::const_iterator item = m_pVarDef->find(strTok);\r
+ if (item==m_pVarDef->end())\r
+ return false;\r
+\r
+ if (m_iSynFlags & noVAR)\r
+ Error(ecUNEXPECTED_VAR, m_iPos, strTok);\r
+\r
+ m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd);\r
+\r
+ m_iPos = iEnd;\r
+ a_Tok.SetVar(item->second, strTok);\r
+ m_UsedVar[item->first] = item->second; // Add variable to used-var-list\r
+\r
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR;\r
+\r
+// Zur Info hier die SynFlags von IsVal():\r
+// m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; \r
+ return true;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ bool ParserTokenReader::IsStrVarTok(token_type &a_Tok)\r
+ {\r
+ if (!m_pStrVarDef || !m_pStrVarDef->size())\r
+ return false;\r
+\r
+ string_type strTok;\r
+ int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);\r
+ if (iEnd==m_iPos)\r
+ return false;\r
+\r
+ strmap_type::const_iterator item = m_pStrVarDef->find(strTok);\r
+ if (item==m_pStrVarDef->end())\r
+ return false;\r
+\r
+ if (m_iSynFlags & noSTR)\r
+ Error(ecUNEXPECTED_VAR, m_iPos, strTok);\r
+\r
+ m_iPos = iEnd;\r
+ if (!m_pParser->m_vStringVarBuf.size())\r
+ Error(ecINTERNAL_ERROR);\r
+\r
+ a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() );\r
+\r
+ m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP);\r
+ return true;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check wheter a token at a given position is an undefined variable. \r
+\r
+ \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here.\r
+ \return true if a variable token has been found.\r
+ \throw nothrow\r
+ */\r
+ bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok)\r
+ {\r
+ string_type strTok;\r
+ int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) );\r
+ if ( iEnd==m_iPos )\r
+ return false;\r
+\r
+ if (m_iSynFlags & noVAR)\r
+ {\r
+ // <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the \r
+ // token identifier. \r
+ // related bug report:\r
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979\r
+ Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok);\r
+ }\r
+\r
+ // If a factory is available implicitely create new variables\r
+ if (m_pFactory)\r
+ {\r
+ value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData);\r
+ a_Tok.SetVar(fVar, strTok );\r
+\r
+ // Do not use m_pParser->DefineVar( strTok, fVar );\r
+ // in order to define the new variable, it will clear the\r
+ // m_UsedVar array which will kill previousely defined variables\r
+ // from the list\r
+ // This is safe because the new variable can never override an existing one\r
+ // because they are checked first!\r
+ (*m_pVarDef)[strTok] = fVar;\r
+ m_UsedVar[strTok] = fVar; // Add variable to used-var-list\r
+ }\r
+ else\r
+ {\r
+ a_Tok.SetVar((value_type*)&m_fZero, strTok);\r
+ m_UsedVar[strTok] = 0; // Add variable to used-var-list\r
+ }\r
+\r
+ m_iPos = iEnd;\r
+\r
+ // Call the variable factory in order to let it define a new parser variable\r
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR;\r
+ return true;\r
+ }\r
+\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Check wheter a token at a given position is a string.\r
+ \param a_Tok [out] If a variable token has been found it will be placed here.\r
+ \return true if a string token has been found.\r
+ \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok\r
+ \throw nothrow\r
+ */\r
+ bool ParserTokenReader::IsString(token_type &a_Tok)\r
+ {\r
+ if (m_strFormula[m_iPos]!='"') \r
+ return false;\r
+\r
+ string_type strBuf(&m_strFormula[m_iPos+1]);\r
+ std::size_t iEnd(0), iSkip(0);\r
+\r
+ // parser over escaped '\"' end replace them with '"'\r
+ for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=0 && iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd))\r
+ {\r
+ if (strBuf[iEnd-1]!='\\') break;\r
+ strBuf.replace(iEnd-1, 2, _T("\"") );\r
+ iSkip++;\r
+ }\r
+\r
+ if (iEnd==string_type::npos)\r
+ Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") );\r
+\r
+ string_type strTok(strBuf.begin(), strBuf.begin()+iEnd);\r
+\r
+ if (m_iSynFlags & noSTR)\r
+ Error(ecUNEXPECTED_STR, m_iPos, strTok);\r
+\r
+ m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer\r
+ a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size());\r
+\r
+ m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 wg Anführungszeichen; +iSkip für entfernte escape zeichen\r
+ m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND );\r
+\r
+ return true;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ /** \brief Create an error containing the parse error position.\r
+\r
+ This function will create an Parser Exception object containing the error text and its position.\r
+\r
+ \param a_iErrc [in] The error code of type #EErrorCodes.\r
+ \param a_iPos [in] The position where the error was detected.\r
+ \param a_strTok [in] The token string representation associated with the error.\r
+ \throw ParserException always throws thats the only purpose of this function.\r
+ */\r
+ void ParserTokenReader::Error( EErrorCodes a_iErrc, \r
+ int a_iPos, \r
+ const string_type &a_sTok) const\r
+ {\r
+ m_pParser->Error(a_iErrc, a_iPos, a_sTok);\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ void ParserTokenReader::SetArgSep(char_type cArgSep)\r
+ {\r
+ m_cArgSep = cArgSep;\r
+ }\r
+\r
+ //---------------------------------------------------------------------------\r
+ char_type ParserTokenReader::GetArgSep() const\r
+ {\r
+ return m_cArgSep;\r
+ }\r
+} // namespace mu\r
+\r
OFF)
SET(UMFPACK_FOLDER "${CMAKE_SOURCE_DIR}/bundled/umfpack")
+
+
+#
+# muparser
+#
+SET(FEATURE_MUPARSER_HAVE_BUNDLED TRUE)
+
+OPTION(DEAL_II_FORCE_BUNDLED_MUPARSER
+ "Always use the bundled functionparser library instead of an external one."
+ OFF)
+
+SET(MUPARSER_FOLDER "${CMAKE_SOURCE_DIR}/bundled/muparser_v2_2_3/")
# Configuration for the MUPARSER library:
#
+MACRO(FEATURE_MUPARSER_FIND_EXTERNAL var)
+ MESSAGE(STATUS
+ "No module available for finding functionparser externally."
+ )
+ENDMACRO()
+
+
+MACRO(FEATURE_MUPARSER_CONFIGURE_BUNDLED)
+ SET(MUPARSER_BUNDLED_INCLUDE_DIRS ${MUPARSER_FOLDER}/include)
+ENDMACRO()
+
+
+MACRO(FEATURE_MUPARSER_ERROR_MESSAGE)
+ MESSAGE(FATAL_ERROR "\n"
+ "No module available for finding functionparser externally.\n"
+ "Disable DEAL_II_WITH_MUPARSER, or enable DEAL_II_ALLOW_BUNDLED.\n\n"
+ )
+ENDMACRO()
+
+
CONFIGURE_FEATURE(MUPARSER)