aboutsummaryrefslogtreecommitdiffstats
path: root/muparser
diff options
context:
space:
mode:
authorastrojhgu <astrojhgu@ed2142bd-67ad-457f-ba7c-d818d4011675>2008-12-15 07:26:12 +0000
committerastrojhgu <astrojhgu@ed2142bd-67ad-457f-ba7c-d818d4011675>2008-12-15 07:26:12 +0000
commit1f4a944064bc42284c33e6b755353d191cf288e8 (patch)
treec8cb2253dea5f395e0f867aa6976433bd3eb00de /muparser
downloadopt-utilities-1f4a944064bc42284c33e6b755353d191cf288e8.tar.bz2
git-svn-id: file:///home/svn/opt_utilities@1 ed2142bd-67ad-457f-ba7c-d818d4011675
Diffstat (limited to 'muparser')
-rw-r--r--muparser/makefile16
-rw-r--r--muparser/muParser.cpp259
-rw-r--r--muparser/muParser.h104
-rw-r--r--muparser/muParserBase.cpp1364
-rw-r--r--muparser/muParserBase.h324
-rw-r--r--muparser/muParserBytecode.cpp396
-rw-r--r--muparser/muParserBytecode.h148
-rw-r--r--muparser/muParserCallback.cpp198
-rw-r--r--muparser/muParserCallback.h94
-rw-r--r--muparser/muParserDLL.cpp657
-rw-r--r--muparser/muParserDLL.h123
-rw-r--r--muparser/muParserDef.h239
-rw-r--r--muparser/muParserError.cpp300
-rw-r--r--muparser/muParserError.h160
-rw-r--r--muparser/muParserFixes.h196
-rw-r--r--muparser/muParserInt.cpp264
-rw-r--r--muparser/muParserInt.h93
-rw-r--r--muparser/muParserStack.h120
-rw-r--r--muparser/muParserTest.cpp1125
-rw-r--r--muparser/muParserTest.h176
-rw-r--r--muparser/muParserToken.h464
-rw-r--r--muparser/muParserTokenReader.cpp822
-rw-r--r--muparser/muParserTokenReader.h156
23 files changed, 7798 insertions, 0 deletions
diff --git a/muparser/makefile b/muparser/makefile
new file mode 100644
index 0000000..83d2cd5
--- /dev/null
+++ b/muparser/makefile
@@ -0,0 +1,16 @@
+MUP_OBJ=muParserBase.o muParser.o muParserInt.o\
+ muParserBytecode.o muParserDLL.o\
+ muParserTest.o\
+ muParserCallback.o muParserError.o\
+ muParserTokenReader.o
+
+libmuparser.a:$(MUP_OBJ)
+ $(AR) $@ *.o
+
+.cpp.o:
+ $(CPP) $< $(CPPFLAGS)
+
+clean:
+ $(RM) *.o
+
+
diff --git a/muparser/muParser.cpp b/muparser/muParser.cpp
new file mode 100644
index 0000000..e92b1a2
--- /dev/null
+++ b/muparser/muParser.cpp
@@ -0,0 +1,259 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#include "muParser.h"
+
+#include <cmath>
+#include <algorithm>
+#include <numeric>
+
+/** \brief Pi (what else?). */
+#define PARSER_CONST_PI 3.141592653589793238462643
+
+/** \brief The eulerian number. */
+#define PARSER_CONST_E 2.718281828459045235360287
+
+using namespace std;
+
+
+/** \brief Namespace for mathematical applications. */
+namespace mu
+{
+
+//---------------------------------------------------------------------------
+// Trigonometric function
+value_type Parser::Sin(value_type v) { return sin(v); }
+value_type Parser::Cos(value_type v) { return cos(v); }
+value_type Parser::Tan(value_type v) { return tan(v); }
+value_type Parser::ASin(value_type v) { return asin(v); }
+value_type Parser::ACos(value_type v) { return acos(v); }
+value_type Parser::ATan(value_type v) { return atan(v); }
+value_type Parser::Sinh(value_type v) { return sinh(v); }
+value_type Parser::Cosh(value_type v) { return cosh(v); }
+value_type Parser::Tanh(value_type v) { return tanh(v); }
+value_type Parser::ASinh(value_type v) { return log(v + sqrt(v * v + 1)); }
+value_type Parser::ACosh(value_type v) { return log(v + sqrt(v * v - 1)); }
+value_type Parser::ATanh(value_type v) { return ((value_type)0.5 * log((1 + v) / (1 - v))); }
+
+//---------------------------------------------------------------------------
+// Logarithm functions
+value_type Parser::Log2(value_type v) { return log(v)/log((value_type)2); } // Logarithm base 2
+value_type Parser::Log10(value_type v) { return log10(v); } // Logarithm base 10
+value_type Parser::Ln(value_type v) { return log(v); } // Logarithm base e (natural logarithm)
+
+//---------------------------------------------------------------------------
+// misc
+value_type Parser::Exp(value_type v) { return exp(v); }
+value_type Parser::Abs(value_type v) { return fabs(v); }
+value_type Parser::Sqrt(value_type v) { return sqrt(v); }
+value_type Parser::Rint(value_type v) { return floor(v + (value_type)0.5); }
+value_type Parser::Sign(value_type v) { return (value_type)((v<0) ? -1 : (v>0) ? 1 : 0); }
+
+//---------------------------------------------------------------------------
+// Conditional (if then else)
+value_type Parser::Ite(value_type v1, value_type v2, value_type v3) { return (v1==1) ? v2 : v3; }
+
+//---------------------------------------------------------------------------
+// Unary operator Callbacks: Infix operators
+value_type Parser::UnaryMinus(value_type v) { return -v; }
+
+//---------------------------------------------------------------------------
+// Functions with variable number of arguments
+// sum
+value_type Parser::Sum(const value_type *a_afArg, int a_iArgc)
+{
+ if (!a_iArgc)
+ throw exception_type(_T("too few arguments for function sum."));
+
+ value_type fRes=0;
+ for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];
+ return fRes;
+}
+
+//---------------------------------------------------------------------------
+// mean value
+value_type Parser::Avg(const value_type *a_afArg, int a_iArgc)
+{
+ if (!a_iArgc)
+ throw exception_type(_T("too few arguments for function sum."));
+
+ value_type fRes=0;
+ for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];
+ return fRes/(double)a_iArgc;
+}
+
+//---------------------------------------------------------------------------
+// minimum
+value_type Parser::Min(const value_type *a_afArg, int a_iArgc)
+{
+ if (!a_iArgc)
+ throw exception_type(_T("too few arguments for function min."));
+
+ value_type fRes=a_afArg[0];
+ for (int i=0; i<a_iArgc; ++i) fRes = std::min(fRes, a_afArg[i]);
+
+ return fRes;
+}
+
+//---------------------------------------------------------------------------
+// maximum
+value_type Parser::Max(const value_type *a_afArg, int a_iArgc)
+{
+ if (!a_iArgc)
+ throw exception_type(_T("too few arguments for function min."));
+
+ value_type fRes=a_afArg[0];
+ for (int i=0; i<a_iArgc; ++i) fRes = std::max(fRes, a_afArg[i]);
+
+ return fRes;
+}
+
+//---------------------------------------------------------------------------
+// Default value recognition callback
+bool Parser::IsVal(const char_type *a_szExpr, int &a_iPos, value_type &a_fVal)
+{
+ value_type fVal(0);
+
+// thanks to CodeProject member sailorickm for writing this fix:
+// http://www.codeproject.com/cpp/FastMathParser.asp?msg=1354598#xx1354598xx
+// i cant test it myself, if you see problems please contact me.
+#if defined (__hpux) || (defined __GNUC__ && (__GNUC__ == 3 && (__GNUC_MINOR__ < 3 )))
+ int iEnd = 0;
+ int nAssigned = sscanf(a_szExpr, "%lf%n", &fVal, &iEnd);
+ if (nAssigned == 0)
+ iEnd = -1;
+#else
+ stringstream_type stream(a_szExpr);
+ stream.seekg(0); // todo: check if this really is necessary
+ stream >> fVal;
+ int iEnd = stream.tellg(); // Position after reading
+#endif
+
+ if (iEnd==-1)
+ return false;
+
+ a_iPos += iEnd;
+ a_fVal = fVal;
+ return true;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Constructor.
+
+ Call ParserBase class constructor and trigger Function, Operator and Constant initialization.
+*/
+Parser::Parser()
+ :ParserBase()
+ ,m_fEpsilon((value_type)1e-7)
+{
+ AddValIdent(IsVal);
+
+ InitCharSets();
+ InitFun();
+ InitConst();
+ InitOprt();
+}
+
+//---------------------------------------------------------------------------
+/** Define the character sets. */
+void Parser::InitCharSets()
+{
+ DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") );
+ DefineOprtChars( _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_") );
+ DefineInfixOprtChars( _T("/+-*^?<>=#!$%&|~'_") );
+}
+
+//---------------------------------------------------------------------------
+/** \brief Initialize the default functions. */
+void Parser::InitFun()
+{
+ // trigonometric functions
+ DefineFun(_T("sin"), Sin);
+ DefineFun(_T("cos"), Cos);
+ DefineFun(_T("tan"), Tan);
+ // arcus functions
+ DefineFun(_T("asin"), ASin);
+ DefineFun(_T("acos"), ACos);
+ DefineFun(_T("atan"), ATan);
+ // hyperbolic functions
+ DefineFun(_T("sinh"), Sinh);
+ DefineFun(_T("cosh"), Cosh);
+ DefineFun(_T("tanh"), Tanh);
+ // arcus hyperbolic functions
+ DefineFun(_T("asinh"), ASinh);
+ DefineFun(_T("acosh"), ACosh);
+ DefineFun(_T("atanh"), ATanh);
+ // Logarithm functions
+ DefineFun(_T("log2"), Log2);
+ DefineFun(_T("log10"), Log10);
+ DefineFun(_T("log"), Log10);
+ DefineFun(_T("ln"), Ln);
+ // misc
+ DefineFun(_T("exp"), Exp);
+ DefineFun(_T("sqrt"), Sqrt);
+ DefineFun(_T("sign"), Sign);
+ DefineFun(_T("rint"), Rint);
+ DefineFun(_T("abs"), Abs);
+ DefineFun(_T("if"), Ite);
+ // Functions with variable number of arguments
+ DefineFun(_T("sum"), Sum);
+ DefineFun(_T("avg"), Avg);
+ DefineFun(_T("min"), Min);
+ DefineFun(_T("max"), Max);
+}
+
+//---------------------------------------------------------------------------
+/** \brief Initialize operators. */
+void Parser::InitConst()
+{
+ DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI);
+ DefineConst(_T("_e"), (value_type)PARSER_CONST_E);
+}
+
+//---------------------------------------------------------------------------
+/** \brief Initialize operators. */
+void Parser::InitOprt()
+{
+ DefineInfixOprt(_T("-"), UnaryMinus);
+}
+
+//---------------------------------------------------------------------------
+/** \brief Numerically differentiate with regard to a variable. */
+value_type Parser::Diff(value_type *a_Var, value_type a_fPos) const
+{
+ assert(m_fEpsilon);
+ value_type fEpsilon( (a_fPos==0) ? (value_type)1e-10 : m_fEpsilon * a_fPos ),
+ fRes(0), fBuf(*a_Var), f[4] = {0,0,0,0};
+
+ *a_Var = a_fPos+2*fEpsilon; f[0] = Eval();
+ *a_Var = a_fPos+1*fEpsilon; f[1] = Eval();
+ *a_Var = a_fPos-1*fEpsilon; f[2] = Eval();
+ *a_Var = a_fPos-2*fEpsilon; f[3] = Eval();
+ *a_Var = fBuf; // restore variable
+
+ fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon);
+ return fRes;
+}
+
+} // namespace mu
diff --git a/muparser/muParser.h b/muparser/muParser.h
new file mode 100644
index 0000000..5aff62d
--- /dev/null
+++ b/muparser/muParser.h
@@ -0,0 +1,104 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef MU_PARSER_H
+#define MU_PARSER_H
+
+#include "muParserBase.h"
+#include <vector>
+
+
+namespace mu
+{
+
+/** \brief Mathematical expressions parser (reference implementation).
+
+ Standard implementation of the mathematical expressions parser.
+ Can be used as a reference implementation for subclassing the parser.
+
+ <small>
+ (C) 2004-2006 Ingo Berg<br>
+ ingo_berg(at)gmx.de
+ </small>
+*/
+class Parser : public ParserBase
+{
+private:
+ // Trigonometric functions
+ static value_type Sin(value_type);
+ static value_type Cos(value_type);
+ static value_type Tan(value_type);
+ // arcus functions
+ static value_type ASin(value_type);
+ static value_type ACos(value_type);
+ static value_type ATan(value_type);
+ // hyperbolic functions
+ static value_type Sinh(value_type);
+ static value_type Cosh(value_type);
+ static value_type Tanh(value_type);
+ // arcus hyperbolic functions
+ static value_type ASinh(value_type);
+ static value_type ACosh(value_type);
+ static value_type ATanh(value_type);
+ // Logarithm functions
+ static value_type Log2(value_type); // Logarithm Base 2
+ static value_type Log10(value_type); // Logarithm Base 10
+ static value_type Ln(value_type); // Logarithm Base e (natural logarithm)
+ // misc
+ static value_type Exp(value_type);
+ static value_type Abs(value_type);
+ static value_type Sqrt(value_type);
+ static value_type Rint(value_type);
+ static value_type Sign(value_type);
+ static value_type Ite(value_type, value_type, value_type);
+
+ // Prefix operators
+ // !!! Unary Minus is a MUST if you want to use negative signs !!!
+ static value_type UnaryMinus(value_type);
+
+ // Functions with variable number of arguments
+ static value_type Sum(const value_type*, int); // sum
+ static value_type Avg(const value_type*, int); // mean value
+ static value_type Min(const value_type*, int); // minimum
+ static value_type Max(const value_type*, int); // maximum
+
+ static bool IsVal(const char_type *a_szExpr, int &a_iPos, value_type &a_fVal);
+
+ value_type m_fEpsilon; ///< Epsilon used for numerical differentiation.
+
+public:
+ Parser();
+
+ virtual void InitCharSets();
+ virtual void InitFun();
+ virtual void InitConst();
+ virtual void InitOprt();
+
+ value_type Diff(value_type *a_Var, value_type a_fPos) const;
+};
+
+} // namespace mu
+
+#endif
+
diff --git a/muparser/muParserBase.cpp b/muparser/muParserBase.cpp
new file mode 100644
index 0000000..e81e53e
--- /dev/null
+++ b/muparser/muParserBase.cpp
@@ -0,0 +1,1364 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "muParser.h"
+
+#include <cassert>
+#include <cmath>
+#include <memory>
+#include <vector>
+#include <sstream>
+
+using namespace std;
+
+
+namespace mu
+{
+
+//------------------------------------------------------------------------------
+/** \brief Identifiers for built in binary operators.
+
+ When defining custom binary operators with #AddOprt(...) make sure not to choose
+ names conflicting with these definitions.
+*/
+const char_type* ParserBase::c_DefaultOprt[] =
+{
+ _T("<="), _T(">="), _T("!="),
+ _T("=="), _T("<"), _T(">"),
+ _T("+"), _T("-"), _T("*"),
+ _T("/"), _T("^"), _T("and"),
+ _T("or"), _T("xor"), _T("="),
+ _T("("), _T(")"), _T(","), 0
+};
+
+//------------------------------------------------------------------------------
+/** \brief Constructor.
+ \param a_szFormula the formula to interpret.
+ \throw ParserException if a_szFormula is null.
+*/
+ParserBase::ParserBase()
+ :m_pParseFormula(&ParserBase::ParseString)
+ ,m_pCmdCode(0)
+ ,m_vByteCode()
+ ,m_vStringBuf()
+ ,m_pTokenReader()
+ ,m_FunDef()
+ ,m_PostOprtDef()
+ ,m_InfixOprtDef()
+ ,m_OprtDef()
+ ,m_ConstDef()
+ ,m_StrVarDef()
+ ,m_VarDef()
+ ,m_bOptimize(true)
+ ,m_bUseByteCode(true)
+ ,m_bBuiltInOp(true)
+ ,m_sNameChars()
+ ,m_sOprtChars()
+ ,m_sInfixOprtChars()
+{
+ InitTokenReader();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Copy constructor.
+
+ Implemented by calling Assign(a_Parser)
+*/
+ParserBase::ParserBase(const ParserBase &a_Parser)
+ :m_pParseFormula(&ParserBase::ParseString)
+ ,m_pCmdCode(0)
+ ,m_vByteCode()
+ ,m_vStringBuf()
+ ,m_pTokenReader()
+ ,m_FunDef()
+ ,m_PostOprtDef()
+ ,m_InfixOprtDef()
+ ,m_OprtDef()
+ ,m_ConstDef()
+ ,m_StrVarDef()
+ ,m_VarDef()
+ ,m_bOptimize(true)
+ ,m_bUseByteCode(true)
+ ,m_bBuiltInOp(true)
+{
+ m_pTokenReader.reset(new token_reader_type(this));
+ Assign(a_Parser);
+}
+
+//---------------------------------------------------------------------------
+/** \brief Assignement operator.
+
+ Implemented by calling Assign(a_Parser). Self assignement is suppressed.
+ \param a_Parser Object to copy to this.
+ \return *this
+ \throw nothrow
+*/
+ParserBase& ParserBase::operator=(const ParserBase &a_Parser)
+{
+ Assign(a_Parser);
+ return *this;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Copy state of a parser object to this.
+
+ Clears Variables and Functions of this parser.
+ Copies the states of all internal variables.
+ Resets parse function to string parse mode.
+
+ \param a_Parser the source object.
+*/
+void ParserBase::Assign(const ParserBase &a_Parser)
+{
+ if (&a_Parser==this)
+ return;
+
+ // Don't copy bytecode instead cause the parser to create new bytecode
+ // by resetting the parse function.
+ ReInit();
+
+ m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants
+ m_VarDef = a_Parser.m_VarDef; // Copy user defined variables
+ m_bOptimize = a_Parser.m_bOptimize;
+ m_bUseByteCode = a_Parser.m_bUseByteCode;
+ m_bBuiltInOp = a_Parser.m_bBuiltInOp;
+ m_vStringBuf = a_Parser.m_vStringBuf;
+ m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this));
+ m_StrVarDef = a_Parser.m_StrVarDef;
+ m_vStringVarBuf = a_Parser.m_vStringVarBuf;
+
+ // Copy function and operator callbacks
+ m_FunDef = a_Parser.m_FunDef; // Copy function definitions
+ m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators
+ m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation
+
+ m_sNameChars = a_Parser.m_sNameChars;
+ m_sOprtChars = a_Parser.m_sOprtChars;
+ m_sInfixOprtChars = a_Parser.m_sInfixOprtChars;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Initialize the token reader.
+
+ Create new token reader object and submit pointers to function, operator,
+ constant and variable definitions.
+
+ \post m_pTokenReader.get()!=0
+ \throw nothrow
+*/
+void ParserBase::InitTokenReader()
+{
+ m_pTokenReader.reset(new token_reader_type(this));
+}
+
+//---------------------------------------------------------------------------
+/** \brief Reset parser to string parsing mode and clear internal buffers.
+
+ Clear bytecode, reset the token reader.
+ \throw nothrow
+*/
+void ParserBase::ReInit() const
+{
+ m_pParseFormula = &ParserBase::ParseString;
+ m_vStringBuf.clear();
+ m_vByteCode.clear();
+ m_pTokenReader->ReInit();
+}
+
+//---------------------------------------------------------------------------
+void ParserBase::AddValIdent(identfun_type a_pCallback)
+{
+ m_pTokenReader->AddValIdent(a_pCallback);
+}
+
+//---------------------------------------------------------------------------
+void ParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData)
+{
+ m_pTokenReader->SetVarCreator(a_pFactory, pUserData);
+}
+
+//---------------------------------------------------------------------------
+/** \brief Add a function or operator callback to the parser.
+*/
+void ParserBase::AddCallback( const string_type &a_strName,
+ const ParserCallback &a_Callback,
+ funmap_type &a_Storage,
+ const char_type *a_szCharSet )
+{
+ if (a_Callback.GetAddr()==0)
+ Error(ecINVALID_FUN_PTR);
+
+ const funmap_type *pFunMap = &a_Storage;
+
+ // Check for conflicting operator or function names
+ if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() )
+ Error(ecNAME_CONFLICT);
+
+ if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() )
+ Error(ecNAME_CONFLICT);
+
+ if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() )
+ Error(ecNAME_CONFLICT);
+
+ if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() )
+ Error(ecNAME_CONFLICT);
+
+ CheckName(a_strName, a_szCharSet);
+ a_Storage[a_strName] = a_Callback;
+ ReInit();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Check if a name contains invalid characters.
+
+ \throw ParserException if the name contains invalid charakters.
+*/
+void ParserBase::CheckName(const string_type &a_sName,
+ const string_type &a_szCharSet) const
+{
+ if ( !a_sName.length() ||
+ (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) ||
+ (a_sName[0]>='0' && a_sName[0]<='9'))
+ {
+ Error(ecINVALID_NAME);
+ }
+}
+
+//---------------------------------------------------------------------------
+/** \brief Set the formula.
+ Triggers first time calculation thus the creation of the bytecode and
+ scanning of used variables.
+
+ \param a_strFormula Formula as string_type
+ \throw ParserException in case of syntax errors.
+*/
+void ParserBase::SetExpr(const string_type &a_sExpr)
+{
+ // <ibg> 20060222: Bugfix for Borland-Kylix:
+ // adding a space to the expression will keep Borlands KYLIX from going wild
+ // when calling tellg on a stringstream created from the expression after
+ // reading a value at the end of an expression. (mu::Parser::IsVal function)
+ // (tellg returns -1 otherwise causing the parser to ignore the value)
+ string_type sBuf(a_sExpr + _T(" ") );
+ m_pTokenReader->SetFormula(sBuf);
+ ReInit();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Add a user defined operator.
+ \post Will reset the Parser to string parsing mode.
+*/
+void ParserBase::DefinePostfixOprt(const string_type &a_sName,
+ fun_type1 a_pFun,
+ bool a_bAllowOpt)
+{
+ AddCallback( a_sName,
+ ParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX),
+ m_PostOprtDef,
+ ValidOprtChars() );
+}
+
+//---------------------------------------------------------------------------
+/** \brief Add a user defined operator.
+ \post Will reset the Parser to string parsing mode.
+ \param a_sName [in] operator Identifier
+ \param a_pFun [in] Operator callback function
+ \param a_iPrec [in] Operator Precedence (default=prSIGN)
+ \param a_bAllowOpt [in] True if operator is volatile (default=false)
+
+ \sa EPrec
+*/
+void ParserBase::DefineInfixOprt(const string_type &a_sName,
+ fun_type1 a_pFun,
+ int a_iPrec,
+ bool a_bAllowOpt)
+{
+ AddCallback( a_sName,
+ ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX),
+ m_InfixOprtDef,
+ ValidOprtChars() );
+}
+
+//---------------------------------------------------------------------------
+void ParserBase::DefineOprt( const string_type &a_sName,
+ fun_type2 a_pFun,
+ unsigned a_iPrec,
+ bool a_bAllowOpt )
+{
+ // Check for conflicts with built in operator names
+ for (int i=0; m_bBuiltInOp && i<cmCOMMA; ++i)
+ if (a_sName == string_type(c_DefaultOprt[i]))
+ Error(ecBUILTIN_OVERLOAD);
+
+ AddCallback( a_sName,
+ ParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_BIN),
+ m_OprtDef,
+ ValidOprtChars() );
+}
+
+//---------------------------------------------------------------------------
+void ParserBase::DefineStrConst(const string_type &a_strName, const string_type &a_strVal)
+{
+ // Test if a constant with that names already exists
+ if (m_StrVarDef.find(a_strName)!=m_StrVarDef.end())
+ Error(ecNAME_CONFLICT);
+
+ CheckName(a_strName, ValidNameChars());
+
+ // Store variable string in internal buffer
+ m_vStringVarBuf.push_back(a_strVal);
+
+ // bind buffer index to variable name
+ m_StrVarDef[a_strName] = m_vStringBuf.size();
+
+ ReInit();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Add a user defined variable.
+ \post Will reset the Parser to string parsing mode.
+ \pre [assert] a_fVar!=0
+ \throw ParserException in case the name contains invalid signs.
+*/
+void ParserBase::DefineVar(const string_type &a_sName, value_type *a_pVar)
+{
+ if (a_pVar==0)
+ Error(ecINVALID_VAR_PTR);
+
+ // Test if a constant with that names already exists
+ if (m_ConstDef.find(a_sName)!=m_ConstDef.end())
+ Error(ecNAME_CONFLICT);
+
+ if (m_FunDef.find(a_sName)!=m_FunDef.end())
+ Error(ecNAME_CONFLICT);
+
+ CheckName(a_sName, ValidNameChars());
+ m_VarDef[a_sName] = a_pVar;
+ ReInit();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Add a user defined constant.
+ \post Will reset the Parser to string parsing mode.
+ \throw ParserException in case the name contains invalid signs.
+*/
+void ParserBase::DefineConst(const string_type &a_sName, value_type a_fVal)
+{
+ CheckName(a_sName, ValidNameChars());
+ m_ConstDef[a_sName] = a_fVal;
+ ReInit();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Get operator priority.
+
+ \throw ParserException if a_Oprt is no operator code
+*/
+int ParserBase::GetOprtPri(const token_type &a_Tok) const
+{
+ switch (a_Tok.GetCode())
+ {
+ // built in operators
+ case cmEND: return -5;
+ case cmCOMMA: return -4;
+ case cmBO :
+ case cmBC : return -2;
+ case cmASSIGN: return -1;
+ case cmAND:
+ case cmXOR:
+ case cmOR: return prLOGIC;
+ case cmLT :
+ case cmGT :
+ case cmLE :
+ case cmGE :
+ case cmNEQ:
+ case cmEQ : return prCMP;
+ case cmADD:
+ case cmSUB: return prADD_SUB;
+ case cmMUL:
+ case cmDIV: return prMUL_DIV;
+ case cmPOW: return prPOW;
+
+ // user defined binary operators
+ case cmOPRT_INFIX:
+ case cmOPRT_BIN: return a_Tok.GetPri();
+ default: Error(ecINTERNAL_ERROR, 5);
+ return 999;
+ }
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return a map containing the used variables only. */
+const varmap_type& ParserBase::GetUsedVar() const
+{
+ try
+ {
+ m_pTokenReader->IgnoreUndefVar(true);
+ ParseString(); // implicitely create or update the map with the
+ // used variables stored in the token reader if not already done
+ m_pTokenReader->IgnoreUndefVar(false);
+ }
+ catch(exception_type &e)
+ {
+ m_pTokenReader->IgnoreUndefVar(false);
+ throw e;
+ }
+
+ // Make sure to stay in string parse mode, dont call ReInit()
+ // because it deletes the array with the used variables
+ m_pParseFormula = &ParserBase::ParseString;
+
+ return m_pTokenReader->GetUsedVar();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return a map containing the used variables only. */
+const varmap_type& ParserBase::GetVar() const
+{
+ return m_VarDef;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return a map containing all parser constants. */
+const valmap_type& ParserBase::GetConst() const
+{
+ return m_ConstDef;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return prototypes of all parser functions.
+
+ The return type is a map of the public type #funmap_type containing the prototype
+ definitions for all numerical parser functions. String functions are not part of
+ this map. The Prototype definition is encapsulated in objects of the class FunProt
+ one per parser function each associated with function names via a map construct.
+ \return #m_FunDef
+ \sa FunProt
+ \throw nothrow
+*/
+const funmap_type& ParserBase::GetFunDef() const
+{
+ return m_FunDef;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Retrieve the formula. */
+const string_type& ParserBase::GetExpr() const
+{
+ return m_pTokenReader->GetFormula();
+}
+
+//---------------------------------------------------------------------------
+ParserBase::token_type ParserBase::ApplyNumFunc( const token_type &a_FunTok,
+ const std::vector<token_type> &a_vArg) const
+{
+ token_type valTok;
+ int iArgCount = (unsigned)a_vArg.size();
+ void *pFunc = a_FunTok.GetFuncAddr();
+ assert(pFunc);
+
+ // Collect the function arguments from the value stack
+ switch(a_FunTok.GetArgCount())
+ {
+ case -1:
+ // Function with variable argument count
+ // copy arguments into a vector<value_type>
+ {
+ /** \todo remove the unnecessary argument vector by changing order in stArg. */
+ std::vector<value_type> vArg;
+ for (int i=0; i<iArgCount; ++i)
+ vArg.push_back(a_vArg[i].GetVal());
+
+ valTok.SetVal( ((multfun_type)a_FunTok.GetFuncAddr())(&vArg[0], (int)vArg.size()) );
+ }
+ break;
+
+ case 1: valTok.SetVal( ((fun_type1)pFunc)(a_vArg[0].GetVal()) ); break;
+ case 2: valTok.SetVal( ((fun_type2)pFunc)(a_vArg[1].GetVal(),
+ a_vArg[0].GetVal()) ); break;
+ case 3: valTok.SetVal( ((fun_type3)pFunc)(a_vArg[2].GetVal(),
+ a_vArg[1].GetVal(),
+ a_vArg[0].GetVal()) ); break;
+ case 4: valTok.SetVal( ((fun_type4)pFunc)(a_vArg[3].GetVal(),
+ a_vArg[2].GetVal(),
+ a_vArg[1].GetVal(),
+ a_vArg[0].GetVal()) ); break;
+ case 5: valTok.SetVal( ((fun_type5)pFunc)(a_vArg[4].GetVal(),
+ a_vArg[3].GetVal(),
+ a_vArg[2].GetVal(),
+ a_vArg[1].GetVal(),
+ a_vArg[0].GetVal()) ); break;
+ default: Error(ecINTERNAL_ERROR, 6);
+ }
+
+ // Find out if the result will depend on a variable
+ /** \todo remove this loop, put content in the loop that takes the argument values.
+
+ (Attention: SetVal will reset Flags.)
+ */
+ bool bVolatile = a_FunTok.IsFlagSet(token_type::flVOLATILE);
+ for (int i=0; (bVolatile==false) && (i<iArgCount); ++i)
+ bVolatile |= a_vArg[i].IsFlagSet(token_type::flVOLATILE);
+
+ if (bVolatile)
+ valTok.AddFlags(token_type::flVOLATILE);
+
+#if defined(_MSC_VER)
+ #pragma warning( disable : 4311 )
+#endif
+
+ // Formula optimization
+ if ( m_bOptimize &&
+ !valTok.IsFlagSet(token_type::flVOLATILE) &&
+ !a_FunTok.IsFlagSet(token_type::flVOLATILE) )
+ {
+ m_vByteCode.RemoveValEntries(iArgCount);
+ m_vByteCode.AddVal( valTok.GetVal() );
+ }
+ else
+ {
+ // operation dosnt depends on a variable or the function is flagged unoptimizeable
+ // we cant optimize here...
+ m_vByteCode.AddFun(pFunc, (a_FunTok.GetArgCount()==-1) ? -iArgCount : iArgCount);
+ }
+
+ return valTok;
+
+#if defined(_MSC_VER)
+ #pragma warning( default : 4311 )
+#endif
+}
+
+//---------------------------------------------------------------------------
+/** \brief Execute a function that takes a single string argument.
+
+ \param a_FunTok Function token.
+ \throw exception_type If the function token is not a string function
+*/
+ParserBase::token_type ParserBase::ApplyStrFunc(const token_type &a_FunTok,
+ const std::vector<token_type> &a_vArg) const
+{
+ if (a_vArg.back().GetCode()!=cmSTRING)
+ Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
+
+ token_type valTok;
+ int iArgCount = (unsigned)a_vArg.size();
+ void *pFunc = a_FunTok.GetFuncAddr();
+ assert(pFunc);
+
+ try
+ {
+ // Collect the function arguments from the value stack
+ switch(a_FunTok.GetArgCount())
+ {
+ case 0: valTok.SetVal( ((strfun_type1)pFunc)(a_vArg[0].GetAsString().c_str()) ); break;
+ case 1: valTok.SetVal( ((strfun_type2)pFunc)(a_vArg[1].GetAsString().c_str(),
+ a_vArg[0].GetVal()) ); break;
+ case 2: valTok.SetVal( ((strfun_type3)pFunc)(a_vArg[2].GetAsString().c_str(),
+ a_vArg[1].GetVal(),
+ a_vArg[0].GetVal()) ); break;
+ default: Error(ecINTERNAL_ERROR);
+ }
+ }
+ catch(ParserError& /*e*/)
+ {
+ Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());
+ }
+
+ // Find out if the result will depend on a variable
+ /** \todo remove this loop, put content in the loop that takes the argument values.
+
+ (Attention: SetVal will reset Flags.)
+ */
+ bool bVolatile = a_FunTok.IsFlagSet(token_type::flVOLATILE);
+ for (int i=0; (bVolatile==false) && (i<iArgCount); ++i)
+ bVolatile |= a_vArg[i].IsFlagSet(token_type::flVOLATILE);
+
+ if (bVolatile)
+ valTok.AddFlags(token_type::flVOLATILE);
+
+ // string functions won't be optimized
+ m_vByteCode.AddStrFun((void*)pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx());
+
+ return valTok;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Apply a function token.
+
+ \param iArgCount Number of Arguments actually gathered used only for multiarg functions.
+ \post Function have been taken from the stack, the result has been pushed
+ \post The function token is removed from the stack
+ \throw exception_type if Argument count does not mach function requirements.
+*/
+void ParserBase::ApplyFunc( ParserStack<token_type> &a_stOpt,
+ ParserStack<token_type> &a_stVal,
+ int a_iArgCount) const
+{
+ assert(m_pTokenReader.get());
+
+ // Operator stack empty or does not contain tokens with callback functions
+ if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==0 )
+ return;
+
+ token_type funTok = a_stOpt.pop();
+ assert(funTok.GetFuncAddr());
+
+ // Binary operators must rely on their internal operator number
+ // since counting of operators relies on commas for function arguments
+ // binary operators do not have commas in their expression
+ int iArgCount = ( funTok.GetCode()==cmOPRT_BIN ) ? funTok.GetArgCount() : a_iArgCount;
+
+ if (funTok.GetArgCount()>0 && iArgCount>funTok.GetArgCount())
+ Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());
+
+ if ( funTok.GetCode()!=cmOPRT_BIN && iArgCount<funTok.GetArgCount() )
+ Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());
+
+ if ( funTok.GetCode()==cmFUNC_STR && iArgCount>funTok.GetArgCount() )
+ Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());
+
+ // Collect the numeric function arguments from the value stack and store them
+ // in a vector
+ std::vector<token_type> stArg;
+ for (int i=0; i<iArgCount; ++i)
+ {
+ stArg.push_back( a_stVal.pop() );
+ if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR )
+ Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
+ }
+
+ // for string functions add the string argument
+ if (funTok.GetCode()==cmFUNC_STR)
+ {
+ stArg.push_back( a_stVal.pop() );
+ if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR )
+ Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString());
+ }
+
+ // String functions accept only one parameter
+ if (funTok.GetType()==tpSTR)
+ {
+ token_type token( ApplyStrFunc(funTok, stArg) );
+ a_stVal.push( token );
+ }
+ else
+ {
+ token_type token( ApplyNumFunc(funTok, stArg) );
+ a_stVal.push( token );
+ }
+/*
+#ifdef __BORLANDC__
+ // Borland C++ Compiler does not support taking references on
+ // unnamed temporaries
+ if (funTok.GetType()==tpSTR)
+ {
+ ParserToken<value_type, string_type> pt( ApplyStrFunc(funTok, stArg.back()) );
+ a_stVal.push(pt);
+ }
+ else
+ {
+ ParserToken<value_type, string_type> pt( ApplyNumFunc(funTok, stArg) );
+ a_stVal.push(pt);
+ }
+#else
+ // String functions accept only one parameter
+ a_stVal.push( (funTok.GetType()==tpSTR) ? ApplyStrFunc(funTok, stArg) :
+ ApplyNumFunc(funTok, stArg) );
+#endif // __BORLANDC__
+*/
+}
+
+//---------------------------------------------------------------------------
+void ParserBase::ApplyBinOprt( ParserStack<token_type> &a_stOpt,
+ ParserStack<token_type> &a_stVal) const
+{
+ assert(a_stOpt.size());
+
+ // user defined binary operator
+ if (a_stOpt.top().GetCode()==cmOPRT_BIN)
+ {
+ ApplyFunc(a_stOpt, a_stVal, 2);
+ }
+ else
+ {
+ // internal binary operator
+ MUP_ASSERT(a_stVal.size()>=2);
+
+ token_type valTok1 = a_stVal.pop(),
+ valTok2 = a_stVal.pop(),
+ optTok = a_stOpt.pop(),
+ resTok;
+
+ if ( valTok1.GetType()!=valTok2.GetType() ||
+ (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) )
+ Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString());
+
+ value_type x = valTok2.GetVal(),
+ y = valTok1.GetVal();
+
+ switch (optTok.GetCode())
+ {
+ // built in binary operators
+ case cmAND: resTok.SetVal( (int)x & (int)y ); break;
+ case cmOR: resTok.SetVal( (int)x | (int)y ); break;
+ case cmXOR: resTok.SetVal( (int)x ^ (int)y ); break;
+ case cmLT: resTok.SetVal( x < y ); break;
+ case cmGT: resTok.SetVal( x > y ); break;
+ case cmLE: resTok.SetVal( x <= y ); break;
+ case cmGE: resTok.SetVal( x >= y ); break;
+ case cmNEQ: resTok.SetVal( x != y ); break;
+ case cmEQ: resTok.SetVal( x == y ); break;
+ case cmADD: resTok.SetVal( x + y ); break;
+ case cmSUB: resTok.SetVal( x - y ); break;
+ case cmMUL: resTok.SetVal( x * y ); break;
+ case cmDIV: resTok.SetVal( x / y ); break;
+ case cmPOW: resTok.SetVal(pow(x, y)); break;
+
+ case cmASSIGN:
+ // The assignement operator needs special treatment
+ // it uses a different format when stored in the bytecode!
+ {
+ if (valTok2.GetCode()!=cmVAR)
+ Error(ecINTERNAL_ERROR, 7);
+
+ value_type *pVar = valTok2.GetVar();
+ resTok.SetVal( *pVar = y );
+ a_stVal.push( resTok );
+
+ m_vByteCode.AddAssignOp(pVar);
+ return; // we must return since the following
+ // stuff does not apply
+ }
+
+ default: Error(ecINTERNAL_ERROR, 8);
+ }
+
+ // Create the bytecode entries
+ if (!m_bOptimize)
+ {
+ // Optimization flag is not set
+ m_vByteCode.AddOp(optTok.GetCode());
+ }
+ else if ( valTok1.IsFlagSet(token_type::flVOLATILE) ||
+ valTok2.IsFlagSet(token_type::flVOLATILE) )
+ {
+ // Optimization flag is not set, but one of the value
+ // depends on a variable
+ m_vByteCode.AddOp(optTok.GetCode());
+ resTok.AddFlags(token_type::flVOLATILE);
+ }
+ else
+ {
+ // operator call can be optimized; If optimization is possible
+ // the two previous tokens must be value tokens / they will be removed
+ // and replaced with the result of the pending operation.
+ m_vByteCode.RemoveValEntries(2);
+ m_vByteCode.AddVal(resTok.GetVal());
+ }
+
+ a_stVal.push( resTok );
+ }
+}
+
+//---------------------------------------------------------------------------
+/** \brief Parse the command code.
+
+ Command code contains precalculated stack positions of the values and the
+ associated operators.
+ The Stack is filled beginning from index one the value at index zero is
+ not used at all.
+
+ \sa ParseString(), ParseValue()
+*/
+value_type ParserBase::ParseCmdCode() const
+{
+#if defined(_MSC_VER)
+ #pragma warning( disable : 4312 )
+#endif
+
+ value_type Stack[99];
+ ECmdCode iCode;
+ bytecode_type idx(0);
+ int i(0);
+
+ __start:
+
+ idx = m_pCmdCode[i];
+ iCode = (ECmdCode)m_pCmdCode[i+1];
+ i += 2;
+
+#ifdef _DEBUG
+ if (idx>=99)
+ throw exception_type(ecGENERIC, _T(""), m_pTokenReader->GetFormula(), -1);
+#endif
+
+ switch (iCode)
+ {
+ // built in binary operators
+ case cmAND: Stack[idx] = (int)Stack[idx] & (int)Stack[idx+1]; goto __start;
+ case cmOR: Stack[idx] = (int)Stack[idx] | (int)Stack[idx+1]; goto __start;
+ case cmXOR: Stack[idx] = (int)Stack[idx] ^ (int)Stack[idx+1]; goto __start;
+ case cmLE: Stack[idx] = Stack[idx] <= Stack[idx+1]; goto __start;
+ case cmGE: Stack[idx] = Stack[idx] >= Stack[idx+1]; goto __start;
+ case cmNEQ: Stack[idx] = Stack[idx] != Stack[idx+1]; goto __start;
+ case cmEQ: Stack[idx] = Stack[idx] == Stack[idx+1]; goto __start;
+ case cmLT: Stack[idx] = Stack[idx] < Stack[idx+1]; goto __start;
+ case cmGT: Stack[idx] = Stack[idx] > Stack[idx+1]; goto __start;
+ case cmADD: Stack[idx] += Stack[1+idx]; goto __start;
+ case cmSUB: Stack[idx] -= Stack[1+idx]; goto __start;
+ case cmMUL: Stack[idx] *= Stack[1+idx]; goto __start;
+ case cmDIV: Stack[idx] /= Stack[1+idx]; goto __start;
+ case cmPOW: Stack[idx] = pow(Stack[idx], Stack[1+idx]); goto __start;
+
+ // Assignement needs special treatment
+ case cmASSIGN:
+ {
+ // next is a pointer to the target
+ value_type **pDest = (value_type**)(&m_pCmdCode[i]);
+
+ // advance index according to pointer size
+ i += m_vByteCode.GetPtrSize();
+ // assign the value
+ Stack[idx] = **pDest = Stack[idx+1];
+ }
+ goto __start;
+
+ // user defined binary operators
+ case cmOPRT_BIN:
+ Stack[idx] = (**(fun_type2**)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1]);
+ ++i;
+ goto __start;
+
+ // variable tokens
+ case cmVAR:
+ Stack[idx] = **(value_type**)(&m_pCmdCode[i]);
+ i += m_vByteCode.GetValSize();
+ goto __start;
+
+ // value tokens
+ case cmVAL:
+ Stack[idx] = *(value_type*)(&m_pCmdCode[i]);
+ i += m_vByteCode.GetValSize();
+ goto __start;
+
+ // Next is treatment of string functions
+ case cmFUNC_STR:
+ {
+ // The function argument count
+ int iArgCount = (int)m_pCmdCode[ i++ ];
+
+ // The index of the string argument in the string table
+ int iIdxStack = (int)m_pCmdCode[ i++ ];
+ MUP_ASSERT( iIdxStack>=0 && iIdxStack<(int)m_vStringBuf.size() );
+
+ switch(iArgCount) // switch according to argument count
+ {
+ case 0: Stack[idx] = (*(strfun_type1*)(&m_pCmdCode[i]))(m_vStringBuf[iIdxStack].c_str()); break;
+ case 1: Stack[idx] = (*(strfun_type2*)(&m_pCmdCode[i]))(m_vStringBuf[iIdxStack].c_str(), Stack[idx]); break;
+ case 2: Stack[idx] = (*(strfun_type3*)(&m_pCmdCode[i]))(m_vStringBuf[iIdxStack].c_str(), Stack[idx], Stack[idx+1]); break;
+ }
+ i += m_vByteCode.GetPtrSize();
+ }
+ goto __start;
+
+ // Next is treatment of numeric functions
+ case cmFUNC:
+ {
+ int iArgCount = (int)m_pCmdCode[i++];
+
+ switch(iArgCount) // switch according to argument count
+ {
+ case 1: Stack[idx] = (*(fun_type1*)(&m_pCmdCode[i]))(Stack[idx]); break;
+ case 2: Stack[idx] = (*(fun_type2*)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1]); break;
+ case 3: Stack[idx] = (*(fun_type3*)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1], Stack[idx+2]); break;
+ case 4: Stack[idx] = (*(fun_type4*)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1], Stack[idx+2], Stack[idx+3]); break;
+ case 5: Stack[idx] = (*(fun_type5*)(&m_pCmdCode[i]))(Stack[idx], Stack[idx+1], Stack[idx+2], Stack[idx+3], Stack[idx+4]); break;
+ default:
+ if (iArgCount>0) // function with variable arguments store the number as a negative value
+ Error(ecINTERNAL_ERROR, 1);
+
+ Stack[idx] =(*(multfun_type*)(&m_pCmdCode[i]))(&Stack[idx], -iArgCount);
+ break;
+ }
+ i += m_vByteCode.GetPtrSize();
+ }
+ goto __start;
+
+ case cmEND:
+ return Stack[1];
+
+ default:
+ Error(ecINTERNAL_ERROR, 2);
+ return 0;
+ }
+
+#if defined(_MSC_VER)
+ #pragma warning( default : 4312 )
+#endif
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return result for constant functions.
+
+ Seems pointless, but for parser functions that are made up of only a value, which occur
+ in real world applications, this speeds up things by removing the parser overhead almost
+ completely.
+*/
+value_type ParserBase::ParseValue() const
+{
+ return *(value_type*)(&m_pCmdCode[2]);
+}
+
+//---------------------------------------------------------------------------
+/** \brief One of the two main parse functions.
+
+ Parse expression from input string. Perform syntax checking and create bytecode.
+ After parsing the string and creating the bytecode the function pointer
+ #m_pParseFormula will be changed to the second parse routine the uses bytecode instead of string parsing.
+
+ \sa ParseCmdCode(), ParseValue()
+*/
+value_type ParserBase::ParseString() const
+{
+#if defined(_MSC_VER)
+ #pragma warning( disable : 4311 )
+#endif
+ if (!m_pTokenReader->GetFormula().length())
+ Error(ecUNEXPECTED_EOF, 0);
+
+ ParserStack<token_type> stOpt, stVal;
+ ParserStack<int> stArgCount;
+ token_type opta, opt; // for storing operators
+ token_type val, tval; // for storing value
+ string_type strBuf; // buffer for string function arguments
+
+ ReInit();
+
+ for(;;)
+ {
+ opt = m_pTokenReader->ReadNextToken();
+
+ switch (opt.GetCode())
+ {
+ //
+ // Next three are different kind of value entries
+ //
+ case cmSTRING:
+ opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token
+ stVal.push(opt);
+ m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer
+ break;
+
+ case cmVAR:
+ stVal.push(opt);
+ m_vByteCode.AddVar( static_cast<value_type*>(opt.GetVar()) );
+ break;
+
+ case cmVAL:
+ stVal.push(opt);
+ m_vByteCode.AddVal( opt.GetVal() );
+ break;
+
+ case cmCOMMA:
+ if (stArgCount.empty())
+ Error(ecUNEXPECTED_COMMA, m_pTokenReader->GetPos());
+ ++stArgCount.top(); // Record number of arguments
+ // fall through...
+ case cmEND:
+ case cmBC:
+ {
+ while ( stOpt.size() && stOpt.top().GetCode() != cmBO)
+ {
+ if (stOpt.top().GetCode()==cmOPRT_INFIX)
+ ApplyFunc(stOpt, stVal, 1); // infix operator
+ else
+ ApplyBinOprt(stOpt, stVal);
+ }
+
+ // <ibg> 20060218 infix operator treatment moved here
+ if (stOpt.size() && stOpt.top().GetCode()==cmOPRT_INFIX)
+ ApplyFunc(stOpt, stVal, 1); // infix operator
+
+ if ( opt.GetCode()!=cmBC || stOpt.size()==0 || stOpt.top().GetCode()!=cmBO )
+ break;
+
+ // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check
+ // if there is either a function or a sign pending
+ // neither the opening nor the closing bracket will be pushed back to
+ // the operator stack
+ // Check if a function is standing in front of the opening bracket,
+ // if yes evaluate it afterwards check for infix operators
+ assert(stArgCount.size());
+ int iArgCount = stArgCount.pop();
+
+ stOpt.pop(); // Take opening bracket from stack
+
+ if (iArgCount>1 && ( stOpt.size()==0 ||
+ (stOpt.top().GetCode()!=cmFUNC &&
+ stOpt.top().GetCode()!=cmFUNC_STR) ) )
+ Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos());
+
+ if (stOpt.size() && stOpt.top().GetCode()!=cmOPRT_INFIX)
+ ApplyFunc(stOpt, stVal, iArgCount);
+ } // if bracket content is evaluated
+ break;
+
+ //
+ // Next are the binary operator entries
+ //
+ case cmAND: // built in binary operators
+ case cmOR:
+ case cmXOR:
+ case cmLT:
+ case cmGT:
+ case cmLE:
+ case cmGE:
+ case cmNEQ:
+ case cmEQ:
+ case cmADD:
+ case cmSUB:
+ case cmMUL:
+ case cmDIV:
+ case cmPOW:
+ case cmASSIGN:
+ case cmOPRT_BIN:
+ // A binary operator (user defined or built in) has been found.
+ while ( stOpt.size() && stOpt.top().GetCode() != cmBO)
+ {
+ if (GetOprtPri(stOpt.top()) < GetOprtPri(opt))
+ break;
+
+ if (stOpt.top().GetCode()==cmOPRT_INFIX)
+ ApplyFunc(stOpt, stVal, 1); // infix operator
+ else
+ ApplyBinOprt(stOpt, stVal);
+ } // while ( ... )
+
+ // The operator can't be evaluated right now, push back to the operator stack
+ stOpt.push(opt);
+ break;
+
+ //
+ // Last section contains functions and operators implicitely mapped to functions
+ //
+ case cmBO:
+ stArgCount.push( (stOpt.size() && stOpt.top().GetCode()==cmFUNC_STR) ? 0 : 1 );
+ stOpt.push(opt);
+ break;
+
+ case cmFUNC_STR:
+ case cmFUNC:
+ case cmOPRT_INFIX:
+ stOpt.push(opt);
+ break;
+
+ case cmOPRT_POSTFIX:
+ stOpt.push(opt);
+ ApplyFunc(stOpt, stVal, 1); // this is the postfix operator
+ break;
+
+ default: Error(ecINTERNAL_ERROR, 3);
+ } // end of switch operator-token
+
+ if ( opt.GetCode() == cmEND )
+ {
+ m_vByteCode.Finalize();
+ break;
+ }
+
+#if defined(MUP_DUMP_STACK)
+ StackDump(stVal, stOpt);
+ m_vByteCode.AsciiDump();
+#endif
+ } // while (true)
+
+ // Store pointer to start of bytecode
+ m_pCmdCode = m_vByteCode.GetRawData();
+
+#if defined(MUP_DUMP_CMDCODE)
+ m_vByteCode.AsciiDump();
+#endif
+
+ // get the last value (= final result) from the stack
+ if (stVal.size()!=1)
+ Error(ecEMPTY_EXPRESSION);
+
+ if (stVal.top().GetType()!=tpDBL)
+ Error(ecSTR_RESULT);
+
+ // no error, so change the function pointer for the main parse routine
+ value_type fVal = stVal.top().GetVal(); // Result from String parsing
+
+ if (m_bUseByteCode)
+ {
+ m_pParseFormula = (m_pCmdCode[1]==cmVAL && m_pCmdCode[6]==cmEND) ?
+ &ParserBase::ParseValue :
+ &ParserBase::ParseCmdCode;
+ }
+
+ return fVal;
+
+#if defined(_MSC_VER)
+ #pragma warning( default : 4311 )
+#endif
+}
+
+
+//---------------------------------------------------------------------------
+/** \brief Create an error containing the parse error position.
+
+ This function will create an Parser Exception object containing the error text and
+ its position.
+
+ \param a_iErrc [in] The error code of type #EErrorCodes.
+ \param a_iPos [in] The position where the error was detected.
+ \param a_strTok [in] The token string representation associated with the error.
+ \throw ParserException always throws thats the only purpose of this function.
+*/
+void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const
+{
+ throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetFormula(), a_iPos);
+}
+
+//------------------------------------------------------------------------------
+/** \brief Clear all user defined variables.
+
+ Resets the parser to string parsing mode by calling #ReInit.
+ \throw nothrow
+*/
+void ParserBase::ClearVar()
+{
+ m_VarDef.clear();
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Remove a variable from internal storage.
+
+Removes a variable if it exists. If the Variable does not exist nothing will be done.
+
+\throw nothrow
+*/
+void ParserBase::RemoveVar(const string_type &a_strVarName)
+{
+ varmap_type::iterator item = m_VarDef.find(a_strVarName);
+ if (item!=m_VarDef.end())
+ {
+ m_VarDef.erase(item);
+ ReInit();
+ }
+}
+
+//------------------------------------------------------------------------------
+/** \brief Clear the formula.
+
+Clear the formula and existing bytecode.
+
+\post Resets the parser to string parsing mode.
+\throw nothrow
+*/
+void ParserBase::ClearFormula()
+{
+ m_vByteCode.clear();
+ m_pCmdCode = 0;
+ m_pTokenReader->SetFormula(_T(""));
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Clear all functions.
+ \post Resets the parser to string parsing mode.
+ \throw nothrow
+*/
+void ParserBase::ClearFun()
+{
+ m_FunDef.clear();
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Clear all user defined constants.
+
+ Both numeric and string constants will be removed from the internal storage.
+ \post Resets the parser to string parsing mode.
+ \throw nothrow
+*/
+void ParserBase::ClearConst()
+{
+ m_ConstDef.clear();
+ m_StrVarDef.clear();
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Clear all user defined postfix operators.
+ \post Resets the parser to string parsing mode.
+ \throw nothrow
+*/
+void ParserBase::ClearPostfixOprt()
+{
+ m_PostOprtDef.clear();
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Clear all user defined binary operators.
+ \post Resets the parser to string parsing mode.
+ \throw nothrow
+*/
+void ParserBase::ClearOprt()
+{
+ m_OprtDef.clear();
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Clear the user defined Prefix operators.
+ \post Resets the parser to string parser mode.
+ \throw nothrow
+*/
+void ParserBase::ClearInfixOprt()
+{
+ m_InfixOprtDef.clear();
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Enable or disable the formula optimization feature.
+ \post Resets the parser to string parser mode.
+ \throw nothrow
+*/
+void ParserBase::EnableOptimizer(bool a_bIsOn)
+{
+ m_bOptimize = a_bIsOn;
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Enable or disable parsing from Bytecode.
+
+ \attention There is no reason to disable bytecode. It will
+ drastically decrease parsing speed.
+*/
+void ParserBase::EnableByteCode(bool a_bIsOn)
+{
+ m_bUseByteCode = a_bIsOn;
+ if (!a_bIsOn)
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Enable or disable the built in binary operators.
+ \throw nothrow
+ \sa m_bBuiltInOp, ReInit()
+
+ If you disable the built in binary operators there will be no binary operators
+ defined. Thus you must add them manually one by one. It is not possible to
+ disable built in operators selectively. This function will Reinitialize the
+ parser by calling ReInit().
+*/
+void ParserBase::EnableBuiltInOprt(bool a_bIsOn)
+{
+ m_bBuiltInOp = a_bIsOn;
+ ReInit();
+}
+
+//------------------------------------------------------------------------------
+/** \brief Query status of built in variables.
+ \return #m_bBuiltInOp; true if built in operators are enabled.
+ \throw nothrow
+*/
+bool ParserBase::HasBuiltInOprt() const
+{
+ return m_bBuiltInOp;
+}
+
+#if defined(MUP_DUMP_STACK) | defined(MUP_DUMP_CMDCODE)
+
+//------------------------------------------------------------------------------
+/** \brief Dump stack content.
+
+ This function is used for debugging only.
+*/
+void ParserBase::StackDump( const ParserStack<token_type> &a_stVal,
+ const ParserStack<token_type> &a_stOprt ) const
+{
+ ParserStack<token_type> stOprt(a_stOprt),
+ stVal(a_stVal);
+
+ mu::console() << _T("\nValue stack:\n");
+ while ( !stVal.empty() )
+ {
+ token_type val = stVal.pop();
+ if (val.GetType()==tpSTR)
+ mu::console() << _T(" \"") << val.GetAsString() << _T("\" ");
+ else
+ mu::console() << _T(" ") << val.GetVal() << _T(" ");
+ }
+ mu::console() << "\nOperator stack:\n";
+
+ while ( !stOprt.empty() )
+ {
+ if (stOprt.top().GetCode()<=cmASSIGN)
+ {
+ mu::console() << _T("OPRT_INTRNL \"")
+ << ParserBase::c_DefaultOprt[stOprt.top().GetCode()]
+ << _T("\" \n");
+ }
+ else
+ {
+ switch(stOprt.top().GetCode())
+ {
+ case cmVAR: mu::console() << _T("VAR\n"); break;
+ case cmVAL: mu::console() << _T("VAL\n"); break;
+ case cmFUNC: mu::console() << _T("FUNC_NUM \"")
+ << stOprt.top().GetAsString()
+ << _T("\"\n"); break;
+ case cmOPRT_INFIX: mu::console() << _T("OPRT_INFIX \"")
+ << stOprt.top().GetAsString()
+ << _T("\"\n"); break;
+ case cmOPRT_BIN: mu::console() << _T("OPRT_BIN \"")
+ << stOprt.top().GetAsString()
+ << _T("\"\n"); break;
+ case cmFUNC_STR: mu::console() << _T("FUNC_STR\n"); break;
+ case cmEND: mu::console() << _T("END\n"); break;
+ case cmUNKNOWN: mu::console() << _T("UNKNOWN\n"); break;
+ case cmBO: mu::console() << _T("BRACKET \"(\"\n"); break;
+ case cmBC: mu::console() << _T("BRACKET \")\"\n"); break;
+ default: mu::console() << stOprt.top().GetType() << _T(" "); break;
+ }
+ }
+ stOprt.pop();
+ }
+
+ mu::console() << dec << endl;
+}
+
+#endif // defined(MUP_DUMP_STACK) | defined(MUP_DUMP_CMDCODE)
+
+} // namespace mu
+
+
diff --git a/muparser/muParserBase.h b/muparser/muParserBase.h
new file mode 100644
index 0000000..c4cc433
--- /dev/null
+++ b/muparser/muParserBase.h
@@ -0,0 +1,324 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef MU_PARSER_BASE_H
+#define MU_PARSER_BASE_H
+
+#include <cmath>
+#include <string>
+#include <iostream>
+#include <map>
+#include <memory>
+
+#include "muParserDef.h"
+#include "muParserStack.h"
+#include "muParserTokenReader.h"
+#include "muParserBytecode.h"
+#include "muParserError.h"
+
+
+namespace mu
+{
+
+/** \brief Mathematical expressions parser (base parser engine).
+
+ Version 1.27 (20061201)
+
+ This is the implementation of a bytecode based mathematical expressions parser.
+ The formula will be parsed from string and converted into a bytecode.
+ Future calculations will be done with the bytecode instead the formula string
+ resulting in a significant performance increase.
+ Complementary to a set of internally implemented functions the parser is able to handle
+ user defined functions and variables.
+
+ \author (C) 2004-2006 Ingo Berg
+*/
+class ParserBase
+{
+friend class ParserTokenReader;
+
+private:
+ typedef value_type (ParserBase::*ParseFunction)() const;
+ typedef ParserToken<value_type, string_type> token_type;
+ typedef std::vector<string_type> stringbuf_type;
+ typedef ParserTokenReader token_reader_type;
+
+ static const char_type *c_DefaultOprt[];
+
+ public:
+ /** \brief Type of the error class.
+
+ Included for backwards compatibility.
+ */
+ typedef ParserError exception_type;
+
+ ParserBase();
+ ParserBase( const ParserBase &a_Parser );
+ ParserBase& operator=(const ParserBase &a_Parser);
+
+ //---------------------------------------------------------------------------
+ /** \brief Destructor. (trivial)
+
+ \throw nothrow
+ */
+ virtual ~ParserBase()
+ {}
+
+ //---------------------------------------------------------------------------
+ /** \brief Calculate the result.
+
+ A note on const correctness:
+ I consider it important that Calc is a const function.
+ Due to caching operations Calc changes only the state of internal variables with one exception
+ m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making
+ Calc non const GetUsedVar is non const because it explicitely calls Eval() forcing this update.
+
+ \pre A formula must be set.
+ \pre Variables must have been set (if needed)
+
+ \sa #m_pParseFormula
+ \return The evaluation result
+ \throw ParseException if no Formula is set or in case of any other error related to the formula.
+ */
+ inline value_type Eval() const
+ {
+ return (this->*m_pParseFormula)();
+ }
+
+ void SetExpr(const string_type &a_sExpr);
+ void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL);
+
+ void EnableOptimizer(bool a_bIsOn=true);
+ void EnableByteCode(bool a_bIsOn=true);
+ void EnableBuiltInOprt(bool a_bIsOn=true);
+
+ bool HasBuiltInOprt() const;
+ void AddValIdent(identfun_type a_pCallback);
+
+#define MUP_DEFINE_FUNC(TYPE) \
+ inline void DefineFun(const string_type &a_strName, TYPE a_pFun, bool a_bAllowOpt = true) \
+ { \
+ AddCallback( a_strName, ParserCallback(a_pFun, a_bAllowOpt), \
+ m_FunDef, ValidNameChars() ); \
+ }
+
+ MUP_DEFINE_FUNC(fun_type1)
+ MUP_DEFINE_FUNC(fun_type2)
+ MUP_DEFINE_FUNC(fun_type3)
+ MUP_DEFINE_FUNC(fun_type4)
+ MUP_DEFINE_FUNC(fun_type5)
+ MUP_DEFINE_FUNC(multfun_type)
+ MUP_DEFINE_FUNC(strfun_type1)
+ MUP_DEFINE_FUNC(strfun_type2)
+ MUP_DEFINE_FUNC(strfun_type3)
+#undef MUP_DEFINE_FUNC
+
+ void DefineOprt(const string_type &a_strName, fun_type2 a_pFun, unsigned a_iPri=0, bool a_bAllowOpt = false);
+ void DefineConst(const string_type &a_sName, value_type a_fVal);
+ void DefineStrConst(const string_type &a_sName, const string_type &a_strVal);
+ void DefineVar(const string_type &a_sName, value_type *a_fVar);
+ void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true);
+ void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true);
+
+ // Clear user defined variables, constants or functions
+ void ClearVar();
+ void ClearFun();
+ void ClearConst();
+ void ClearInfixOprt();
+ void ClearPostfixOprt();
+ void ClearOprt();
+
+ void RemoveVar(const string_type &a_strVarName);
+ const varmap_type& GetUsedVar() const;
+ const varmap_type& GetVar() const;
+ const valmap_type& GetConst() const;
+ const string_type& GetExpr() const;
+ const funmap_type& GetFunDef() const;
+
+ //---------------------------------------------------------------------------
+ /** \brief Return the strings of all Operator identifiers.
+
+ GetOprt is a const function returning a pinter to an array of const char pointers.
+
+ \return Returns a pointer to the c_DefaultOprt array of const char *.
+ \throw nothrow
+ */
+ const char_type ** GetOprtDef() const
+ {
+ return (const char_type **)(&c_DefaultOprt[0]);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Define the set of valid characters to be used in names of
+ functions, variables, constants.
+ */
+ void DefineNameChars(const char_type *a_szCharset)
+ {
+ m_sNameChars = a_szCharset;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Define the set of valid characters to be used in names of
+ binary operators and postfix operators.
+ */
+ void DefineOprtChars(const char_type *a_szCharset)
+ {
+ m_sOprtChars = a_szCharset;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Define the set of valid characters to be used in names of
+ infix operators.
+ */
+ void DefineInfixOprtChars(const char_type *a_szCharset)
+ {
+ m_sInfixOprtChars = a_szCharset;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Virtual function that defines the characters allowed in name identifiers.
+ \sa #ValidOprtChars, #ValidPrefixOprtChars
+ */
+ const char_type* ValidNameChars() const
+ {
+ assert(m_sNameChars.size());
+ return m_sNameChars.c_str();
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Virtual function that defines the characters allowed in operator definitions.
+ \sa #ValidNameChars, #ValidPrefixOprtChars
+ */
+ const char_type* ValidOprtChars() const
+ {
+ assert(m_sOprtChars.size());
+ return m_sOprtChars.c_str();
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Virtual function that defines the characters allowed in infix operator definitions.
+ \sa #ValidNameChars, #ValidOprtChars
+ */
+ const char_type* ValidInfixOprtChars() const
+ {
+ assert(m_sInfixOprtChars.size());
+ return m_sInfixOprtChars.c_str();
+ }
+
+ void Error( EErrorCodes a_iErrc,
+ int a_iPos = (int)mu::string_type::npos,
+ const string_type &a_strTok = string_type() ) const;
+
+ protected:
+
+ //---------------------------------------------------------------------------
+ /** \brief Initialize user defined functions.
+
+ Calls the virtual functions InitFun(), InitConst() and InitOprt().
+ */
+ void Init()
+ {
+ InitCharSets();
+ InitFun();
+ InitConst();
+ InitOprt();
+ }
+
+ //---------------------------------------------------------------------------
+ virtual void InitCharSets() = 0;
+ virtual void InitFun() = 0;
+ virtual void InitConst() = 0;
+ virtual void InitOprt() = 0;
+
+ private:
+ void Assign(const ParserBase &a_Parser);
+ void InitTokenReader();
+ void ReInit() const;
+
+ void AddCallback( const string_type &a_strName,
+ const ParserCallback &a_Callback,
+ funmap_type &a_Storage,
+ const char_type *a_szCharSet );
+
+ void ApplyBinOprt(ParserStack<token_type> &a_stOpt,
+ ParserStack<token_type> &a_stVal) const;
+
+ void ApplyFunc(ParserStack<token_type> &a_stOpt,
+ ParserStack<token_type> &a_stVal,
+ int iArgCount) const;
+
+ token_type ApplyNumFunc(const token_type &a_FunTok,
+ const std::vector<token_type> &a_vArg) const;
+
+ token_type ApplyStrFunc(const token_type &a_FunTok,
+ const std::vector<token_type> &a_vArg) const;
+
+ int GetOprtPri(const token_type &a_Tok) const;
+
+ value_type ParseString() const;
+ value_type ParseCmdCode() const;
+ value_type ParseValue() const;
+
+ void ClearFormula();
+ void CheckName(const string_type &a_strName, const string_type &a_CharSet) const;
+
+#if defined(MUP_DUMP_STACK) | defined(MUP_DUMP_CMDCODE)
+ void StackDump(const ParserStack<token_type > &a_stVal,
+ const ParserStack<token_type > &a_stOprt) const;
+#endif
+
+ /** \brief Pointer to the parser function.
+
+ Eval() calls the function whose address is stored there.
+ */
+ mutable ParseFunction m_pParseFormula;
+ mutable const ParserByteCode::map_type *m_pCmdCode; ///< Formula converted to bytecode, points to the data of the bytecode class.
+ mutable ParserByteCode m_vByteCode; ///< The Bytecode class.
+ mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments
+ stringbuf_type m_vStringVarBuf;
+
+ /** \brief Managed pointer to the token reader object. */
+ std::auto_ptr<token_reader_type> m_pTokenReader;
+
+ funmap_type m_FunDef; ///< Map of function names and pointers.
+ funmap_type m_PostOprtDef; ///< Postfix operator callbacks
+ funmap_type m_InfixOprtDef; ///< unary infix operator.
+ funmap_type m_OprtDef; ///< Binary operator callbacks
+ valmap_type m_ConstDef; ///< user constants.
+ strmap_type m_StrVarDef; ///< user defined string constants
+ varmap_type m_VarDef; ///< user defind variables.
+
+ bool m_bOptimize; ///< Flag that indicates if the optimizer is on or off.
+ bool m_bUseByteCode; ///< Flag that indicates if bytecode parsing is on or off.
+ bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off
+
+ string_type m_sNameChars; ///< Charset for names
+ string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens
+ string_type m_sInfixOprtChars; ///< Charset for infix operator tokens
+};
+
+} // namespace mu
+
+#endif
+
diff --git a/muparser/muParserBytecode.cpp b/muparser/muParserBytecode.cpp
new file mode 100644
index 0000000..7c8db24
--- /dev/null
+++ b/muparser/muParserBytecode.cpp
@@ -0,0 +1,396 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "muParserBytecode.h"
+
+#include <cassert>
+#include <string>
+#include <stack>
+#include <vector>
+#include <iostream>
+
+#include "muParserDef.h"
+#include "muParserError.h"
+#include "muParserToken.h"
+
+
+namespace mu
+{
+
+ //---------------------------------------------------------------------------
+ /** \brief Bytecode default constructor.
+
+ \pre [assert] sizeof(value_type)>=sizeof(map_type)
+ \pre [assert] sizeof(value_type*)>=sizeof(map_type)
+ */
+ ParserByteCode::ParserByteCode()
+ :m_iStackPos(0)
+ ,m_vBase()
+ ,mc_iSizeVal( sizeof(value_type) / sizeof(map_type) )
+ ,mc_iSizePtr( std::max( (int)sizeof(value_type*) /
+ (int)sizeof(map_type), 1 ) )
+ ,mc_iSizeValEntry( 2 + mc_iSizeVal)
+ {
+ m_vBase.reserve(1000);
+ assert( sizeof(value_type)>=sizeof(map_type) );
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Destructor (trivial).*/
+ ParserByteCode::~ParserByteCode()
+ {}
+
+ //---------------------------------------------------------------------------
+ /** \brief Copy constructor.
+
+ Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)
+ */
+ ParserByteCode::ParserByteCode(const ParserByteCode &a_ByteCode)
+ :mc_iSizeVal( sizeof(value_type)/sizeof(map_type) )
+ ,mc_iSizePtr( sizeof(value_type*) / sizeof(map_type) )
+ ,mc_iSizeValEntry( 2 + mc_iSizeVal)
+ {
+ Assign(a_ByteCode);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Assignment operator.
+
+ Implemented in Terms of Assign(const ParserByteCode &a_ByteCode)
+ */
+ ParserByteCode& ParserByteCode::operator=(const ParserByteCode &a_ByteCode)
+ {
+ Assign(a_ByteCode);
+ return *this;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Store an address in bytecode.
+
+ \param a_pAddr Address to be stored.
+ \throw nothrow
+ */
+ void ParserByteCode::StorePtr(void *a_pAddr)
+ {
+ #if defined(_MSC_VER)
+ #pragma warning( disable : 4311 )
+ #endif
+
+ // demo code for packing / unpacking pointers into bytecode
+// void *ptr(NULL);
+// double **pVal;
+// double fVal;
+// map_type dbg[2];
+// dbg[0] = *( reinterpret_cast<map_type*>(&a_pAddr) ),
+// dbg[1] = *( reinterpret_cast<map_type*>(&a_pAddr) + 1 );
+// Version 1:
+// *( (map_type*)&ptr+0) = dbg[0];
+// *( (map_type*)&ptr+1) = dbg[1];
+// Version 2:
+// memcpy(&ptr, dbg, sizeof(dbg));
+// Version 3:
+// pVal = (double**)dbg;
+// fVal = **(double**)dbg;
+
+ for (int i=0; i<mc_iSizePtr; ++i)
+ {
+ m_vBase.push_back( *( reinterpret_cast<map_type*>(&a_pAddr) + i ) );
+ }
+
+ #if defined(_MSC_VER)
+ #pragma warning( default : 4311 )
+ #endif
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Copy state of another object to this.
+
+ \throw nowthrow
+ */
+ void ParserByteCode::Assign(const ParserByteCode &a_ByteCode)
+ {
+ if (this==&a_ByteCode)
+ return;
+
+ m_iStackPos = a_ByteCode.m_iStackPos;
+ m_vBase = a_ByteCode.m_vBase;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Add a Variable pointer to bytecode.
+ \param a_pVar Pointer to be added.
+ \throw nothrow
+ */
+ void ParserByteCode::AddVar(value_type *a_pVar)
+ {
+ m_vBase.push_back( ++m_iStackPos );
+ m_vBase.push_back( cmVAR );
+
+ StorePtr(a_pVar);
+
+ int iSize = GetValSize()-GetPtrSize();
+ assert(iSize>=0);
+
+ // Make sure variable entries have the same size like value entries.
+ // (necessary for optimization; fill with zeros)
+ for (int i=0; i<iSize; ++i)
+ m_vBase.push_back(0);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Add a Variable pointer to bytecode.
+
+ Value entries in byte code consist of:
+ <ul>
+ <li>value array position of the value</li>
+ <li>the operator code according to ParserToken::cmVAL</li>
+ <li>the value stored in #mc_iSizeVal number of bytecode entries.</li>
+ </ul>
+
+ \param a_pVal Value to be added.
+ \throw nothrow
+ */
+ void ParserByteCode::AddVal(value_type a_fVal)
+ {
+ m_vBase.push_back( ++m_iStackPos );
+ m_vBase.push_back( cmVAL );
+
+ for (int i=0; i<mc_iSizeVal; ++i)
+ m_vBase.push_back( *(reinterpret_cast<map_type*>(&a_fVal) + i) );
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Add an operator identifier to bytecode.
+
+ Operator entries in byte code consist of:
+ <ul>
+ <li>value array position of the result</li>
+ <li>the operator code according to ParserToken::ECmdCode</li>
+ </ul>
+
+ \sa ParserToken::ECmdCode
+ */
+ void ParserByteCode::AddOp(ECmdCode a_Oprt)
+ {
+ m_vBase.push_back(--m_iStackPos);
+ m_vBase.push_back(a_Oprt);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Add an assignement operator
+
+ Operator entries in byte code consist of:
+ <ul>
+ <li>cmASSIGN code</li>
+ <li>the pointer of the destination variable</li>
+ </ul>
+
+ \sa ParserToken::ECmdCode
+ */
+ void ParserByteCode::AddAssignOp(value_type *a_pVar)
+ {
+ m_vBase.push_back(--m_iStackPos);
+ m_vBase.push_back(cmASSIGN);
+ StorePtr(a_pVar);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Add function to bytecode.
+
+ \param a_iArgc Number of arguments, negative numbers indicate multiarg functions.
+ \param a_pFun Pointer to function callback.
+ */
+ void ParserByteCode::AddFun(void *a_pFun, int a_iArgc)
+ {
+ if (a_iArgc>=0)
+ {
+ m_iStackPos = m_iStackPos - a_iArgc + 1;
+ }
+ else
+ {
+ m_iStackPos = m_iStackPos + a_iArgc + 1;
+ }
+
+ m_vBase.push_back(m_iStackPos);
+ m_vBase.push_back(cmFUNC);
+ m_vBase.push_back(a_iArgc);
+
+ StorePtr(a_pFun);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Add Strung function entry to the parser bytecode.
+ \throw nothrow
+
+ A string function entry consists of the stack position of the return value,
+ followed by a cmSTRFUNC code, the function pointer and an index into the
+ string buffer maintained by the parser.
+ */
+ void ParserByteCode::AddStrFun(void *a_pFun, int a_iArgc, int a_iIdx)
+ {
+ m_iStackPos = m_iStackPos - a_iArgc + 1;
+ m_vBase.push_back(m_iStackPos);
+ m_vBase.push_back(cmFUNC_STR);
+ m_vBase.push_back(a_iArgc);
+ m_vBase.push_back(a_iIdx);
+
+ StorePtr(a_pFun);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Add end marker to bytecode.
+
+ \throw nothrow
+ */
+ void ParserByteCode::Finalize()
+ {
+ // yes we need the end code three times!! (I forgot why)
+ m_vBase.push_back(cmEND);
+ m_vBase.push_back(cmEND);
+ m_vBase.push_back(cmEND);
+
+ // shrink bytecode vector to fit
+ storage_type(m_vBase).swap(m_vBase);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Get Pointer to bytecode data storage. */
+ const ParserByteCode::map_type* ParserByteCode::GetRawData() const
+ {
+ assert(m_vBase.size());
+ return &m_vBase[0];
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Delete the bytecode.
+
+ \throw nothrow
+
+ The name of this function is a violation of my own coding guidelines
+ but this way it's more in line with the STL functions thus more
+ intuitive.
+ */
+ void ParserByteCode::clear()
+ {
+ m_vBase.clear();
+ m_iStackPos = 0;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Remove a value number of entries from the bytecode.
+
+ \attention Currently I don't test if the entries are really value entries.
+ */
+ void ParserByteCode::RemoveValEntries(unsigned a_iNumber)
+ {
+ unsigned iSize = a_iNumber * mc_iSizeValEntry;
+ assert( m_vBase.size() >= iSize );
+ m_vBase.resize(m_vBase.size()-iSize);
+
+ assert(m_iStackPos >= a_iNumber);
+ m_iStackPos -= (a_iNumber);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Dump bytecode (for debugging only!). */
+ void ParserByteCode::AsciiDump()
+ {
+ if (!m_vBase.size())
+ {
+ std::cout << "No bytecode available\n";
+ return;
+ }
+
+ std::cout << "Entries:" << (int)m_vBase.size()
+ << " (ValSize:" << mc_iSizeVal
+ << " entries, PtrSize:" << mc_iSizePtr
+ << " entries, MapSize:" << sizeof(map_type)
+ << " byte)\n";
+ int i = 0;
+
+ while ( m_vBase[i] != cmEND && i<(int)m_vBase.size())
+ {
+ std::cout << "IDX[" << m_vBase[i++] << "]\t";
+ switch (m_vBase[i])
+ {
+ case cmVAL: std::cout << "VAL "; ++i;
+ std::cout << "[" << *( reinterpret_cast<double*>(&m_vBase[i]) ) << "]\n";
+ i += mc_iSizeVal;
+ break;
+
+ case cmVAR: std::cout << "VAR "; ++i;
+ std::cout << "[ADDR: 0x" << std::hex << *(value_type**)&m_vBase[i] << "]\n";
+ i += mc_iSizePtr;
+
+ // Variable entries have the same size like value entries
+ // the remaining spave must be skipped
+ i+= std::max(mc_iSizeVal - mc_iSizePtr, 0);
+ break;
+
+ case cmFUNC:
+ std::cout << "CALL\t"; ++i;
+ std::cout << "[ARG:" << std::dec << m_vBase[i] << "]"; ++i;
+ std::cout << "[ADDR: 0x" << std::hex << *(value_type**)&m_vBase[i] << "]\n";
+ i += mc_iSizePtr;
+ break;
+
+ case cmFUNC_STR:
+ std::cout << "CALL STRFUNC\t"; ++i;
+ std::cout << "[ARG:" << std::dec << m_vBase[i] << "]"; ++i;
+ std::cout << "[IDX:" << std::dec << m_vBase[i] << "]"; ++i;
+ std::cout << "[ADDR: 0x" << *(value_type**)&m_vBase[i] << "]\n";
+ i += mc_iSizePtr;
+ break;
+
+ case cmLT: std::cout << "LT\n"; ++i; break;
+ case cmGT: std::cout << "GT\n"; ++i; break;
+ case cmLE: std::cout << "LE\n"; ++i; break;
+ case cmGE: std::cout << "GE\n"; ++i; break;
+ case cmEQ: std::cout << "EQ\n"; ++i; break;
+ case cmNEQ: std::cout << "NEQ\n"; ++i; break;
+ case cmADD: std::cout << "ADD\n"; ++i; break;
+ case cmAND: std::cout << "AND\n"; ++i; break;
+ case cmOR: std::cout << "OR\n"; ++i; break;
+ case cmXOR: std::cout << "XOR\n"; ++i; break;
+ case cmSUB: std::cout << "SUB\n"; ++i; break;
+ case cmMUL: std::cout << "MUL\n"; ++i; break;
+ case cmDIV: std::cout << "DIV\n"; ++i; break;
+ case cmPOW: std::cout << "POW\n"; ++i; break;
+
+ case cmASSIGN:
+ std::cout << "ASSIGN\t"; ++i;
+ std::cout << "[ADDR: 0x" << *(value_type**)&m_vBase[i] << "]\n";
+ i += mc_iSizePtr;
+ break;
+
+ default: std::cout << "(unknown code: " << m_vBase[i] << ")\n";
+ ++i;
+ break;
+ } // switch cmdCode
+ } // while bytecode
+
+ std::cout << "END" << std::endl;
+ }
+} // namespace mu
diff --git a/muparser/muParserBytecode.h b/muparser/muParserBytecode.h
new file mode 100644
index 0000000..d425990
--- /dev/null
+++ b/muparser/muParserBytecode.h
@@ -0,0 +1,148 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef MU_PARSER_BYTECODE_H
+#define MU_PARSER_BYTECODE_H
+
+#include <cassert>
+#include <string>
+#include <stack>
+#include <vector>
+
+#include "muParserDef.h"
+#include "muParserError.h"
+#include "muParserToken.h"
+
+
+namespace mu
+{
+
+
+/** \brief Bytecode implementation of the Math Parser.
+
+ The bytecode contains the formula converted to revers polish notation stored in a continious
+ memory area. Associated with this data are operator codes, variable pointers, constant
+ values and function pointers. Those are necessary in order to calculate the result.
+ All those data items will be casted to the underlying datatype of the bytecode.
+
+ \author (C) 2004, 2005 Ingo Berg
+*/
+class ParserByteCode
+{
+public:
+ /** \brief Underlying type of the container.
+
+ The bytecode is a vector of this type containing control codes,
+ values and pointers. Values and pointer will be casted to this
+ type before their storage.
+ */
+ typedef bytecode_type map_type;
+
+private:
+
+ /** \brief Token type for internal use only. */
+ typedef ParserToken<value_type, string_type> token_type;
+
+ /** \brief Core type of the bytecode. */
+ typedef std::vector<map_type> storage_type;
+
+ /** \brief Position in the Calculation array. */
+ unsigned m_iStackPos;
+
+ /** \brief Core type of the bytecode. */
+ storage_type m_vBase;
+
+ /** \brief Size of a value entry in the bytecode, relative to TMapType size. */
+ const int mc_iSizeVal;
+
+ /** \brief Size of a pointer, relative to size of underlying TMapType.
+
+ \attention The size is related to the size of TMapType not bytes!
+ */
+ const int mc_iSizePtr;
+
+ /** \brief A value entry requires that much entires in the bytecode.
+
+ Value entry consists of:
+ <ul>
+ <li>One entry for Stack index</li>
+ <li>One entry for Token identifier</li>
+ <li>mc_iSizeVal entries for the value</li>
+ <ul>
+
+ \sa AddVal(TBaseData a_fVal)
+ */
+ const int mc_iSizeValEntry;
+
+ void StorePtr(void *a_pAddr);
+
+public:
+ ParserByteCode();
+ ~ParserByteCode();
+ ParserByteCode(const ParserByteCode &a_ByteCode);
+ ParserByteCode& operator=(const ParserByteCode &a_ByteCode);
+ void Assign(const ParserByteCode &a_ByteCode);
+
+ void AddVar(value_type *a_pVar);
+ void AddVal(value_type a_fVal);
+ void AddOp(ECmdCode a_Oprt);
+ void AddAssignOp(value_type *a_pVar);
+ void AddFun(void *a_pFun, int a_iArgc);
+ void AddStrFun(void *a_pFun, int a_iArgc, int a_iIdx);
+
+ void Finalize();
+ void clear();
+ const map_type* GetRawData() const;
+
+ /** \brief Return size of a value entry.
+
+ That many bytecode entries are necessary to store a value.
+
+ \sa mc_iSizeVal
+ */
+ unsigned GetValSize() const
+ {
+ return mc_iSizeVal;
+ }
+
+ /** \brief Return size of a pointer entry.
+
+ That many bytecode entries are necessary to store a pointer.
+
+ \sa mc_iSizePtr
+ */
+ unsigned GetPtrSize() const
+ {
+ return mc_iSizePtr;
+ }
+
+ void RemoveValEntries(unsigned a_iNumber);
+ void AsciiDump();
+};
+
+} // namespace mu
+
+#endif
+
+
diff --git a/muparser/muParserCallback.cpp b/muparser/muParserCallback.cpp
new file mode 100644
index 0000000..1312ad7
--- /dev/null
+++ b/muparser/muParserCallback.cpp
@@ -0,0 +1,198 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "muParserCallback.h"
+
+
+namespace mu
+{
+
+ ParserCallback::ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode)
+ :m_pFun((void*)a_pFun)
+ ,m_iArgc(1)
+ ,m_iPri(a_iPrec)
+ ,m_iCode(a_iCode)
+ ,m_iType(tpDBL)
+ ,m_bAllowOpti(a_bAllowOpti)
+ {}
+
+
+ ParserCallback::ParserCallback( fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode)
+ :m_pFun((void*)a_pFun)
+ ,m_iArgc(2)
+ ,m_iPri(a_iPrec)
+ ,m_iCode(a_iCode)
+ ,m_iType(tpDBL)
+ ,m_bAllowOpti(a_bAllowOpti)
+ {}
+
+
+ ParserCallback::ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti)
+ :m_pFun((void*)a_pFun)
+ ,m_iArgc(3)
+ ,m_iPri(-1)
+ ,m_iCode(cmFUNC)
+ ,m_iType(tpDBL)
+ ,m_bAllowOpti(a_bAllowOpti)
+ {}
+
+
+ ParserCallback::ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti)
+ :m_pFun((void*)a_pFun)
+ ,m_iArgc(4)
+ ,m_iPri(-1)
+ ,m_iCode(cmFUNC)
+ ,m_iType(tpDBL)
+ ,m_bAllowOpti(a_bAllowOpti)
+ {}
+
+ ParserCallback::ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti)
+ :m_pFun((void*)a_pFun)
+ ,m_iArgc(5)
+ ,m_iPri(-1)
+ ,m_iCode(cmFUNC)
+ ,m_iType(tpDBL)
+ ,m_bAllowOpti(a_bAllowOpti)
+ {}
+
+ ParserCallback::ParserCallback(multfun_type a_pFun, bool a_bAllowOpti)
+ :m_pFun((void*)a_pFun)
+ ,m_iArgc(-1)
+ ,m_iPri(-1)
+ ,m_iCode(cmFUNC)
+ ,m_iType(tpDBL)
+ ,m_bAllowOpti(a_bAllowOpti)
+ {}
+
+ ParserCallback::ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti)
+ :m_pFun((void*)a_pFun)
+ ,m_iArgc(0)
+ ,m_iPri(-1)
+ ,m_iCode(cmFUNC_STR)
+ ,m_iType(tpSTR)
+ ,m_bAllowOpti(a_bAllowOpti)
+ {}
+
+ ParserCallback::ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti)
+ :m_pFun((void*)a_pFun)
+ ,m_iArgc(1)
+ ,m_iPri(-1)
+ ,m_iCode(cmFUNC_STR)
+ ,m_iType(tpSTR)
+ ,m_bAllowOpti(a_bAllowOpti)
+ {}
+
+ ParserCallback::ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti)
+ :m_pFun((void*)a_pFun)
+ ,m_iArgc(2)
+ ,m_iPri(-1)
+ ,m_iCode(cmFUNC_STR)
+ ,m_iType(tpSTR)
+ ,m_bAllowOpti(a_bAllowOpti)
+ {}
+
+ /** \brief Default constructor.
+
+ \throw nothrow
+ */
+ ParserCallback::ParserCallback()
+ :m_pFun(0)
+ ,m_iArgc(0)
+ ,m_iCode(cmUNKNOWN)
+ ,m_iType(tpVOID)
+ ,m_bAllowOpti(0)
+ {}
+
+ /** \brief Copy constructor.
+
+ \throw nothrow
+ */
+ ParserCallback::ParserCallback(const ParserCallback &a_Fun)
+ {
+ m_pFun = a_Fun.m_pFun;
+ m_iArgc = a_Fun.m_iArgc;
+ m_bAllowOpti = a_Fun.m_bAllowOpti;
+ m_iCode = a_Fun.m_iCode;
+ m_iType = a_Fun.m_iType;
+ m_iPri = a_Fun.m_iPri;
+ }
+
+ /** \brief Clone this instance and return a pointer to the new instance. */
+ ParserCallback* ParserCallback::Clone() const
+ {
+ return new ParserCallback(*this);
+ }
+
+
+ /** \brief Return tru if the function is conservative.
+
+ Conservative functions return always the same result for the same argument.
+ \throw nothrow
+ */
+ bool ParserCallback::IsOptimizable() const
+ {
+ return m_bAllowOpti;
+ }
+
+ /** \brief Get the callback address for the parser function.
+
+ The type of the address is void. It needs to be recasted according to the
+ argument number to the right type.
+
+ \throw nothrow
+ \return #pFun
+ */
+ void* ParserCallback::GetAddr() const
+ {
+ return m_pFun;
+ }
+
+ /** \brief Return the callback code. */
+ ECmdCode ParserCallback::GetCode() const
+ {
+ return m_iCode;
+ }
+
+
+ ETypeCode ParserCallback::GetType() const
+ {
+ return m_iType;
+ }
+
+ /** \brief Return the operator priority.
+
+ Only valid if the callback token is an operator token (binary or infix).
+ */
+ int ParserCallback::GetPri() const
+ {
+ return m_iPri;
+ }
+
+ /** \brief Returns the number of function Arguments. */
+ int ParserCallback::GetArgc() const
+ {
+ return m_iArgc;
+ }
+} // namespace mu
diff --git a/muparser/muParserCallback.h b/muparser/muParserCallback.h
new file mode 100644
index 0000000..9fecddb
--- /dev/null
+++ b/muparser/muParserCallback.h
@@ -0,0 +1,94 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MU_PARSER_CALLBACK_H
+#define MU_PARSER_CALLBACK_H
+
+#include "muParserDef.h"
+
+
+namespace mu
+{
+
+/** \brief Encapsulation of prototypes for a numerical parser function.
+
+ Encapsulates the prototyp for numerical parser functions. The class
+ stores the number of arguments for parser functions as well
+ as additional flags indication the function is non optimizeable.
+ The pointer to the callback function pointer is stored as void*
+ and needs to be casted according to the argument count.
+ Negative argument counts indicate a parser function with a variable number
+ of arguments.
+ This class is not used for string function prototyping.
+
+ \author (C) 2004-2006 Ingo Berg
+*/
+class ParserCallback
+{
+public:
+ ParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC);
+ ParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC);
+ ParserCallback(fun_type3 a_pFun, bool a_bAllowOpti);
+ ParserCallback(fun_type4 a_pFun, bool a_bAllowOpti);
+ ParserCallback(fun_type5 a_pFun, bool a_bAllowOpti);
+ ParserCallback(multfun_type a_pFun, bool a_bAllowOpti);
+ ParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti);
+ ParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti);
+ ParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti);
+ ParserCallback();
+ ParserCallback(const ParserCallback &a_Fun);
+
+ ParserCallback* Clone() const;
+
+ bool IsOptimizable() const;
+ void* GetAddr() const;
+ ECmdCode GetCode() const;
+ ETypeCode GetType() const;
+ int GetPri() const;
+ int GetArgc() const;
+
+private:
+ void *m_pFun; ///< Pointer to the callback function, casted to void
+
+ /** \brief Number of numeric function arguments
+
+ This number is negative for functions with variable number of arguments. in this cases
+ they represent the actual number of arguments found.
+ */
+ int m_iArgc;
+ int m_iPri; ///< Valid only for binary and infix operators; Operator precedence.
+ ECmdCode m_iCode;
+ ETypeCode m_iType;
+ bool m_bAllowOpti; ///< Flag indication optimizeability
+};
+
+//------------------------------------------------------------------------------
+/** \brief Container for Callback objects. */
+typedef std::map<string_type, ParserCallback> funmap_type;
+
+} // namespace mu
+
+#endif
+
diff --git a/muparser/muParserDLL.cpp b/muparser/muParserDLL.cpp
new file mode 100644
index 0000000..0f85cb7
--- /dev/null
+++ b/muparser/muParserDLL.cpp
@@ -0,0 +1,657 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#if defined(MUPARSER_DLL) && defined(_WIN32)
+
+#include "muParserDLL.h"
+#include "muParser.h"
+#include "muParserError.h"
+
+
+#define MU_PARSER_TRY \
+ try \
+ {
+
+#define MU_PARSER_CATCH \
+ } \
+ catch(exception_type &e) \
+ { \
+ g_bError = true; \
+ g_ParserError = e; \
+ if (g_pErrHandler) \
+ g_pErrHandler(); \
+ } \
+ catch(...) \
+ { \
+ g_bError = true; \
+ g_ParserError = exception_type(mu::ecINTERNAL_ERROR); \
+ if (g_pErrHandler) \
+ g_pErrHandler(); \
+ }
+
+//---------------------------------------------------------------------------
+typedef mu::ParserBase::exception_type exception_type;
+typedef mu::ParserBase* parser_type;
+
+#if !defined(_UNICODE)
+ typedef std::string string_type;
+#else
+ typedef std::wstring string_type;
+#endif
+
+typedef string_type::value_type char_type;
+
+//---------------------------------------------------------------------------
+//
+//
+// unexported variables
+//
+//
+//---------------------------------------------------------------------------
+
+/** \brief The last exception that was caught.
+*/
+exception_type g_ParserError;
+errhandler_type g_pErrHandler;
+
+//---------------------------------------------------------------------------
+/** \brief Flags indicating an error occured.
+*/
+bool g_bError;
+
+//---------------------------------------------------------------------------
+//
+//
+// unexported functions
+//
+//
+//---------------------------------------------------------------------------
+
+parser_type GetPtr(parser_handle a_hParser)
+{
+ return static_cast<parser_type>(a_hParser);
+}
+
+//---------------------------------------------------------------------------
+/** \brief DLL entry point.
+*/
+BOOL APIENTRY DllMain( HANDLE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ g_pErrHandler = 0;
+ g_bError = false;
+ break;
+
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+
+ return TRUE;
+}
+
+//---------------------------------------------------------------------------
+//
+//
+// exported functions
+//
+//
+//---------------------------------------------------------------------------
+
+MU_PARSER_API void mupSetErrorHandler(errhandler_type a_pHandler)
+{
+ g_pErrHandler = a_pHandler;
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupSetVarFactory(parser_handle a_hParser, facfun_type a_pFactory, void *pUserData)
+{
+ parser_type p(GetPtr(a_hParser));
+ p->SetVarFactory(a_pFactory, pUserData);
+}
+
+//---------------------------------------------------------------------------
+/** \brief Create a new Parser instance and return its handle.
+*/
+MU_PARSER_API parser_handle mupInit()
+{
+ return (void*)(new mu::Parser());
+}
+
+//---------------------------------------------------------------------------
+/** \brief Release the parser instance related with a parser handle.
+*/
+MU_PARSER_API void mupRelease(parser_handle a_hParser)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ delete p;
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+/** \brief Evaluate the expression.
+*/
+MU_PARSER_API double mupEval(parser_handle a_hParser)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ return p->Eval();
+ MU_PARSER_CATCH
+
+ return 0;
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupSetExpr(parser_handle a_hParser, const char *a_szExpr)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->SetExpr(a_szExpr);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupRemoveVar(parser_handle a_hParser, const char *a_szName)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->RemoveVar( string_type(a_szName) );
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+/** \brief Release all parser variables.
+ \param a_hParser Handle to the parser instance.
+*/
+MU_PARSER_API void mupClearVar(parser_handle a_hParser)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->ClearVar();
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+/** \brief Release all parser variables.
+ \param a_hParser Handle to the parser instance.
+*/
+MU_PARSER_API void mupClearConst(parser_handle a_hParser)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->ClearConst();
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+/** \brief Clear all user defined operators.
+ \param a_hParser Handle to the parser instance.
+*/
+MU_PARSER_API void mupClearOprt(parser_handle a_hParser)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->ClearOprt();
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineFun1(parser_handle a_hParser, const char *a_szName, fun_type1 a_pFun, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineFun2(parser_handle a_hParser, const char *a_szName, fun_type2 a_pFun, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineFun3(parser_handle a_hParser, const char *a_szName, fun_type3 a_pFun, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineFun4(parser_handle a_hParser, const char *a_szName, fun_type4 a_pFun, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineFun5(parser_handle a_hParser, const char *a_szName, fun_type5 a_pFun, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineStrFun1(parser_handle a_hParser, const char *a_szName, strfun_type1 a_pFun, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineStrFun2(parser_handle a_hParser, const char *a_szName, strfun_type2 a_pFun, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineStrFun3(parser_handle a_hParser, const char *a_szName, strfun_type3 a_pFun, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineMultFun(parser_handle a_hParser, const char *a_szName, multfun_type a_pFun, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineFun(a_szName, a_pFun, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineOprt(parser_handle a_hParser, const char *a_szName, fun_type2 a_pFun, int a_iPri, bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineOprt(a_szName, a_pFun, a_iPri, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineVar(parser_handle a_hParser, const char *a_szName, double *a_pVar)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineVar(a_szName, a_pVar);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineConst(parser_handle a_hParser, const char *a_szName, double a_fVal)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineConst(a_szName, a_fVal);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineStrConst(parser_handle a_hParser, const char *a_szName, const char *a_szVal)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineStrConst(a_szName, a_szVal);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API const char* mupGetExpr(parser_handle a_hParser)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ return p->GetExpr().c_str();
+ MU_PARSER_CATCH
+
+ return "";
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefinePostfixOprt(parser_handle a_hParser,
+ const char *a_szName,
+ fun_type1 a_pOprt,
+ bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefinePostfixOprt(a_szName, a_pOprt, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineInfixOprt(parser_handle a_hParser,
+ const char *a_szName,
+ fun_type1 a_pOprt,
+ bool a_bAllowOpt)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->DefineInfixOprt(a_szName, a_pOprt, a_bAllowOpt);
+ MU_PARSER_CATCH
+}
+
+// Define character sets for identifiers
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineNameChars(parser_handle a_hParser, const char *a_szCharset)
+{
+ parser_type p(GetPtr(a_hParser));
+ p->DefineNameChars(a_szCharset);
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineOprtChars(parser_handle a_hParser, const char *a_szCharset)
+{
+ parser_type p(GetPtr(a_hParser));
+ p->DefineOprtChars(a_szCharset);
+}
+
+//---------------------------------------------------------------------------
+MU_PARSER_API void mupDefineInfixOprtChars(parser_handle a_hParser, const char *a_szCharset)
+{
+ parser_type p(GetPtr(a_hParser));
+ p->DefineInfixOprtChars(a_szCharset);
+}
+
+//---------------------------------------------------------------------------
+/** \brief Get the number of variables defined in the parser.
+ \param a_hParser [in] Must be a valid parser handle.
+ \return The number of used variables.
+ \sa mupGetExprVar
+*/
+MU_PARSER_API int mupGetVarNum(parser_handle a_hParser)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ const mu::varmap_type VarMap = p->GetVar();
+ return (int)VarMap.size();
+ MU_PARSER_CATCH
+
+ return 0; // never reached
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return a variable that is used in an expression.
+
+ Prior to calling this function call mupGetExprVarNum in order to get the
+ number of variables in the expression. If the parameter a_iVar is greater
+ than the number of variables both a_szName and a_pVar will be set to zero.
+ As a side effect this function will trigger an internal calculation of the
+ expression undefined variables will be set to zero during this calculation.
+ During the calculation user defined callback functions present in the expression
+ will be called, this is unavoidable.
+
+ \param a_hParser [in] A valid parser handle.
+ \param a_iVar [in] The index of the variable to return.
+ \param a_szName [out] Pointer to the variable name.
+ \param a_pVar [out] Pointer to the variable.
+ \throw nothrow
+*/
+MU_PARSER_API void mupGetVar(parser_handle a_hParser, unsigned a_iVar, const char **a_szName, double **a_pVar)
+{
+ // A static buffer is needed for the name since i cant return the
+ // pointer from the map.
+ static char szName[1024];
+
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ const mu::varmap_type VarMap = p->GetVar();
+
+ if (a_iVar>=VarMap.size())
+ {
+ *a_szName = 0;
+ *a_pVar = 0;
+ return;
+ }
+ mu::varmap_type::const_iterator item;
+
+ item = VarMap.begin();
+ for (unsigned i=0; i<a_iVar; ++i)
+ item++;
+
+ strncpy(szName, item->first.c_str(), sizeof(szName));
+ szName[sizeof(szName)-1] = 0;
+
+ *a_szName = &szName[0];
+ *a_pVar = item->second;
+ return;
+
+ MU_PARSER_CATCH
+
+ *a_szName = 0;
+ *a_pVar = 0;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Get the number of variables used in the expression currently set in the parser.
+ \param a_hParser [in] Must be a valid parser handle.
+ \return The number of used variables.
+ \sa mupGetExprVar
+*/
+MU_PARSER_API int mupGetExprVarNum(parser_handle a_hParser)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ const mu::varmap_type VarMap = p->GetUsedVar();
+ return (int)VarMap.size();
+ MU_PARSER_CATCH
+
+ return 0; // never reached
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return a variable that is used in an expression.
+
+ Prior to calling this function call mupGetExprVarNum in order to get the
+ number of variables in the expression. If the parameter a_iVar is greater
+ than the number of variables both a_szName and a_pVar will be set to zero.
+ As a side effect this function will trigger an internal calculation of the
+ expression undefined variables will be set to zero during this calculation.
+ During the calculation user defined callback functions present in the expression
+ will be called, this is unavoidable.
+
+ \param a_hParser [in] A valid parser handle.
+ \param a_iVar [in] The index of the variable to return.
+ \param a_szName [out] Pointer to the variable name.
+ \param a_pVar [out] Pointer to the variable.
+ \throw nothrow
+*/
+MU_PARSER_API void mupGetExprVar(parser_handle a_hParser, unsigned a_iVar, const char **a_szName, double **a_pVar)
+{
+ // A static buffer is needed for the name since i cant return the
+ // pointer from the map.
+ static char szName[1024];
+
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ const mu::varmap_type VarMap = p->GetUsedVar();
+
+ if (a_iVar>=VarMap.size())
+ {
+ *a_szName = 0;
+ *a_pVar = 0;
+ return;
+ }
+ mu::varmap_type::const_iterator item;
+
+ item = VarMap.begin();
+ for (unsigned i=0; i<a_iVar; ++i)
+ item++;
+
+ strncpy(szName, item->first.c_str(), sizeof(szName));
+ szName[sizeof(szName)-1] = 0;
+
+ *a_szName = &szName[0];
+ *a_pVar = item->second;
+ return;
+
+ MU_PARSER_CATCH
+
+ *a_szName = 0;
+ *a_pVar = 0;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return the number of constants defined in a parser. */
+MU_PARSER_API int mupGetConstNum(parser_handle a_hParser)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ const mu::valmap_type ValMap = p->GetConst();
+ return (int)ValMap.size();
+ MU_PARSER_CATCH
+
+ return 0; // never reached
+}
+
+//---------------------------------------------------------------------------
+/** \brief Retrieve name and value of a single parser constant.
+ \param a_hParser [in] a valid parser handle
+ \param a_iVar [in] Index of the constant to query
+ \param a_pszName [out] pointer to a null terminated string with the constant name
+ \param [out] The constant value
+*/
+MU_PARSER_API void mupGetConst(parser_handle a_hParser, unsigned a_iVar,
+ const char **a_pszName, double &a_fVal)
+{
+ // A static buffer is needed for the name since i cant return the
+ // pointer from the map.
+ static char szName[1024];
+
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ const mu::valmap_type ValMap = p->GetConst();
+
+ if (a_iVar>=ValMap.size())
+ {
+ *a_pszName = 0;
+ a_fVal = 0;
+ return;
+ }
+
+ mu::valmap_type::const_iterator item;
+ item = ValMap.begin();
+ for (unsigned i=0; i<a_iVar; ++i)
+ item++;
+
+ strncpy(szName, item->first.c_str(), sizeof(szName));
+ szName[sizeof(szName)-1] = 0;
+
+ *a_pszName = &szName[0];
+ a_fVal = item->second;
+ return;
+
+ MU_PARSER_CATCH
+
+ *a_pszName = 0;
+ a_fVal = 0;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Add a custom value regognition function.
+*/
+MU_PARSER_API void mupAddValIdent(parser_handle a_hParser, identfun_type a_pFun)
+{
+ MU_PARSER_TRY
+ parser_type p(GetPtr(a_hParser));
+ p->AddValIdent(a_pFun);
+ MU_PARSER_CATCH
+}
+
+//---------------------------------------------------------------------------
+/** \brief Query if an error occured.
+
+ After querying the internal error bit will be reset. So a consecutive call
+ will return false.
+*/
+MU_PARSER_API bool mupError()
+{
+ bool bError(g_bError);
+ g_bError = false;
+ return bError;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Reset the internal error flag.
+*/
+MU_PARSER_API void mupErrorReset()
+{
+ g_bError = false;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return the message associated with the last error.
+*/
+MU_PARSER_API const char* mupGetErrorMsg()
+{
+ return g_ParserError.GetMsg().c_str();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return the message associated with the last error.
+*/
+MU_PARSER_API const char* mupGetErrorToken()
+{
+ return g_ParserError.GetToken().c_str();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return the code associated with the last error.
+*/
+MU_PARSER_API int mupGetErrorCode()
+{
+ return g_ParserError.GetCode();
+}
+
+//---------------------------------------------------------------------------
+/** \brief Return the postion associated with the last error. */
+MU_PARSER_API int mupGetErrorPos()
+{
+ return (int)g_ParserError.GetPos();
+}
+
+
+#endif // MUPARSER_DLL
diff --git a/muparser/muParserDLL.h b/muparser/muParserDLL.h
new file mode 100644
index 0000000..20e2db8
--- /dev/null
+++ b/muparser/muParserDLL.h
@@ -0,0 +1,123 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+// Folgender ifdef-Block ist die Standardmethode zum Erstellen von Makros, die das Exportieren
+// aus einer DLL vereinfachen. Alle Dateien in der DLL werden mit dem MUPARSERLIB_EXPORTS-Symbol
+// kompiliert, das in der Befehlszeile definiert wurde. Das Symbol darf nicht für ein Projekt definiert werden,
+// das diese DLL verwendet. Alle anderen Projekte, deren Quelldateien diese Datei beinhalten, erkennen
+// MUPARSERLIB_API-Funktionen als aus einer DLL importiert, während die DLL mit diesem Makro
+// definierte Symbole als exportiert ansieht.
+#ifndef MU_PARSER_DLL_H
+#define MU_PARSER_DLL_H
+
+#ifdef MUPARSERLIB_EXPORTS
+#define MU_PARSER_API __declspec(dllexport)
+#else
+#define MU_PARSER_API __declspec(dllimport)
+#endif
+
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef void* parser_handle;
+typedef double (*fun_type1)(double);
+typedef double (*fun_type2)(double, double);
+typedef double (*fun_type3)(double, double, double);
+typedef double (*fun_type4)(double, double, double, double);
+typedef double (*fun_type5)(double, double, double, double, double);
+typedef double (*multfun_type)(const double*, int);
+typedef double (*strfun_type1)(const char*);
+typedef double (*strfun_type2)(const char*, double);
+typedef double (*strfun_type3)(const char*, double, double);
+typedef void (*errhandler_type)();
+typedef double* (*facfun_type)(const char*, void *);
+typedef bool (*identfun_type)(const char*, int&, double&);
+
+extern "C"
+{
+
+// Basic operations / initialization
+MU_PARSER_API parser_handle mupInit();
+MU_PARSER_API void mupRelease(parser_handle a_hParser);
+MU_PARSER_API const char* mupGetExpr(parser_handle a_hParser);
+MU_PARSER_API void mupSetExpr(parser_handle a_hParser, const char *a_szExpr);
+MU_PARSER_API void mupSetErrorHandler(errhandler_type a_pErrHandler);
+MU_PARSER_API void mupSetVarFactory(parser_handle a_hParser, facfun_type a_pFactory, void *pUserData);
+
+MU_PARSER_API double mupEval(parser_handle a_hParser);
+
+// Defining callbacks / variables / constants
+MU_PARSER_API void mupDefineFun1(parser_handle a_hParser, const char *a_szName, fun_type1 a_pFun, bool a_bAllowOpt = true);
+MU_PARSER_API void mupDefineFun2(parser_handle a_hParser, const char *a_szName, fun_type2 a_pFun, bool a_bAllowOpt = true);
+MU_PARSER_API void mupDefineFun3(parser_handle a_hParser, const char *a_szName, fun_type3 a_pFun, bool a_bAllowOpt = true);
+MU_PARSER_API void mupDefineFun4(parser_handle a_hParser, const char *a_szName, fun_type4 a_pFun, bool a_bAllowOpt = true);
+MU_PARSER_API void mupDefineFun5(parser_handle a_hParser, const char *a_szName, fun_type5 a_pFun, bool a_bAllowOpt = true);
+// string functions
+MU_PARSER_API void mupDefineStrFun1(parser_handle a_hParser, const char *a_szName, strfun_type1 a_pFun, bool a_bAllowOpt = true);
+MU_PARSER_API void mupDefineStrFun2(parser_handle a_hParser, const char *a_szName, strfun_type2 a_pFun, bool a_bAllowOpt = true);
+MU_PARSER_API void mupDefineStrFun3(parser_handle a_hParser, const char *a_szName, strfun_type3 a_pFun, bool a_bAllowOpt = true);
+
+MU_PARSER_API void mupDefineMultFun(parser_handle a_hParser, const char *a_szName, multfun_type a_pFun, bool a_bAllowOpt = true);
+MU_PARSER_API void mupDefineOprt(parser_handle a_hParser, const char *a_szName, fun_type2 a_pFun, int a_iPri = 0, bool a_bAllowOpt = true);
+MU_PARSER_API void mupDefineConst(parser_handle a_hParser, const char *a_szName, double a_fVal);
+MU_PARSER_API void mupDefineStrConst(parser_handle a_hParser, const char *a_szName, const char *a_sVal);
+MU_PARSER_API void mupDefineVar(parser_handle a_hParser, const char *a_szName, double *a_fVar);
+MU_PARSER_API void mupDefinePostfixOprt(parser_handle a_hParser, const char *a_szName, fun_type1 a_pOprt, bool a_bAllowOpt = true);
+MU_PARSER_API void mupDefineInfixOprt(parser_handle a_hParser, const char *a_szName, fun_type1 a_pOprt, bool a_bAllowOpt=true);
+
+// Define character sets for identifiers
+MU_PARSER_API void mupDefineNameChars(parser_handle a_hParser, const char *a_szCharset);
+MU_PARSER_API void mupDefineOprtChars(parser_handle a_hParser, const char *a_szCharset);
+MU_PARSER_API void mupDefineInfixOprtChars(parser_handle a_hParser, const char *a_szCharset);
+
+// Remove all / single variables
+MU_PARSER_API void mupRemoveVar(parser_handle a_hParser, const char *a_szName);
+MU_PARSER_API void mupClearVar(parser_handle a_hParser);
+MU_PARSER_API void mupClearConst(parser_handle a_hParser);
+MU_PARSER_API void mupClearOprt(parser_handle a_hParser);
+
+// Querying variables / expression variables / constants
+MU_PARSER_API int mupGetExprVarNum(parser_handle a_hParser);
+MU_PARSER_API int mupGetVarNum(parser_handle a_hParser);
+MU_PARSER_API int mupGetConstNum(parser_handle a_hParser);
+MU_PARSER_API void mupGetExprVar(parser_handle a_hParser, unsigned a_iVar, const char **a_pszName, double **a_pVar);
+MU_PARSER_API void mupGetVar(parser_handle a_hParser, unsigned a_iVar, const char **a_pszName, double **a_pVar);
+MU_PARSER_API void mupGetConst(parser_handle a_hParser, unsigned a_iVar, const char **a_pszName, double &a_pVar);
+
+// Add value recognition callbacks
+MU_PARSER_API void mupAddValIdent(parser_handle a_hParser, identfun_type);
+
+// Error handling
+MU_PARSER_API bool mupError();
+MU_PARSER_API void mupErrorReset();
+MU_PARSER_API const char* mupGetErrorMsg();
+MU_PARSER_API int mupGetErrorCode();
+MU_PARSER_API int mupGetErrorPos();
+MU_PARSER_API const char* mupGetErrorToken();
+
+} // extern "C"
+
+#endif
diff --git a/muparser/muParserDef.h b/muparser/muParserDef.h
new file mode 100644
index 0000000..164b882
--- /dev/null
+++ b/muparser/muParserDef.h
@@ -0,0 +1,239 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef MUP_DEF_H
+#define MUP_DEF_H
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <map>
+
+#include "muParserFixes.h"
+
+/** \brief Define the base datatype for values.
+
+ This datatype must be a built in value type. You can not use custom classes.
+ It has been tested with float, double and long double types, int should
+ work as well.
+*/
+#define MUP_BASETYPE double
+
+
+/** \brief Definition of the basic bytecode datatype. */
+#define MUP_BYTECODE_TYPE long
+
+/** \brief Maybe I use this for unicode support later. */
+#if defined(_UNICODE)
+ /** \brief Definition of the basic parser string type. */
+ #define MUP_STRING_TYPE std::wstring
+
+ #if !defined(_T)
+ #define _T(x) L##x
+ #endif // not defined _T
+#else
+ #ifndef _T
+ #define _T
+ #endif
+
+ /** \brief Definition of the basic parser string type. */
+ #define MUP_STRING_TYPE std::string
+#endif
+
+#if defined(_DEBUG)
+ /** \brief Debug macro to force an abortion of the programm with a certain message.
+ */
+ #define MUP_FAIL(MSG) \
+ bool MSG=false; \
+ assert(MSG);
+
+ #ifndef _UNICODE
+ /** \brief An assertion that does not kill the program.
+
+ This macro is neutralised in UNICODE builds. It's
+ too difficult to translate.
+ */
+ #define MUP_ASSERT(COND) \
+ if (!(COND)) \
+ { \
+ stringstream_type ss; \
+ ss << "Assertion \""#COND"\" failed: " \
+ << __FILE__ << " line " \
+ << __LINE__ << "."; \
+ throw ParserError( ss.str() ); \
+ }
+ #else
+ #define MUP_ASSERT(COND)
+ #endif // _UNICODE
+#else
+ #define MUP_FAIL(MSG)
+ #define MUP_ASSERT(COND)
+#endif
+
+//------------------------------------------------------------------------------
+//
+// do not change anything beyond this point...
+//
+// !!! This section is devoted to macros that are used for debugging
+// !!! or for features that are not fully implemented yet.
+//
+//#define MUP_DUMP_STACK
+//#define MUP_DUMP_CMDCODE
+
+
+namespace mu
+{
+#if defined(_UNICODE)
+
+ //------------------------------------------------------------------------------
+ /** \brief Encapsulate wcout. */
+ inline std::wostream& console()
+ {
+ return std::wcout;
+ }
+
+ /** \brief Encapsulate cin. */
+ inline std::wistream& console_in()
+ {
+ return std::wcin;
+ }
+
+#else
+
+ /** \brief Encapsulate cout. */
+ inline std::ostream& console()
+ {
+ return std::cout;
+ }
+
+ /** \brief Encapsulate cin. */
+ inline std::istream& console_in()
+ {
+ return std::cin;
+ }
+
+#endif
+
+ //------------------------------------------------------------------------------
+ /** \brief Bytecode values.
+
+ \attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt!
+ */
+ enum ECmdCode
+ {
+ // The following are codes for built in binary operators
+ // apart from built in operators the user has the opportunity to
+ // add user defined operators.
+ cmLE = 0, ///< Operator item: less or equal
+ cmGE = 1, ///< Operator item: greater or equal
+ cmNEQ = 2, ///< Operator item: not equal
+ cmEQ = 3, ///< Operator item: equals
+ cmLT = 4, ///< Operator item: less than
+ cmGT = 5, ///< Operator item: greater than
+ cmADD = 6, ///< Operator item: add
+ cmSUB = 7, ///< Operator item: subtract
+ cmMUL = 8, ///< Operator item: multiply
+ cmDIV = 9, ///< Operator item: division
+ cmPOW = 10, ///< Operator item: y to the power of ...
+ cmAND = 11, ///< Operator item: logical and
+ cmOR = 12, ///< Operator item: logical or
+ cmXOR = 13, ///< Operator item: logical xor
+ cmASSIGN = 14, ///< Operator item: Assignment operator
+ cmBO = 15, ///< Operator item: opening bracket
+ cmBC = 16, ///< Operator item: closing bracket
+ cmCOMMA = 17, ///< Operator item: comma
+ cmVAR = 18, ///< variable item
+ cmSTRVAR = 19,
+ cmVAL = 20, ///< value item
+
+ cmFUNC = 21, ///< Code for a function item
+ cmFUNC_STR = 22, ///< Code for a function with a string parameter
+
+ cmSTRING = 23, ///< Code for a string token
+ cmOPRT_BIN = 24, ///< user defined binary operator
+ cmOPRT_POSTFIX = 25, ///< code for postfix operators
+ cmOPRT_INFIX = 26, ///< code for infix operators
+ cmEND = 27, ///< end of formula
+ cmUNKNOWN = 28 ///< uninitialized item
+ };
+
+ //------------------------------------------------------------------------------
+ /** \brief Types internally used by the parser.
+ */
+ enum ETypeCode
+ {
+ tpSTR = 0, ///> String type (Function arguments and constants only, no string variables)
+ tpDBL = 1, ///> Floating point variables
+ tpVOID = 2 ///> Undefined type.
+ };
+
+ //------------------------------------------------------------------------------
+ /** \brief Parser operator precedence values. */
+ enum EPrec
+ {
+ // binary operators
+ prLOGIC = 1, ///> logic operators
+ prCMP = 2, ///> comparsion operators
+ prADD_SUB = 3, ///> addition
+ prMUL_DIV = 4, ///> multiplication/division
+ prPOW = 5, ///> power operator priority (highest)
+
+ // infix operators
+ prINFIX = 4, ///> Signs have a higher priority than ADD_SUB, but lower than power operator
+ prPOSTFIX = 4 ///> Postfix operator priority (currently unused)
+ };
+
+ //------------------------------------------------------------------------------
+ // basic types
+ typedef MUP_BASETYPE value_type;
+ typedef MUP_STRING_TYPE string_type;
+ typedef MUP_BYTECODE_TYPE bytecode_type;
+ typedef string_type::value_type char_type;
+ typedef std::basic_stringstream<char_type,
+ std::char_traits<char_type>,
+ std::allocator<char_type> > stringstream_type;
+
+ // Data container types
+ typedef std::map<string_type, value_type*> varmap_type;
+ typedef std::map<string_type, value_type> valmap_type;
+ typedef std::map<string_type, std::size_t> strmap_type;
+
+ // Parser callbacks
+ typedef value_type (*fun_type1)(value_type);
+ typedef value_type (*fun_type2)(value_type, value_type);
+ typedef value_type (*fun_type3)(value_type, value_type, value_type);
+ typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type);
+ typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type);
+ typedef value_type (*multfun_type)(const value_type*, int);
+ typedef value_type (*strfun_type1)(const char_type*);
+ typedef value_type (*strfun_type2)(const char_type*, value_type);
+ typedef value_type (*strfun_type3)(const char_type*, value_type, value_type);
+
+ // Parser utility callback functions (unrelated to the math callbacks)
+ typedef bool (*identfun_type)(const char_type*, int&, value_type&);
+ typedef value_type* (*facfun_type)(const char_type*, void*);
+} // end fo namespace
+
+#endif
+
diff --git a/muparser/muParserError.cpp b/muparser/muParserError.cpp
new file mode 100644
index 0000000..237f529
--- /dev/null
+++ b/muparser/muParserError.cpp
@@ -0,0 +1,300 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#include "muParserError.h"
+
+
+namespace mu
+{
+ const ParserErrorMsg ParserErrorMsg::m_Instance;
+
+ //------------------------------------------------------------------------------
+ const ParserErrorMsg& ParserErrorMsg::Instance()
+ {
+ return m_Instance;
+ }
+
+ //------------------------------------------------------------------------------
+ string_type ParserErrorMsg::operator[](unsigned a_iIdx) const
+ {
+ return (a_iIdx<m_vErrMsg.size()) ? m_vErrMsg[a_iIdx] : string_type();
+ }
+
+
+ //---------------------------------------------------------------------------
+ ParserErrorMsg::~ParserErrorMsg()
+ {}
+
+ //---------------------------------------------------------------------------
+ /** \brief Assignement operator is deactivated.
+ */
+ ParserErrorMsg& ParserErrorMsg::operator=(const ParserErrorMsg& )
+ {
+ assert(false);
+ return *this;
+ }
+
+ //---------------------------------------------------------------------------
+ ParserErrorMsg::ParserErrorMsg(const ParserErrorMsg&)
+ {}
+
+ //---------------------------------------------------------------------------
+ ParserErrorMsg::ParserErrorMsg()
+ :m_vErrMsg(0)
+ {
+ m_vErrMsg.resize(ecCOUNT);
+
+ m_vErrMsg[ecUNASSIGNABLE_TOKEN] = _T("Undefined token \"$TOK$\" found at position $POS$.");
+ m_vErrMsg[ecINTERNAL_ERROR] = _T("Internal error");
+ m_vErrMsg[ecINVALID_NAME] = _T("Invalid function-, variable- or constant name.");
+ m_vErrMsg[ecINVALID_FUN_PTR] = _T("Invalid pointer to callback function.");
+ m_vErrMsg[ecEMPTY_EXPRESSION] = _T("Expression is empty.");
+ m_vErrMsg[ecINVALID_VAR_PTR] = _T("Invalid pointer to variable.");
+ m_vErrMsg[ecUNEXPECTED_OPERATOR] = _T("Unexpected operator \"$TOK$\" found at position $POS$");
+ m_vErrMsg[ecUNEXPECTED_EOF] = _T("Unexpected end of formula at position $POS$");
+ m_vErrMsg[ecUNEXPECTED_COMMA] = _T("Unexpected comma at position $POS$");
+ m_vErrMsg[ecUNEXPECTED_PARENS] = _T("Unexpected parenthesis \"$TOK$\" at position $POS$");
+ m_vErrMsg[ecUNEXPECTED_FUN] = _T("Unexpected function \"$TOK$\" at position $POS$");
+ m_vErrMsg[ecUNEXPECTED_VAL] = _T("Unexpected value \"$TOK$\" found at position $POS$");
+ m_vErrMsg[ecUNEXPECTED_VAR] = _T("Unexpected variable \"$TOK$\" found at position $POS$");
+ m_vErrMsg[ecUNEXPECTED_ARG] = _T("Function arguments used without a function (position: $POS$)");
+ m_vErrMsg[ecMISSING_PARENS] = _T("Missing parenthesis");
+ m_vErrMsg[ecTOO_MANY_PARAMS] = _T("Too many parameters for function \"$TOK$\" at formula position $POS$");
+ m_vErrMsg[ecTOO_FEW_PARAMS] = _T("Too few parameters for function \"$TOK$\" at formula position $POS$");
+ m_vErrMsg[ecDIV_BY_ZERO] = _T("Divide by zero");
+ m_vErrMsg[ecDOMAIN_ERROR] = _T("Domain error");
+ m_vErrMsg[ecNAME_CONFLICT] = _T("Name conflict");
+ m_vErrMsg[ecOPT_PRI] = _T("Invalid value for operator priority (must be greater or equal to zero).");
+ m_vErrMsg[ecBUILTIN_OVERLOAD] = _T("Binary operator identifier conflicts with a built in operator.");
+ m_vErrMsg[ecUNEXPECTED_STR] = _T("Unexpected string token found at position $POS$.");
+ m_vErrMsg[ecUNTERMINATED_STRING] = _T("Unterminated string starting at position $POS$.");
+ m_vErrMsg[ecSTRING_EXPECTED] = _T("String function called with a non string type of argument.");
+ m_vErrMsg[ecVAL_EXPECTED] = _T("String value used where a numerical argument is expected.");
+ m_vErrMsg[ecOPRT_TYPE_CONFLICT] = _T("No suitable overload for operator \"$TOK$\" at position $POS$.");
+ m_vErrMsg[ecGENERIC] = _T("Parser error.");
+ m_vErrMsg[ecSTR_RESULT] = _T("Function result is a string.");
+
+ #if defined(_DEBUG)
+ for (int i=0; i<ecCOUNT; ++i)
+ if (!m_vErrMsg[i].length())
+ assert(false);
+ #endif
+ }
+
+ //---------------------------------------------------------------------------
+ //
+ //
+ //
+ // ParserError class
+ //
+ //
+ //
+ //---------------------------------------------------------------------------
+
+ //------------------------------------------------------------------------------
+ ParserError::ParserError()
+ :m_strMsg()
+ ,m_strFormula()
+ ,m_strTok()
+ ,m_iPos(-1)
+ ,m_iErrc(ecUNDEFINED)
+ ,m_ErrMsg(ParserErrorMsg::Instance())
+ {
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief This Constructor is used for internal exceptions only.
+
+ It does not contain any information but the error code.
+ */
+ ParserError::ParserError(EErrorCodes /*a_iErrc*/)
+ :m_ErrMsg(ParserErrorMsg::Instance())
+ {
+ Reset();
+ m_strMsg = _T("parser error");
+ }
+
+ //------------------------------------------------------------------------------
+ ParserError::ParserError(const string_type &sMsg)
+ :m_ErrMsg(ParserErrorMsg::Instance())
+ {
+ Reset();
+ m_strMsg = sMsg;
+ }
+
+ //------------------------------------------------------------------------------
+ ParserError::ParserError( EErrorCodes a_iErrc,
+ const string_type &sTok,
+ const string_type &sFormula,
+ int a_iPos )
+ :m_strMsg()
+ ,m_strFormula(sFormula)
+ ,m_strTok(sTok)
+ ,m_iPos(a_iPos)
+ ,m_iErrc(a_iErrc)
+ ,m_ErrMsg(ParserErrorMsg::Instance())
+ {
+ m_strMsg = m_ErrMsg[m_iErrc];
+ stringstream_type stream;
+ stream << (int)m_iPos;
+ ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
+ ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
+ }
+
+ //------------------------------------------------------------------------------
+ ParserError::ParserError( EErrorCodes a_iErrc, int a_iPos, const string_type &sTok)
+ :m_strMsg()
+ ,m_strFormula()
+ ,m_strTok(sTok)
+ ,m_iPos(a_iPos)
+ ,m_iErrc(a_iErrc)
+ ,m_ErrMsg(ParserErrorMsg::Instance())
+ {
+ m_strMsg = m_ErrMsg[m_iErrc];
+ stringstream_type stream;
+ stream << (int)m_iPos;
+ ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
+ ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
+ }
+
+ //------------------------------------------------------------------------------
+ ParserError::ParserError( const char_type *a_szMsg, int a_iPos, const string_type &sTok)
+ :m_strMsg(a_szMsg)
+ ,m_strFormula()
+ ,m_strTok(sTok)
+ ,m_iPos(a_iPos)
+ ,m_iErrc(ecGENERIC)
+ ,m_ErrMsg(ParserErrorMsg::Instance())
+ {
+ stringstream_type stream;
+ stream << (int)m_iPos;
+ ReplaceSubString(m_strMsg, _T("$POS$"), stream.str());
+ ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok);
+ }
+
+ //------------------------------------------------------------------------------
+ ParserError::ParserError(const ParserError &a_Obj)
+ :m_strMsg(a_Obj.m_strMsg)
+ ,m_strFormula(a_Obj.m_strFormula)
+ ,m_strTok(a_Obj.m_strTok)
+ ,m_iPos(a_Obj.m_iPos)
+ ,m_iErrc(a_Obj.m_iErrc)
+ ,m_ErrMsg(ParserErrorMsg::Instance())
+ {
+ }
+
+ //------------------------------------------------------------------------------
+ ParserError& ParserError::operator=(const ParserError &a_Obj)
+ {
+ if (this==&a_Obj)
+ return *this;
+
+ m_strMsg = a_Obj.m_strMsg;
+ m_strFormula = a_Obj.m_strFormula;
+ m_strTok = a_Obj.m_strTok;
+ m_iPos = a_Obj.m_iPos;
+ m_iErrc = a_Obj.m_iErrc;
+ return *this;
+ }
+
+ //------------------------------------------------------------------------------
+ ParserError::~ParserError()
+ {
+ }
+
+ /** \brief Replace all ocuurences of a substring with another string. */
+ void ParserError::ReplaceSubString( string_type &strSource,
+ const string_type &strFind,
+ const string_type &strReplaceWith)
+ {
+ string_type strResult;
+ string_type::size_type iPos(0), iNext(0);
+
+ for(;;)
+ {
+ iNext = strSource.find(strFind, iPos);
+ strResult.append(strSource, iPos, iNext-iPos);
+
+ if( iNext==string_type::npos )
+ break;
+
+ strResult.append(strReplaceWith);
+ iPos = iNext + strFind.length();
+ }
+
+ strSource.swap(strResult);
+ }
+
+ //------------------------------------------------------------------------------
+ void ParserError::Reset()
+ {
+ m_strMsg = _T("");
+ m_strFormula = _T("");
+ m_strTok = _T("");
+ m_iPos = -1;
+ m_iErrc = ecUNDEFINED;
+ }
+
+ //------------------------------------------------------------------------------
+ void ParserError::SetFormula(const string_type &a_strFormula)
+ {
+ m_strFormula = a_strFormula;
+ }
+
+ //------------------------------------------------------------------------------
+ const string_type& ParserError::GetExpr() const
+ {
+ return m_strFormula;
+ }
+
+ //------------------------------------------------------------------------------
+ const string_type& ParserError::GetMsg() const
+ {
+ return m_strMsg;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Return the formula position related to the error.
+
+ If the error is not related to a distinct position this will return -1
+ */
+ std::size_t ParserError::GetPos() const
+ {
+ return m_iPos;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Return string related with this token (if available). */
+ const string_type& ParserError::GetToken() const
+ {
+ return m_strTok;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Return the error code. */
+ EErrorCodes ParserError::GetCode() const
+ {
+ return m_iErrc;
+ }
+} // namespace mu
diff --git a/muparser/muParserError.h b/muparser/muParserError.h
new file mode 100644
index 0000000..c550eff
--- /dev/null
+++ b/muparser/muParserError.h
@@ -0,0 +1,160 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MU_PARSER_ERROR_H
+#define MU_PARSER_ERROR_H
+
+#include <cassert>
+#include <stdexcept>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <memory>
+
+#include "muParserDef.h"
+
+
+namespace mu
+{
+
+/** \brief Error codes. */
+enum EErrorCodes
+{
+ // Formula syntax errors
+ ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found
+ ecUNASSIGNABLE_TOKEN = 1, ///< Token cant be identified.
+ ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(")
+ ecUNEXPECTED_COMMA = 3, ///< An unexpected comma has been found. (Example: "1,23")
+ ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found
+ ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found
+ ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found
+ ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing
+ ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position
+ ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument
+ ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument
+ ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3")
+ ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)")
+ ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)")
+ ecTOO_MANY_PARAMS = 14, ///< Too many function parameters
+ ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)")
+ ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type
+ ecSTR_RESULT = 17, ///< result is a string
+
+ // Invalid Parser input Parameters
+ ecINVALID_NAME = 18, ///< Invalid function, variable or constant name.
+ ecBUILTIN_OVERLOAD = 19, ///< Trying to overload builtin operator
+ ecINVALID_FUN_PTR = 20, ///< Invalid callback function pointer
+ ecINVALID_VAR_PTR = 21, ///< Invalid variable pointer
+ ecEMPTY_EXPRESSION = 22, ///< The Expression is empty
+ ecNAME_CONFLICT = 23, ///< Name conflict
+ ecOPT_PRI = 24, ///< Invalid operator priority
+ //
+ ecDOMAIN_ERROR = 25, ///< catch division by zero, sqrt(-1), log(0) (currently unused)
+ ecDIV_BY_ZERO = 26, ///< Division by zero (currently unused)
+ ecGENERIC = 27, ///< Generic error
+
+ // internal errors
+ ecINTERNAL_ERROR = 28, ///< Internal error of any kind.
+
+ // The last two are special entries
+ ecCOUNT, ///< This is no error code, It just stores just the total number of error codes
+ ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages
+};
+
+//---------------------------------------------------------------------------
+class ParserErrorMsg
+{
+public:
+ typedef ParserErrorMsg self_type;
+
+ ParserErrorMsg& operator=(const ParserErrorMsg &);
+ ParserErrorMsg(const ParserErrorMsg&);
+ ParserErrorMsg();
+
+ ~ParserErrorMsg();
+
+ static const ParserErrorMsg& Instance();
+ string_type operator[](unsigned a_iIdx) const;
+
+private:
+ std::vector<string_type> m_vErrMsg;
+ static const self_type m_Instance;
+};
+
+//---------------------------------------------------------------------------
+/** \brief Error class of the parser.
+
+ Part of the math parser package.
+
+ \author Ingo Berg
+*/
+/* final */ class ParserError
+{
+private:
+ //------------------------------------------------------------------------------
+ /** \brief Replace all ocuurences of a substring with another string. */
+ void ReplaceSubString( string_type &strSource,
+ const string_type &strFind,
+ const string_type &strReplaceWith);
+ void Reset();
+
+public:
+ ParserError();
+ explicit ParserError(EErrorCodes a_iErrc);
+ explicit ParserError(const string_type &sMsg);
+ ParserError( EErrorCodes a_iErrc,
+ const string_type &sTok,
+ const string_type &sFormula = string_type(_T("(formula is not available)")),
+ int a_iPos = -1);
+ ParserError( EErrorCodes a_iErrc,
+ int a_iPos,
+ const string_type &sTok);
+ ParserError( const char_type *a_szMsg,
+ int a_iPos = -1,
+ const string_type &sTok = string_type());
+ ParserError(const ParserError &a_Obj);
+ ParserError& operator=(const ParserError &a_Obj);
+ ~ParserError();
+
+ void SetFormula(const string_type &a_strFormula);
+ const string_type& GetExpr() const;
+ const string_type& GetMsg() const;
+ std::size_t GetPos() const;
+ const string_type& GetToken() const;
+ EErrorCodes GetCode() const;
+
+private:
+ string_type m_strMsg; ///< The message string
+ string_type m_strFormula; ///< Formula string
+ string_type m_strTok; ///< Token related with the error
+ int m_iPos; ///< Formula position related to the error
+ EErrorCodes m_iErrc; ///< Error code
+ const ParserErrorMsg &m_ErrMsg;
+};
+
+} // namespace mu
+
+#endif
+
diff --git a/muparser/muParserFixes.h b/muparser/muParserFixes.h
new file mode 100644
index 0000000..02ca007
--- /dev/null
+++ b/muparser/muParserFixes.h
@@ -0,0 +1,196 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MU_PARSER_FIXES_H
+#define MU_PARSER_FIXES_H
+
+//
+// Compatibility fixes
+//
+
+//---------------------------------------------------------------------------
+//
+// Intel Compiler
+//
+//---------------------------------------------------------------------------
+
+#ifdef __INTEL_COMPILER
+
+// remark #981: operands are evaluated in unspecified order
+// disabled -> completely pointless if the functions do not have side effects
+//
+#pragma warning(disable:981)
+
+// remark #383: value copied to temporary, reference to temporary used
+#pragma warning(disable:383)
+
+// remark #1572: floating-point equality and inequality comparisons are unreliable
+// disabled -> everyone knows it, the parser passes this problem
+// deliberately to the user
+#pragma warning(disable:1572)
+
+#endif
+
+
+//---------------------------------------------------------------------------
+//
+// MSVC6
+//
+//---------------------------------------------------------------------------
+
+
+#if _MSC_VER==1200
+
+/** \brief Macro to replace the MSVC6 auto_ptr with the _my_auto_ptr class.
+
+ Hijack auto_ptr and replace it with a version that actually does
+ what an auto_ptr normally does. If you use std::auto_ptr in your other code
+ it might either explode or work much better. The original crap created
+ by Microsoft, called auto_ptr and bundled with MSVC6 is not standard compliant.
+*/
+#define auto_ptr _my_auto_ptr
+
+// This is another stupidity that needs to be undone in order to de-pollute
+// the global namespace!
+#undef min
+#undef max
+
+
+namespace std
+{
+ typedef ::size_t size_t;
+
+ //---------------------------------------------------------------------------
+ /** \brief MSVC6 fix: Dummy function to put rand into namespace std.
+
+ This is a hack for MSVC6 only. It's dirty, it's ugly and it works, provided
+ inlining is enabled. Necessary because I will not pollute or change my
+ code in order to adopt it to MSVC6 interpretation of how C++ should look like!
+ */
+ inline int rand(void)
+ {
+ return ::rand();
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief MSVC6 fix: Dummy function to put strlen into namespace std.
+
+ This is a hack for MSVC6 only. It's dirty, it's ugly and it works, provided
+ inlining is enabled. Necessary because I will not pollute or change my
+ code in order to adopt it to MSVC6 interpretation of how C++ should look like!
+ */
+ inline size_t strlen(const char *szMsg)
+ {
+ return ::strlen(szMsg);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief MSVC6 fix: Dummy function to put strncmp into namespace std.
+
+ This is a hack for MSVC6 only. It's dirty, it's ugly and it works, provided
+ inlining is enabled. Necessary because I will not pollute or change my
+ code in order to adopt it to MSVC6 interpretation of how C++ should look like!
+ */
+ inline int strncmp(const char *a, const char *b, size_t len)
+ {
+ return ::strncmp(a,b,len);
+ }
+
+ //---------------------------------------------------------------------------
+ template<typename T>
+ T max(T a, T b)
+ {
+ return (a>b) ? a : b;
+ }
+
+ //---------------------------------------------------------------------------
+ template<typename T>
+ T min(T a, T b)
+ {
+ return (a<b) ? a : b;
+ }
+
+ //---------------------------------------------------------------------------
+ /** Standard compliant auto_ptr redefinition for MSVC6.
+
+ The code is taken from VS.NET 2003, slightly modified to reduce
+ it's dependencies from other classes.
+ */
+ template<class _Ty>
+ class _my_auto_ptr
+ {
+ public:
+ typedef _Ty element_type;
+
+ explicit _my_auto_ptr(_Ty *_Ptr = 0)
+ :_Myptr(_Ptr)
+ {}
+
+ _my_auto_ptr(_my_auto_ptr<_Ty>& _Right)
+ :_Myptr(_Right.release())
+ {}
+
+ template<class _Other>
+ operator _my_auto_ptr<_Other>()
+ {
+ return (_my_auto_ptr<_Other>(*this));
+ }
+
+ template<class _Other>
+ _my_auto_ptr<_Ty>& operator=(_my_auto_ptr<_Other>& _Right)
+ {
+ reset(_Right.release());
+ return (*this);
+ }
+
+ ~auto_ptr() { delete _Myptr; }
+ _Ty& operator*() const { return (*_Myptr); }
+ _Ty *operator->() const { return (&**this); }
+ _Ty *get() const { return (_Myptr); }
+
+ _Ty *release()
+ {
+ _Ty *_Tmp = _Myptr;
+ _Myptr = 0;
+ return (_Tmp);
+ }
+
+ void reset(_Ty* _Ptr = 0)
+ {
+ if (_Ptr != _Myptr)
+ delete _Myptr;
+ _Myptr = _Ptr;
+ }
+
+ private:
+ _Ty *_Myptr;
+ }; // class _my_auto_ptr
+} // namespace std
+
+#endif // Microsoft Visual Studio Version 6.0
+
+#endif // include guard
+
+
diff --git a/muparser/muParserInt.cpp b/muparser/muParserInt.cpp
new file mode 100644
index 0000000..1b072bc
--- /dev/null
+++ b/muparser/muParserInt.cpp
@@ -0,0 +1,264 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "muParserInt.h"
+
+#include <cmath>
+#include <algorithm>
+#include <numeric>
+
+using namespace std;
+
+
+/** \brief Namespace for mathematical applications. */
+namespace mu
+{
+
+value_type ParserInt::Abs(value_type v) { return Round(fabs(v)); }
+value_type ParserInt::Sign(value_type v) { return (Round(v)<0) ? -1 : (Round(v)>0) ? 1 : 0; }
+value_type ParserInt::Ite(value_type v1,
+ value_type v2,
+ value_type v3) { return (Round(v1)==1) ? Round(v2) : Round(v3); }
+value_type ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); }
+value_type ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); }
+value_type ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); }
+value_type ParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); }
+value_type ParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); }
+value_type ParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); }
+value_type ParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); }
+value_type ParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); }
+value_type ParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); }
+value_type ParserInt::LogXor(value_type v1, value_type v2) { return Round(v1) ^ Round(v2); }
+value_type ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); }
+value_type ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); }
+value_type ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); }
+value_type ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); }
+value_type ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); }
+value_type ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); }
+value_type ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); }
+value_type ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); }
+value_type ParserInt::Not(value_type v) { return !Round(v); }
+
+//---------------------------------------------------------------------------
+// Unary operator Callbacks: Infix operators
+value_type ParserInt::UnaryMinus(value_type v)
+{
+ return -Round(v);
+}
+
+//---------------------------------------------------------------------------
+value_type ParserInt::Sum(const value_type* a_afArg, int a_iArgc)
+{
+ if (!a_iArgc)
+ throw ParserError(_T("too few arguments for function sum."));
+
+ value_type fRes=0;
+ for (int i=0; i<a_iArgc; ++i)
+ fRes += a_afArg[i];
+
+ return fRes;
+}
+
+//---------------------------------------------------------------------------
+value_type ParserInt::Min(const value_type* a_afArg, int a_iArgc)
+{
+ if (!a_iArgc)
+ throw ParserError( _T("too few arguments for function min.") );
+
+ value_type fRes=a_afArg[0];
+ for (int i=0; i<a_iArgc; ++i)
+ fRes = std::min(fRes, a_afArg[i]);
+
+ return fRes;
+}
+
+//---------------------------------------------------------------------------
+value_type ParserInt::Max(const value_type* a_afArg, int a_iArgc)
+{
+ if (!a_iArgc)
+ throw ParserError(_T("too few arguments for function min."));
+
+ value_type fRes=a_afArg[0];
+ for (int i=0; i<a_iArgc; ++i)
+ fRes = std::max(fRes, a_afArg[i]);
+
+ return fRes;
+}
+
+//---------------------------------------------------------------------------
+// Default value recognition callback
+bool ParserInt::IsVal(const char_type *a_szExpr, int &a_iPos, value_type &a_fVal)
+{
+ stringstream_type stream(a_szExpr);
+ int iVal(0);
+
+ stream >> iVal;
+ int iEnd = stream.tellg(); // Position after reading
+
+ if (iEnd==-1)
+ return false;
+
+ a_iPos += iEnd;
+ a_fVal = (value_type)iVal;
+ return true;
+}
+
+//---------------------------------------------------------------------------
+bool ParserInt::IsHexVal(const char_type *a_szExpr, int &a_iPos, value_type &a_fVal)
+{
+ if (a_szExpr[0]!='$')
+ return false;
+
+ unsigned iVal(0);
+
+// New code based on streams for UNICODE compliance:
+ stringstream_type::pos_type nPos(0);
+ stringstream_type ss(a_szExpr+1);
+ ss >> std::hex >> iVal;
+ nPos = ss.tellg();
+
+ if (nPos==(stringstream_type::pos_type)0)
+ return false;
+
+ a_iPos += 1 + nPos;
+
+/*
+ // original code based on sscanf. Working but not UNICODE compliant!
+ int iLen(0);
+ if (sscanf(a_szExpr+1, "%x%n", &iVal, &iLen)==0)
+ return false;
+
+ a_iPos += iLen+1;
+*/
+
+ a_fVal = iVal;
+ return true;
+}
+
+//---------------------------------------------------------------------------
+bool ParserInt::IsBinVal(const char_type *a_szExpr, int &a_iPos, value_type &a_fVal)
+{
+ if (a_szExpr[0]!='#')
+ return false;
+
+ unsigned iVal(0),
+ iBits(sizeof(iVal)*8),
+ i(0);
+
+ for (i=0; (a_szExpr[i+1]=='0' || a_szExpr[i+1]=='1') && i<iBits; ++i)
+ iVal |= (int)(a_szExpr[i+1]=='1') << ((iBits-1)-i);
+
+ if (i==0)
+ return false;
+
+ if (i==iBits)
+ throw exception_type(_T("Binary to integer conversion error (overflow)."));
+
+ a_fVal = (unsigned)(iVal >> (iBits-i) );
+ a_iPos += i+1;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+/** \brief Constructor.
+
+ Call ParserBase class constructor and trigger Function, Operator and Constant initialization.
+*/
+ParserInt::ParserInt()
+:ParserBase()
+{
+ AddValIdent(IsVal);
+ AddValIdent(IsHexVal);
+ AddValIdent(IsBinVal);
+
+ InitCharSets();
+ InitFun();
+ InitOprt();
+}
+
+//---------------------------------------------------------------------------
+void ParserInt::InitConst()
+{
+}
+
+//---------------------------------------------------------------------------
+void ParserInt::InitCharSets()
+{
+ DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") );
+ DefineOprtChars( _T("+-*^/?<>=!%&|~'_") );
+ DefineInfixOprtChars( _T("/+-*^?<>=!%&|~'_") );
+}
+
+//---------------------------------------------------------------------------
+/** \brief Initialize the default functions. */
+void ParserInt::InitFun()
+{
+ DefineFun( _T("sign"), Sign);
+ DefineFun( _T("abs"), Abs);
+ DefineFun( _T("if"), Ite);
+ DefineFun( _T("sum"), Sum);
+ DefineFun( _T("min"), Min);
+ DefineFun( _T("max"), Max);
+}
+
+//---------------------------------------------------------------------------
+/** \brief Initialize operators. */
+void ParserInt::InitOprt()
+{
+ // disable all built in operators, not all of them usefull for integer numbers
+ // (they don't do rounding of values)
+ EnableBuiltInOprt(false);
+
+ // Disable all built in operators, they wont work with integer numbers
+ // since they are designed for floating point numbers
+ DefineInfixOprt( _T("-"), UnaryMinus);
+ DefineInfixOprt( _T("!"), Not);
+
+ DefineOprt( _T("&"), LogAnd, prLOGIC);
+ DefineOprt( _T("|"), LogOr, prLOGIC);
+ DefineOprt( _T("^"), LogXor, prLOGIC);
+ DefineOprt( _T("&&"), And, prLOGIC);
+ DefineOprt( _T("||"), Or, prLOGIC);
+
+ DefineOprt( _T("<"), Less, prCMP);
+ DefineOprt( _T(">"), Greater, prCMP);
+ DefineOprt( _T("<="), LessEq, prCMP);
+ DefineOprt( _T(">="), GreaterEq, prCMP);
+ DefineOprt( _T("=="), Equal, prCMP);
+ DefineOprt( _T("!="), NotEqual, prCMP);
+
+ DefineOprt( _T("+"), Add, prADD_SUB);
+ DefineOprt( _T("-"), Sub, prADD_SUB);
+
+ DefineOprt( _T("*"), Mul, prMUL_DIV);
+ DefineOprt( _T("/"), Div, prMUL_DIV);
+ DefineOprt( _T("%"), Mod, prMUL_DIV);
+
+ DefineOprt( _T(">>"), Shr, prMUL_DIV+1);
+ DefineOprt( _T("<<"), Shl, prMUL_DIV+1);
+}
+
+} // namespace mu
diff --git a/muparser/muParserInt.h b/muparser/muParserInt.h
new file mode 100644
index 0000000..008792d
--- /dev/null
+++ b/muparser/muParserInt.h
@@ -0,0 +1,93 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MU_PARSER_INT_H
+#define MU_PARSER_INT_H
+
+#include "muParserBase.h"
+#include <vector>
+
+
+namespace mu
+{
+
+/** \brief Mathematical expressions parser.
+
+ This version of the parser handles only integer numbers. It disables the built in operators thus it is
+ slower than muParser. Integer values are stored in the double value_type and converted if needed.
+*/
+class ParserInt : public ParserBase
+{
+private:
+ static int Round(value_type v) { return (int)(v + ((v>=0) ? 0.5 : -0.5) ); };
+
+ static value_type Abs(value_type);
+ static value_type Sign(value_type);
+ static value_type Ite(value_type, value_type, value_type);
+ // !! The unary Minus is a MUST, otherwise you cant use negative signs !!
+ static value_type UnaryMinus(value_type);
+ // Functions with variable number of arguments
+ static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum
+ static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum
+ static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum
+ // binary operator callbacks
+ static value_type Add(value_type v1, value_type v2);
+ static value_type Sub(value_type v1, value_type v2);
+ static value_type Mul(value_type v1, value_type v2);
+ static value_type Div(value_type v1, value_type v2);
+ static value_type Mod(value_type v1, value_type v2);
+ static value_type Shr(value_type v1, value_type v2);
+ static value_type Shl(value_type v1, value_type v2);
+ static value_type LogAnd(value_type v1, value_type v2);
+ static value_type LogOr(value_type v1, value_type v2);
+ static value_type LogXor(value_type v1, value_type v2);
+ static value_type And(value_type v1, value_type v2);
+ static value_type Or(value_type v1, value_type v2);
+ static value_type Xor(value_type v1, value_type v2);
+ static value_type Less(value_type v1, value_type v2);
+ static value_type Greater(value_type v1, value_type v2);
+ static value_type LessEq(value_type v1, value_type v2);
+ static value_type GreaterEq(value_type v1, value_type v2);
+ static value_type Equal(value_type v1, value_type v2);
+ static value_type NotEqual(value_type v1, value_type v2);
+ static value_type Not(value_type v1);
+
+ static bool IsHexVal(const char_type *a_szExpr, int &a_iPos, value_type &a_iVal);
+ static bool IsBinVal(const char_type *a_szExpr, int &a_iPos, value_type &a_iVal);
+ static bool IsVal(const char_type *a_szExpr, int &a_iPos, value_type &a_iVal);
+
+public:
+ ParserInt();
+
+ virtual void InitFun();
+ virtual void InitOprt();
+ virtual void InitConst();
+ virtual void InitCharSets();
+};
+
+} // namespace mu
+
+#endif
+
diff --git a/muparser/muParserStack.h b/muparser/muParserStack.h
new file mode 100644
index 0000000..e035582
--- /dev/null
+++ b/muparser/muParserStack.h
@@ -0,0 +1,120 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MU_PARSER_STACK_H
+#define MU_PARSER_STACK_H
+
+#include <cassert>
+#include <string>
+#include <stack>
+#include <vector>
+
+#include "muParserError.h"
+#include "muParserToken.h"
+
+
+namespace mu
+{
+
+ /** \brief Parser stack implementation.
+
+ Stack implementation based on a std::stack. The behaviour of pop() had been
+ slightly changed in order to get an error code if the stack is empty.
+ The stack is used within the Parser both as a value stack and as an operator stack.
+
+ \author (C) 2004, 2005 Ingo Berg
+ */
+ template <typename TValueType>
+ class ParserStack
+ {
+ private:
+ /** \brief Type of the underlying stack implementation. */
+ typedef std::stack<TValueType, std::vector<TValueType> > impl_type;
+ impl_type m_Stack;
+
+ public:
+
+ //---------------------------------------------------------------------------
+ ParserStack()
+ :m_Stack()
+ {}
+
+ //---------------------------------------------------------------------------
+ virtual ~ParserStack()
+ {}
+
+ //---------------------------------------------------------------------------
+ /** \brief Pop a value from the stack.
+
+ Unlike the standard implementation this function will return the value that
+ is going to be taken from the stack.
+
+ \throw ParserException in case the stack is empty.
+ \sa pop(int &a_iErrc)
+ */
+ TValueType pop()
+ {
+ if (empty())
+ throw ParserError( _T("stack is empty.") );
+
+ TValueType el = top();
+ m_Stack.pop();
+ return el;
+ }
+
+ /** \brief Push an object into the stack.
+
+ \param a_Val object to push into the stack.
+ \throw nothrow
+ */
+ void push(const TValueType& a_Val)
+ {
+ m_Stack.push(a_Val);
+ }
+
+ /** \brief Return the number of stored elements. */
+ unsigned size() const
+ {
+ return (unsigned)m_Stack.size();
+ }
+
+ /** \brief Returns true if stack is empty false otherwise. */
+ bool empty() const
+ {
+ return m_Stack.size()==0;
+ }
+
+ /** \brief Return reference to the top object in the stack.
+
+ The top object is the one pushed most recently.
+ */
+ TValueType& top()
+ {
+ return m_Stack.top();
+ }
+ };
+} // namespace MathUtils
+
+#endif
diff --git a/muparser/muParserTest.cpp b/muparser/muParserTest.cpp
new file mode 100644
index 0000000..eed6cc4
--- /dev/null
+++ b/muparser/muParserTest.cpp
@@ -0,0 +1,1125 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "muParserTest.h"
+
+#include <cstdio>
+#include <cmath>
+#include <iostream>
+
+#define PARSER_CONST_PI 3.141592653589793238462643
+#define PARSER_CONST_E 2.718281828459045235360287
+
+using namespace std;
+
+
+namespace mu
+{
+ namespace Test
+ {
+ int ParserTester::c_iCount = 0;
+
+ //---------------------------------------------------------------------------
+ ParserTester::ParserTester()
+ :m_vTestFun()
+ {
+ AddTest(&ParserTester::TestNames);
+ AddTest(&ParserTester::TestSyntax);
+ AddTest(&ParserTester::TestPostFix);
+ AddTest(&ParserTester::TestInfixOprt);
+ AddTest(&ParserTester::TestVarConst);
+ AddTest(&ParserTester::TestVolatile);
+ AddTest(&ParserTester::TestMultiArg);
+ AddTest(&ParserTester::TestFormula);
+ AddTest(&ParserTester::TestInterface);
+ AddTest(&ParserTester::TestBinOprt);
+ AddTest(&ParserTester::TestException);
+ AddTest(&ParserTester::TestStrArg);
+
+ ParserTester::c_iCount = 0;
+ }
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestInterface()
+ {
+ int iStat = 0;
+ mu::console() << _T("testing member functions...");
+
+ // Test RemoveVar
+ value_type afVal[3] = {1,2,3};
+ Parser p;
+
+ try
+ {
+ p.DefineVar( _T("a"), &afVal[0]);
+ p.DefineVar( _T("b"), &afVal[1]);
+ p.DefineVar( _T("c"), &afVal[2]);
+ p.SetExpr( _T("a+b+c") );
+ p.Eval();
+ }
+ catch(...)
+ {
+ iStat += 1; // this is not supposed to happen
+ }
+
+ try
+ {
+ p.RemoveVar( _T("c") );
+ p.Eval();
+ iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted...
+ }
+ catch(...)
+ {
+ // failure is expected...
+ }
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestStrArg()
+ {
+ int iStat = 0;
+ mu::console() << _T("testing string arguments...");
+
+ iStat += EqnTest(_T("valueof(\"aaa\")+valueof(\"bbb\") "), 246, true);
+ iStat += EqnTest(_T("2*(valueof(\"aaa\")-23)+valueof(\"bbb\")"), 323, true);
+ // use in expressions with variables
+ iStat += EqnTest(_T("a*(atof(\"10\")-b)"), 8, true);
+ iStat += EqnTest(_T("a-(atof(\"10\")*b)"), -19, true);
+ // string + numeric arguments
+ iStat += EqnTest(_T("strfun1(\"100\")"), 100, true);
+ iStat += EqnTest(_T("strfun2(\"100\",1)"), 101, true);
+ iStat += EqnTest(_T("strfun3(\"99\",1,2)"), 102, true);
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestBinOprt()
+ {
+ int iStat = 0;
+ mu::console() << _T("testing binary operators...");
+
+ // built in operators
+ // xor operator
+ iStat += EqnTest(_T("1 xor 2"), 3, true);
+ iStat += EqnTest(_T("a xor b"), 3, true); // with a=1 and b=2
+ iStat += EqnTest(_T("1 xor 2 xor 3"), 0, true);
+ iStat += EqnTest(_T("a xor b xor 3"), 0, true); // with a=1 and b=2
+ iStat += EqnTest(_T("a xor b xor c"), 0, true); // with a=1 and b=2
+ iStat += EqnTest(_T("(1 xor 2) xor 3"), 0, true);
+ iStat += EqnTest(_T("(a xor b) xor c"), 0, true); // with a=1 and b=2
+ iStat += EqnTest(_T("(a) xor (b) xor c"), 0, true); // with a=1 and b=2
+ iStat += EqnTest(_T("1 or 2"), 3, true);
+ iStat += EqnTest(_T("a or b"), 3, true); // with a=1 and b=2
+
+ // Assignement operator
+ iStat += EqnTest(_T("a = b"), 2, true);
+ iStat += EqnTest(_T("a = sin(b)"), 0.909297, true);
+ iStat += EqnTest(_T("a = 1+sin(b)"), 1.909297, true);
+
+ // Test user defined binary operators
+ iStat += EqnTestInt(_T("1 | 2"), 3, true);
+ iStat += EqnTestInt(_T("1 || 2"), 1, true);
+ iStat += EqnTestInt(_T("123 & 456"), 72, true);
+ iStat += EqnTestInt(_T("(123 & 456) % 10"), 2, true);
+ iStat += EqnTestInt(_T("1 && 0"), 0, true);
+ iStat += EqnTestInt(_T("123 && 456"), 1, true);
+ iStat += EqnTestInt(_T("1 << 3"), 8, true);
+ iStat += EqnTestInt(_T("8 >> 3"), 1, true);
+ iStat += EqnTestInt(_T("10 ^ 10"), 0, true);
+ iStat += EqnTestInt(_T("10 * 10 ^ 99"), 7, true);
+ iStat += EqnTestInt(_T("9 / 4"), 2, true);
+ iStat += EqnTestInt(_T("9 % 4"), 1, true);
+ iStat += EqnTestInt(_T("if(5%2,1,0)"), 1, true);
+ iStat += EqnTestInt(_T("if(4%2,1,0)"), 0, true);
+ iStat += EqnTestInt(_T("-10+1"), -9, true);
+ iStat += EqnTestInt(_T("1+2*3"), 7, true);
+ iStat += EqnTestInt(_T("const1 != const2"), 1, true);
+ iStat += EqnTestInt(_T("const1 != const2"), 0, false);
+ iStat += EqnTestInt(_T("const1 == const2"), 0, true);
+ iStat += EqnTestInt(_T("const1 == 1"), 1, true);
+ iStat += EqnTestInt(_T("10*(const1 == 1)"), 10, true);
+ iStat += EqnTestInt(_T("2*(const1 | const2)"), 6, true);
+ iStat += EqnTestInt(_T("2*(const1 | const2)"), 7, false);
+ iStat += EqnTestInt(_T("const1 < const2"), 1, true);
+ iStat += EqnTestInt(_T("const2 > const1"), 1, true);
+ iStat += EqnTestInt(_T("const1 <= 1"), 1, true);
+ iStat += EqnTestInt(_T("const2 >= 2"), 1, true);
+ iStat += EqnTestInt(_T("2*(const1 + const2)"), 6, true);
+ iStat += EqnTestInt(_T("2*(const1 - const2)"), -2, true);
+
+ iStat += EqnTestInt(_T("a != b"), 1, true);
+ iStat += EqnTestInt(_T("a != b"), 0, false);
+ iStat += EqnTestInt(_T("a == b"), 0, true);
+ iStat += EqnTestInt(_T("a == 1"), 1, true);
+ iStat += EqnTestInt(_T("10*(a == 1)"), 10, true);
+ iStat += EqnTestInt(_T("2*(a | b)"), 6, true);
+ iStat += EqnTestInt(_T("2*(a | b)"), 7, false);
+ iStat += EqnTestInt(_T("a < b"), 1, true);
+ iStat += EqnTestInt(_T("b > a"), 1, true);
+ iStat += EqnTestInt(_T("a <= 1"), 1, true);
+ iStat += EqnTestInt(_T("b >= 2"), 1, true);
+ iStat += EqnTestInt(_T("2*(a + b)"), 6, true);
+ iStat += EqnTestInt(_T("2*(a - b)"), -2, true);
+ iStat += EqnTestInt(_T("a + (a << b)"), 5, true);
+ iStat += EqnTestInt(_T("-2^2"), -4, true);
+// incorrect: '^' is yor here, not power
+// iStat += EqnTestInt("-(1+2)^2", -9, true);
+// iStat += EqnTestInt("-1^3", -1, true);
+
+ // Test precedence
+ // a=1, b=2, c=3
+ iStat += EqnTestInt(_T("a + b * c"), 7, true);
+ iStat += EqnTestInt(_T("a * b + c"), 5, true);
+ iStat += EqnTestInt(_T("a<b && b>10"), 0, true);
+ iStat += EqnTestInt(_T("a<b && b<10"), 1, true);
+
+ iStat += EqnTestInt(_T("a + b << c"), 17, true);
+ iStat += EqnTestInt(_T("a << b + c"), 7, true);
+ iStat += EqnTestInt(_T("c * b < a"), 0, true);
+ iStat += EqnTestInt(_T("c * b == 6 * a"), 1, true);
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check muParser name restriction enforcement. */
+ int ParserTester::TestNames()
+ {
+ int iStat= 0,
+ iErr = 0;
+
+ mu::console() << "testing name restriction enforcement...";
+
+ Parser p;
+
+ #define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG) \
+ iErr = 0; \
+ ParserTester::c_iCount++; \
+ try \
+ { \
+ p.Define##DOMAIN(EXPR, ARG); \
+ } \
+ catch(Parser::exception_type&) \
+ { \
+ iErr = (FAIL==false) ? 0 : 1; \
+ } \
+ iStat += iErr;
+
+ // constant names
+ PARSER_THROWCHECK(Const, false, _T("0a"), 1)
+ PARSER_THROWCHECK(Const, false, _T("9a"), 1)
+ PARSER_THROWCHECK(Const, false, _T("+a"), 1)
+ PARSER_THROWCHECK(Const, false, _T("-a"), 1)
+ PARSER_THROWCHECK(Const, false, _T("a-"), 1)
+ PARSER_THROWCHECK(Const, false, _T("a*"), 1)
+ PARSER_THROWCHECK(Const, false, _T("a?"), 1)
+ PARSER_THROWCHECK(Const, true, _T("a"), 1)
+ PARSER_THROWCHECK(Const, true, _T("a_min"), 1)
+ PARSER_THROWCHECK(Const, true, _T("a_min0"), 1)
+ PARSER_THROWCHECK(Const, true, _T("a_min9"), 1)
+ // variable names
+ value_type a;
+ p.ClearConst();
+ PARSER_THROWCHECK(Var, false, _T("123abc"), &a)
+ PARSER_THROWCHECK(Var, false, _T("9a"), &a)
+ PARSER_THROWCHECK(Var, false, _T("0a"), &a)
+ PARSER_THROWCHECK(Var, false, _T("+a"), &a)
+ PARSER_THROWCHECK(Var, false, _T("-a"), &a)
+ PARSER_THROWCHECK(Var, false, _T("?a"), &a)
+ PARSER_THROWCHECK(Var, false, _T("!a"), &a)
+ PARSER_THROWCHECK(Var, false, _T("a+"), &a)
+ PARSER_THROWCHECK(Var, false, _T("a-"), &a)
+ PARSER_THROWCHECK(Var, false, _T("a*"), &a)
+ PARSER_THROWCHECK(Var, false, _T("a?"), &a)
+ PARSER_THROWCHECK(Var, true, _T("a"), &a)
+ PARSER_THROWCHECK(Var, true, _T("a_min"), &a)
+ PARSER_THROWCHECK(Var, true, _T("a_min0"), &a)
+ PARSER_THROWCHECK(Var, true, _T("a_min9"), &a)
+ PARSER_THROWCHECK(Var, false, _T("a_min9"), 0)
+ // Postfix operators
+ // fail
+ PARSER_THROWCHECK(PostfixOprt, false, _T("(k"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, false, _T("9+"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, false, _T("+"), 0)
+ // pass
+ PARSER_THROWCHECK(PostfixOprt, true, _T("-a"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("?a"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("_"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("#"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("&&"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("||"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("&"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("|"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("++"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("--"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("?>"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("?<"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("**"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("xor"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("and"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("or"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("not"), f1of1)
+ PARSER_THROWCHECK(PostfixOprt, true, _T("!"), f1of1)
+ // Binary operator
+ // The following must fail with builtin operators activated
+ // p.EnableBuiltInOp(true); -> this is the default
+ PARSER_THROWCHECK(Oprt, false, _T("+"), f1of2)
+ PARSER_THROWCHECK(Oprt, false, _T("-"), f1of2)
+ PARSER_THROWCHECK(Oprt, false, _T("*"), f1of2)
+ PARSER_THROWCHECK(Oprt, false, _T("/"), f1of2)
+ // without activated built in operators it should work
+ p.EnableBuiltInOprt(false);
+ PARSER_THROWCHECK(Oprt, true, _T("+"), f1of2)
+ PARSER_THROWCHECK(Oprt, true, _T("-"), f1of2)
+ PARSER_THROWCHECK(Oprt, true, _T("*"), f1of2)
+ PARSER_THROWCHECK(Oprt, true, _T("/"), f1of2)
+ #undef PARSER_THROWCHECK
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestSyntax()
+ {
+ int iStat = 0;
+ mu::console() << _T("testing syntax engine...");
+
+ iStat += EqnTest(_T("(1+ 2*a)"), 3, true); // Spaces within formula
+ iStat += EqnTest(_T("(2+"), 0, false); // missing closing bracket
+ iStat += EqnTest(_T("2++4"), 0, false); // unexpected operator
+ iStat += EqnTest(_T("2+-4"), 0, false); // unexpected operator
+ iStat += EqnTest(_T("(2+)"), 0, false); // unexpected closing bracket
+ iStat += EqnTest(_T("--2"), 0, false); // double sign
+ iStat += EqnTest(_T("ksdfj"), 0, false); // unknown token
+ iStat += EqnTest(_T("()"), 0, false); // empty bracket
+ iStat += EqnTest(_T("sin(cos)"), 0, false); // unexpected function
+ iStat += EqnTest(_T("5t6"), 0, false); // unknown token
+ iStat += EqnTest(_T("5 t 6"), 0, false); // unknown token
+ iStat += EqnTest(_T("8*"), 0, false); // unexpected end of formula
+ iStat += EqnTest(_T(",3"), 0, false); // unexpected comma
+ iStat += EqnTest(_T("3,5"), 0, false); // unexpected comma
+ iStat += EqnTest(_T("sin(8,8)"), 0, false); // too many function args
+ iStat += EqnTest(_T("(7,8)"), 0, false); // too many function args
+ iStat += EqnTest(_T("sin)"), 0, false); // unexpected closing bracket
+ iStat += EqnTest(_T("a)"), 0, false); // unexpected closing bracket
+ iStat += EqnTest(_T("pi)"), 0, false); // unexpected closing bracket
+ iStat += EqnTest(_T("sin(())"), 0, false); // unexpected closing bracket
+ iStat += EqnTest(_T("sin()"), 0, false); // unexpected closing bracket
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestVarConst()
+ {
+ int iStat = 0;
+ mu::console() << _T("testing variable/constant name recognition...");
+
+ // distinguish constants with same basename
+ iStat += EqnTest( _T("const"), 1, true);
+ iStat += EqnTest( _T("const1"), 2, true);
+ iStat += EqnTest( _T("const2"), 3, true);
+ iStat += EqnTest( _T("2*const"), 2, true);
+ iStat += EqnTest( _T("2*const1"), 4, true);
+ iStat += EqnTest( _T("2*const2"), 6, true);
+ iStat += EqnTest( _T("2*const+1"), 3, true);
+ iStat += EqnTest( _T("2*const1+1"), 5, true);
+ iStat += EqnTest( _T("2*const2+1"), 7, true);
+ iStat += EqnTest( _T("const"), 0, false);
+ iStat += EqnTest( _T("const1"), 0, false);
+ iStat += EqnTest( _T("const2"), 0, false);
+
+ // distinguish variables with same basename
+ iStat += EqnTest( _T("a"), 1, true);
+ iStat += EqnTest( _T("aa"), 2, true);
+ iStat += EqnTest( _T("2*a"), 2, true);
+ iStat += EqnTest( _T("2*aa"), 4, true);
+ iStat += EqnTest( _T("2*a-1"), 1, true);
+ iStat += EqnTest( _T("2*aa-1"), 3, true);
+
+ // Finally test querying of used variables
+ try
+ {
+ int idx;
+ mu::Parser p;
+ mu::value_type vVarVal[] = { 1, 2, 3, 4, 5};
+ p.DefineVar( _T("a"), &vVarVal[0]);
+ p.DefineVar( _T("b"), &vVarVal[1]);
+ p.DefineVar( _T("c"), &vVarVal[2]);
+ p.DefineVar( _T("d"), &vVarVal[3]);
+ p.DefineVar( _T("e"), &vVarVal[4]);
+
+ // Test lookup of defined variables
+ // 4 used variables
+ p.SetExpr( _T("a+b+c+d") );
+ mu::varmap_type UsedVar = p.GetUsedVar();
+ int iCount = (int)UsedVar.size();
+ if (iCount!=4) throw false;
+
+ mu::varmap_type::const_iterator item = UsedVar.begin();
+ for (idx=0; item!=UsedVar.end(); ++item)
+ {
+ if (&vVarVal[idx++]!=item->second)
+ throw false;
+ }
+
+ // Test lookup of undefined variables
+ p.SetExpr( _T("undef1+undef2+undef3") );
+ UsedVar = p.GetUsedVar();
+ iCount = (int)UsedVar.size();
+ if (iCount!=3) throw false;
+
+ for (item = UsedVar.begin(); item!=UsedVar.end(); ++item)
+ {
+ if (item->second!=0)
+ throw false; // all pointers to undefined variables must be null
+ }
+
+ // 1 used variables
+ p.SetExpr( _T("a+b") );
+ UsedVar = p.GetUsedVar();
+ iCount = (int)UsedVar.size();
+ if (iCount!=2) throw false;
+ item = UsedVar.begin();
+ for (idx=0; item!=UsedVar.end(); ++item)
+ if (&vVarVal[idx++]!=item->second) throw false;
+
+ }
+ catch(...)
+ {
+ iStat += 1;
+ }
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestMultiArg()
+ {
+ int iStat = 0;
+ mu::console() << _T("testing multiarg functions...");
+
+ // picking the right argument
+ iStat += EqnTest( _T("f1of1(1)"), 1, true);
+ iStat += EqnTest( _T("f1of2(1, 2)"), 1, true);
+ iStat += EqnTest( _T("f2of2(1, 2)"), 2, true);
+ iStat += EqnTest( _T("f1of3(1, 2, 3)"), 1, true);
+ iStat += EqnTest( _T("f2of3(1, 2, 3)"), 2, true);
+ iStat += EqnTest( _T("f3of3(1, 2, 3)"), 3, true);
+ iStat += EqnTest( _T("f1of4(1, 2, 3, 4)"), 1, true);
+ iStat += EqnTest( _T("f2of4(1, 2, 3, 4)"), 2, true);
+ iStat += EqnTest( _T("f3of4(1, 2, 3, 4)"), 3, true);
+ iStat += EqnTest( _T("f4of4(1, 2, 3, 4)"), 4, true);
+ iStat += EqnTest( _T("f1of5(1, 2, 3, 4, 5)"), 1, true);
+ iStat += EqnTest( _T("f2of5(1, 2, 3, 4, 5)"), 2, true);
+ iStat += EqnTest( _T("f3of5(1, 2, 3, 4, 5)"), 3, true);
+ iStat += EqnTest( _T("f4of5(1, 2, 3, 4, 5)"), 4, true);
+ iStat += EqnTest( _T("f5of5(1, 2, 3, 4, 5)"), 5, true);
+ // Too few arguments / Too many arguments
+ iStat += EqnTest( _T("f1of1(1,2)"), 0, false);
+ iStat += EqnTest( _T("f1of1()"), 0, false);
+ iStat += EqnTest( _T("f1of2(1, 2, 3)"), 0, false);
+ iStat += EqnTest( _T("f1of2(1)"), 0, false);
+ iStat += EqnTest( _T("f1of3(1, 2, 3, 4)"), 0, false);
+ iStat += EqnTest( _T("f1of3(1)"), 0, false);
+ iStat += EqnTest( _T("f1of4(1, 2, 3, 4, 5)"), 0, false);
+ iStat += EqnTest( _T("f1of4(1)"), 0, false);
+ iStat += EqnTest( _T("(1,2,3)"), 0, false);
+ iStat += EqnTest( _T("1,2,3"), 0, false);
+ iStat += EqnTest( _T("(1*a,2,3)"), 0, false);
+ iStat += EqnTest( _T("1,2*a,3"), 0, false);
+
+ // correct calculation of arguments
+ iStat += EqnTest( _T("min(a, 1)"), 1, true);
+ iStat += EqnTest( _T("min(3*2, 1)"), 1, true);
+ iStat += EqnTest( _T("min(3*2, 1)"), 6, false);
+ // correct calculation of arguments
+ iStat += EqnTest( _T("min(3*a+1, 1)"), 1, true);
+ iStat += EqnTest( _T("max(3*a+1, 1)"), 4, true);
+ iStat += EqnTest( _T("max(3*a+1, 1)*2"), 8, true);
+ iStat += EqnTest( _T("2*max(3*a+1, 1)+2"), 10, true);
+
+ // functions with Variable argument count
+ iStat += EqnTest( _T("sum(1,2,3)"), 6, true);
+ iStat += EqnTest( _T("2*sum(1,2,3)"), 12, true);
+ iStat += EqnTest( _T("2*sum(1,2,3)+2"), 14, true);
+ iStat += EqnTest( _T("2*sum(-1,2,3)+2"), 10, true);
+ iStat += EqnTest( _T("2*sum(-1,2,-(-a))+2"), 6, true);
+ iStat += EqnTest( _T("2*sum(-1,10,-a)+2"), 18, true);
+ iStat += EqnTest( _T("2*sum(1,2,3)*2"), 24, true);
+ iStat += EqnTest( _T("sum(1,-max(1,2),3)*2"), 4, true);
+ iStat += EqnTest( _T("sum(1*3, 4, a+2)"), 10, true);
+ iStat += EqnTest( _T("sum(1*3, 2*sum(1,2,2), a+2)"), 16, true);
+ iStat += EqnTest( _T("sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)"), 24, true);
+
+ // some failures
+ iStat += EqnTest( _T("sum()"), 0, false);
+ iStat += EqnTest( _T("sum(,)"), 0, false);
+ iStat += EqnTest( _T("sum(1,2,)"), 0, false);
+ iStat += EqnTest( _T("sum(,1,2)"), 0, false);
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestInfixOprt()
+ {
+ int iStat = 0;
+ mu::console() << "testing infix operators...";
+
+ iStat += EqnTest( _T("-1"), -1, true);
+ iStat += EqnTest( _T("-(-1)"), 1, true);
+ iStat += EqnTest( _T("-(-1)*2"), 2, true);
+ iStat += EqnTest( _T("-(-2)*sqrt(4)"), 4, true);
+ iStat += EqnTest( _T("-a"), -1, true);
+ iStat += EqnTest( _T("-(a)"), -1, true);
+ iStat += EqnTest( _T("-(-a)"), 1, true);
+ iStat += EqnTest( _T("-(-a)*2"), 2, true);
+ iStat += EqnTest( _T("-(8)"), -8, true);
+ iStat += EqnTest( _T("-8"), -8, true);
+ iStat += EqnTest( _T("-(2+1)"), -3, true);
+ iStat += EqnTest( _T("-(f1of1(1+2*3)+1*2)"), -9, true);
+ iStat += EqnTest( _T("-(-f1of1(1+2*3)+1*2)"), 5, true);
+ iStat += EqnTest( _T("-sin(8)"), -0.989358, true);
+ iStat += EqnTest( _T("3-(-a)"), 4, true);
+ iStat += EqnTest( _T("3--a"), 4, true);
+
+ // Postfix / infix priorities
+ iStat += EqnTest( _T("~2#"), 8, true);
+ iStat += EqnTest( _T("~f1of1(2)#"), 8, true);
+ iStat += EqnTest( _T("~(b)#"), 8, true);
+ iStat += EqnTest( _T("(~b)#"), 12, true);
+ iStat += EqnTest( _T("~(2#)"), 8, true);
+ iStat += EqnTest( _T("~(f1of1(2)#)"), 8, true);
+ //
+ iStat += EqnTest( _T("-2^2"),-4, true);
+ iStat += EqnTest( _T("-(a+b)^2"),-9, true);
+ iStat += EqnTest( _T("(-3)^2"),9, true);
+ iStat += EqnTest( _T("-(-2^2)"),4, true);
+ iStat += EqnTest( _T("3+-3^2"),-6, true);
+ // The following assumes use of sqr as postfix operator ("?") together
+ // tiwth a sign operator of low priority:
+ iStat += EqnTest( _T("-2?"), -4, true);
+ iStat += EqnTest( _T("-(1+1)?"),-4, true);
+ iStat += EqnTest( _T("2+-(1+1)?"),-2, true);
+ iStat += EqnTest( _T("2+-2?"), -2, true);
+ // This is the classic behaviour of the infix sign operator (here: "$") which is
+ // now deprecated:
+ iStat += EqnTest( _T("$2^2"),4, true);
+ iStat += EqnTest( _T("$(a+b)^2"),9, true);
+ iStat += EqnTest( _T("($3)^2"),9, true);
+ iStat += EqnTest( _T("$($2^2)"),-4, true);
+ iStat += EqnTest( _T("3+$3^2"),12, true);
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestPostFix()
+ {
+ int iStat = 0;
+ mu::console() << _T("testing postfix operators...");
+
+ // application
+ iStat += EqnTest( _T("3m+5"), 5.003, true);
+ iStat += EqnTest( _T("1000m"), 1, true);
+ iStat += EqnTest( _T("1000 m"), 1, true);
+ iStat += EqnTest( _T("(a)m"), 1e-3, true);
+ iStat += EqnTest( _T("-(a)m"), -1e-3, true);
+ iStat += EqnTest( _T("-2m"), -2e-3, true);
+ iStat += EqnTest( _T("f1of1(1000)m"), 1, true);
+ iStat += EqnTest( _T("-f1of1(1000)m"), -1, true);
+ iStat += EqnTest( _T("-f1of1(-1000)m"), 1, true);
+ iStat += EqnTest( _T("f4of4(0,0,0,1000)m"), 1, true);
+ iStat += EqnTest( _T("2+(a*1000)m"), 3, true);
+ // some incorrect results
+ iStat += EqnTest( _T("1000m"), 0.1, false);
+ iStat += EqnTest( _T("(a)m"), 2, false);
+ // failure due to syntax checking
+ iStat += EqnTest( _T("a m"), 0, false);
+ iStat += EqnTest( _T("4 + m"), 0, false);
+ iStat += EqnTest( _T("m4"), 0, false);
+ iStat += EqnTest( _T("sin(m)"), 0, false);
+ iStat += EqnTest( _T("m m"), 0, false);
+ iStat += EqnTest( _T("m(8)"), 0, false);
+ iStat += EqnTest( _T("4,m"), 0, false);
+ iStat += EqnTest( _T("-m"), 0, false);
+ iStat += EqnTest( _T("2(-m)"), 0, false);
+ iStat += EqnTest( _T("2(m)"), 0, false);
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Test volatile (nonoptimizeable functions). */
+ int ParserTester::TestVolatile()
+ {
+ int iStat = 0;
+ mu::console() << "testing volatile/nonvolatile functions...";
+
+ // First test with volatile flag turned on
+ try
+ {
+ mu::Parser p;
+ p.DefineFun( _T("rnd"), Rnd, false);
+ p.DefineFun( _T("valueof"), RndWithString, false);
+
+ // 1st test, compare results from sucessive calculations
+ p.SetExpr( _T("3+rnd(8)") );
+ if (p.Eval()==p.Eval()) iStat += 1;
+
+ // 2nd test, force bytecode creation, compare two results both
+ // calculated from bytecode
+ p.SetExpr( _T("3+rnd(8)") );
+ p.Eval(); //<- Force bytecode creation
+ if (p.Eval()==p.Eval()) iStat += 1;
+
+ p.SetExpr( _T("3*rnd(8)+3") );
+ p.Eval(); //<- Force bytecode creation
+ if (p.Eval()==p.Eval()) iStat += 1;
+
+ p.SetExpr( _T("10+3*sin(rnd(8))-1") );
+ p.Eval(); //<- Force bytecode creation
+ if (p.Eval()==p.Eval()) iStat += 1;
+
+ p.SetExpr( _T("3+rnd(rnd(8))*2") );
+ p.Eval(); //<- Force bytecode creation
+ if (p.Eval()==p.Eval()) iStat += 1;
+
+ p.SetExpr( _T("valueof(\"Das ist ein Test\")") );
+ p.Eval(); //<- Force bytecode creation
+ if (p.Eval()==p.Eval()) iStat += 1;
+ }
+ catch(Parser::exception_type &e)
+ {
+ mu::console() << _T("\n ") << e.GetExpr() << _T(" : ") << e.GetMsg();
+ iStat += 1;
+ }
+
+ // Second test with volatile flag turned off
+ try
+ {
+ mu::Parser p;
+ p.DefineFun( _T("rnd"), Rnd);
+ p.DefineFun( _T("valueof"), RndWithString);
+
+ // compare string parsing with bytecode
+ p.SetExpr( _T("3+rnd(8)") );
+ if (p.Eval()!=p.Eval()) iStat += 1;
+
+ p.SetExpr( _T("3+rnd(8)") );
+ p.Eval(); //<- Force bytecode creation
+ if (p.Eval()!=p.Eval()) iStat += 1;
+
+ p.SetExpr( _T("3*rnd(8)+3") );
+ p.Eval(); //<- Force bytecode creation
+ if (p.Eval()!=p.Eval()) iStat += 1;
+
+ p.SetExpr( _T("10+3*sin(rnd(8))-1") );
+ p.Eval(); //<- Force bytecode creation
+ if (p.Eval()!=p.Eval()) iStat += 1;
+
+ p.SetExpr( _T("3+rnd(rnd(8))*2") );
+ p.Eval(); //<- Force bytecode creation
+ if (p.Eval()!=p.Eval()) iStat += 1;
+ }
+ catch(Parser::exception_type &e)
+ {
+ mu::console() << _T("\n ") << e.GetExpr() << _T(" : ") << e.GetMsg();
+ iStat += 1;
+ }
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestFormula()
+ {
+ int iStat = 0;
+ mu::console() << _T("testing sample formulas...");
+
+ // operator precedencs
+ iStat += EqnTest( _T("1+2-3*4/5^6"), 2.99923, true);
+ iStat += EqnTest( _T("1^2/3*4-5+6"), 2.3333, true);
+ iStat += EqnTest( _T("1+2*3"), 7, true);
+ iStat += EqnTest( _T("1+2*3"), 7, true);
+ iStat += EqnTest( _T("(1+2)*3"), 9, true);
+ iStat += EqnTest( _T("(1+2)*(-3)"), -9, true);
+ iStat += EqnTest( _T("2/4"), 0.5, true);
+
+ iStat += EqnTest( _T("exp(ln(7))"), 7, true);
+ iStat += EqnTest( _T("e^ln(7)"), 7, true);
+ iStat += EqnTest( _T("e^(ln(7))"), 7, true);
+ iStat += EqnTest( _T("(e^(ln(7)))"), 7, true);
+ iStat += EqnTest( _T("1-(e^(ln(7)))"), -6, true);
+ iStat += EqnTest( _T("2*(e^(ln(7)))"), 14, true);
+ iStat += EqnTest( _T("10^log(5)"), 5, true);
+ iStat += EqnTest( _T("10^log10(5)"), 5, true);
+ iStat += EqnTest( _T("2^log2(4)"), 4, true);
+ iStat += EqnTest( _T("-(sin(0)+1)"), -1, true);
+ iStat += EqnTest( _T("-(2^1.1)"), -2.14354692, true);
+
+ iStat += EqnTest( _T("(cos(2.41)/b)"), -0.372056, true);
+
+#if !defined(_UNICODE)
+ // I can't translate the following two tests to unicode without loosing
+ // readability.
+
+ // long formula (Reference: Matlab)
+ iStat += EqnTest(
+ "(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))"
+ "/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/"
+ "((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-"
+ "e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6"
+ "+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e"
+ "*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)", -12.23016549, true);
+
+ // long formula (Reference: Matlab)
+ iStat += EqnTest(
+ "(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"
+ ")+a)))*2.77)", -2.16995656, true);
+#endif
+
+ // long formula (Reference: Matlab)
+ iStat += EqnTest( _T("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12"), -7995810.09926, true);
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+
+ //---------------------------------------------------------------------------
+ int ParserTester::TestException()
+ {
+ int iStat = 0;
+ mu::console() << _T("testing error codes...");
+
+ iStat += ThrowTest(_T("3+"), ecUNEXPECTED_EOF);
+ iStat += ThrowTest(_T("3+)"), ecUNEXPECTED_PARENS);
+ iStat += ThrowTest(_T("sin(3,4)"), ecTOO_MANY_PARAMS);
+ iStat += ThrowTest(_T("3,4"), ecUNEXPECTED_COMMA);
+ iStat += ThrowTest(_T("if(3)"), ecTOO_FEW_PARAMS);
+ iStat += ThrowTest(_T("(1+2"), ecMISSING_PARENS);
+ iStat += ThrowTest(_T("sin(3)3"), ecUNEXPECTED_VAL);
+ iStat += ThrowTest(_T("sin(3)xyz"), ecUNASSIGNABLE_TOKEN);
+ iStat += ThrowTest(_T("sin(3)cos(3)"), ecUNEXPECTED_FUN);
+
+ // String function related
+ iStat += ThrowTest( _T("valueof(\"xxx\")"), 999, false);
+ iStat += ThrowTest( _T("valueof()"), ecUNEXPECTED_PARENS);
+ iStat += ThrowTest( _T("1+valueof(\"abc\""), ecMISSING_PARENS);
+ iStat += ThrowTest( _T("valueof(\"abc\""), ecMISSING_PARENS);
+ iStat += ThrowTest( _T("valueof(\"abc"), ecUNTERMINATED_STRING);
+ iStat += ThrowTest( _T("valueof(\"abc\",3)"), ecTOO_MANY_PARAMS);
+ iStat += ThrowTest( _T("valueof(3)"), ecSTRING_EXPECTED);
+ iStat += ThrowTest( _T("sin(\"abc\")"), ecVAL_EXPECTED);
+ iStat += ThrowTest( _T("valueof(\"\\\"abc\\\"\")"), 999, false);
+ iStat += ThrowTest( _T("\"hello world\""), ecSTR_RESULT);
+ iStat += ThrowTest( _T("(\"hello world\")"), ecSTR_RESULT);
+ iStat += ThrowTest( _T("\"abcd\"+100"), ecOPRT_TYPE_CONFLICT);
+ iStat += ThrowTest( _T("\"a\"+\"b\""), ecOPRT_TYPE_CONFLICT);
+ iStat += ThrowTest( _T("strfun1(\"100\",3)"), ecTOO_MANY_PARAMS);
+ iStat += ThrowTest( _T("strfun2(\"100\",3,5)"), ecTOO_MANY_PARAMS);
+ iStat += ThrowTest( _T("strfun3(\"100\",3,5,6)"), ecTOO_MANY_PARAMS);
+ iStat += ThrowTest( _T("strfun2(\"100\")"), ecTOO_FEW_PARAMS);
+ iStat += ThrowTest( _T("strfun3(\"100\",6)"), ecTOO_FEW_PARAMS);
+ iStat += ThrowTest( _T("strfun2(1,1)"), ecSTRING_EXPECTED);
+ iStat += ThrowTest( _T("strfun2(a,1)"), ecSTRING_EXPECTED);
+ iStat += ThrowTest( _T("strfun2(1,1,1)"), ecTOO_MANY_PARAMS);
+ iStat += ThrowTest( _T("strfun2(a,1,1)"), ecTOO_MANY_PARAMS);
+ iStat += ThrowTest( _T("strfun3(1,2,3)"), ecSTRING_EXPECTED);
+ iStat += ThrowTest( _T("strfun3(1, \"100\",3)"), ecSTRING_EXPECTED);
+ iStat += ThrowTest( _T("strfun3(\"1\", \"100\",3)"), ecVAL_EXPECTED);
+ iStat += ThrowTest( _T("strfun3(\"1\", 3, \"100\")"), ecVAL_EXPECTED);
+ iStat += ThrowTest( _T("strfun3(\"1\", \"100\", \"100\", \"100\")"), ecTOO_MANY_PARAMS);
+
+ // assignement operator
+// iStat += ThrowTest("maxspec=0", 0, false);
+ iStat += ThrowTest( _T("3=4"), ecUNEXPECTED_OPERATOR);
+ iStat += ThrowTest( _T("sin(8)=4"), ecUNEXPECTED_OPERATOR);
+ iStat += ThrowTest( _T("\"test\"=a"), ecUNEXPECTED_OPERATOR);
+ iStat += ThrowTest( _T("sin=9"), ecUNEXPECTED_OPERATOR);
+ iStat += ThrowTest( _T("(8)=5"), ecUNEXPECTED_OPERATOR);
+ iStat += ThrowTest( _T("(a)=5"), ecUNEXPECTED_OPERATOR);
+ iStat += ThrowTest( _T("a=\"tttt\""), ecOPRT_TYPE_CONFLICT);
+
+ if (iStat==0)
+ mu::console() << _T("passed") << endl;
+ else
+ mu::console() << _T("\n failed with ") << iStat << _T(" errors") << endl;
+
+ return iStat;
+ }
+
+
+ //---------------------------------------------------------------------------
+ void ParserTester::AddTest(testfun_type a_pFun)
+ {
+ m_vTestFun.push_back(a_pFun);
+ }
+
+ //---------------------------------------------------------------------------
+ void ParserTester::Run()
+ {
+ int iStat = 0;
+ try
+ {
+ for (int i=0; i<(int)m_vTestFun.size(); ++i)
+ iStat += (this->*m_vTestFun[i])();
+ }
+ catch(Parser::exception_type &e)
+ {
+ mu::console() << "\n" << e.GetMsg() << endl;
+ mu::console() << e.GetToken() << endl;
+ Abort();
+ }
+ catch(std::exception &e)
+ {
+ mu::console() << e.what() << endl;
+ Abort();
+ }
+ catch(...)
+ {
+ mu::console() << "Internal error";
+ Abort();
+ }
+
+ if (iStat==0)
+ {
+ mu::console() << "Test passed (" << ParserTester::c_iCount << " expressions)" << endl;
+ }
+ else
+ {
+ mu::console() << "Test failed with " << iStat
+ << " errors (" << ParserTester::c_iCount
+ << " expressions)" << endl;
+ }
+ ParserTester::c_iCount = 0;
+ }
+
+
+ //---------------------------------------------------------------------------
+ int ParserTester::ThrowTest(const string_type &a_str, int a_iErrc, bool a_bFail)
+ {
+ ParserTester::c_iCount++;
+
+ try
+ {
+ double fVal=0;
+ Parser p;
+
+ p.DefineVar( _T("a"), &fVal);
+ p.DefineFun( _T("valueof"), ValueOf);
+ p.DefineFun( _T("strfun1"), StrFun1);
+ p.DefineFun( _T("strfun2"), StrFun2);
+ p.DefineFun( _T("strfun3"), StrFun3);
+ p.SetExpr(a_str);
+ p.Eval();
+ }
+ catch(Parser::exception_type &e)
+ {
+ // output the formula in case of an failed test
+ if (a_bFail==true && a_iErrc!=e.GetCode() )
+ {
+ mu::console() << _T("\n ")
+ << _T("Expression: ") << a_str
+ << _T(" Code:") << e.GetCode()
+ << _T(" Expected:") << a_iErrc;
+ }
+
+ return (a_iErrc==e.GetCode()) ? 0 : 1;
+ }
+
+ // if a_bFail==false no exception is expected
+ bool bRet((a_bFail==false) ? 0 : 1);
+ if (bRet==1)
+ {
+ mu::console() << _T("\n ")
+ << _T("Expression: ") << a_str
+ << _T(" did evaluate; Expected error:") << a_iErrc;
+ }
+
+ return bRet;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Evaluate a tet expression.
+
+ \return 1 in case of a failure, 0 otherwise.
+ */
+ int ParserTester::EqnTest(const string_type &a_str, double a_fRes, bool a_fPass)
+ {
+ ParserTester::c_iCount++;
+ int iRet(0);
+
+ try
+ {
+ Parser *p1, p2, p3; // three parser objects
+ // they will be used for testing copy and assihnment operators
+ // p1 is a pointer since i'm going to delete it in order to test if
+ // parsers after copy construction still refer to members of it.
+ // !! If this is the case this function will crash !!
+
+ p1 = new mu::Parser();
+ // Add constants
+ p1->DefineConst( _T("pi"), (value_type)PARSER_CONST_PI);
+ p1->DefineConst( _T("e"), (value_type)PARSER_CONST_E);
+ p1->DefineConst( _T("const"), 1);
+ p1->DefineConst( _T("const1"), 2);
+ p1->DefineConst( _T("const2"), 3);
+ // variables
+ value_type vVarVal[] = { 1, 2, 3, -2};
+ p1->DefineVar( _T("a"), &vVarVal[0]);
+ p1->DefineVar( _T("aa"), &vVarVal[1]);
+ p1->DefineVar( _T("b"), &vVarVal[1]);
+ p1->DefineVar( _T("c"), &vVarVal[2]);
+ p1->DefineVar( _T("d"), &vVarVal[3]);
+ // functions
+ p1->DefineFun( _T("f1of1"), f1of1); // one parameter
+ p1->DefineFun( _T("f1of2"), f1of2); // two parameter
+ p1->DefineFun( _T("f2of2"), f2of2);
+ p1->DefineFun( _T("f1of3"), f1of3); // three parameter
+ p1->DefineFun( _T("f2of3"), f2of3);
+ p1->DefineFun( _T("f3of3"), f3of3);
+ p1->DefineFun( _T("f1of4"), f1of4); // four parameter
+ p1->DefineFun( _T("f2of4"), f2of4);
+ p1->DefineFun( _T("f3of4"), f3of4);
+ p1->DefineFun( _T("f4of4"), f4of4);
+ p1->DefineFun( _T("f1of5"), f1of5); // five parameter
+ p1->DefineFun( _T("f2of5"), f2of5);
+ p1->DefineFun( _T("f3of5"), f3of5);
+ p1->DefineFun( _T("f4of5"), f4of5);
+ p1->DefineFun( _T("f5of5"), f5of5);
+ // sample functions
+ p1->DefineFun( _T("min"), Min);
+ p1->DefineFun( _T("max"), Max);
+ p1->DefineFun( _T("sum"), Sum);
+ p1->DefineFun( _T("valueof"), ValueOf);
+ p1->DefineFun( _T("atof"), StrToFloat);
+ p1->DefineFun( _T("strfun1"), StrFun1);
+ p1->DefineFun( _T("strfun2"), StrFun2);
+ p1->DefineFun( _T("strfun3"), StrFun3);
+
+ // infix / postfix operator
+ // (identifiers used here do not have any meaning or make any sense at all)
+ p1->DefineInfixOprt( _T("$"), sign, prPOW+1); // sign with high priority
+ p1->DefineInfixOprt( _T("~"), plus2); // high priority
+ p1->DefinePostfixOprt( _T("m"), Milli);
+ p1->DefinePostfixOprt( _T("#"), times3);
+ p1->DefinePostfixOprt( _T("?"), sqr); //
+ p1->SetExpr(a_str);
+
+ // Test bytecode integrity
+ // String parsing and bytecode parsing must yield the same result
+ value_type fVal[4] = {-999, -998, -997, -996}; // initially should be different
+ fVal[0] = p1->Eval(); // result from stringparsing
+ fVal[1] = p1->Eval(); // result from bytecode
+ if (fVal[0]!=fVal[1])
+ throw Parser::exception_type( _T("Bytecode corrupt.") );
+
+ // Test copy and assignement operators
+ try
+ {
+ // Test copy constructor
+ std::vector<mu::Parser> vParser;
+ vParser.push_back(*p1);
+ mu::Parser p2 = vParser[0]; // take parser from vector
+
+ // destroy the originals from p2
+ vParser.clear(); // delete the vector
+ delete p1; // delete the original
+ p1 = 0;
+
+ fVal[2] = p2.Eval();
+
+ // Test assignement operator
+ // additionally disable Optimizer this time
+ mu::Parser p3;
+ p3 = p2;
+ p3.EnableOptimizer(false);
+ fVal[3] = p3.Eval();
+ }
+ catch(std::exception &e)
+ {
+ mu::console() << _T("\n ") << e.what() << _T("\n");
+ }
+
+ // limited floating point accuracy requires the following test
+ bool bCloseEnough(true);
+ for (int i=0; i<4; ++i)
+ {
+ bCloseEnough &= (fabs(a_fRes-fVal[i]) <= fabs(fVal[i]*0.0001));
+ }
+
+ iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
+ if (iRet==1)
+ {
+ mu::console() << "\n fail: " << a_str.c_str()
+ << " (incorrect result; expected: " << a_fRes
+ << " ;calculated: " << fVal[0]<< ").";
+ }
+ }
+ catch(Parser::exception_type &e)
+ {
+ if (a_fPass)
+ {
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.GetMsg() << _T(")");
+ return 1;
+ }
+ }
+ catch(std::exception &e)
+ {
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (") << e.what() << _T(")");
+ return 1; // always return a failure since this exception is not expected
+ }
+ catch(...)
+ {
+ mu::console() << _T("\n fail: ") << a_str.c_str() << _T(" (unexpected exception)");
+ return 1; // exceptions other than ParserException are not allowed
+ }
+
+ return iRet;
+ }
+
+ //---------------------------------------------------------------------------
+ int ParserTester::EqnTestInt(const string_type &a_str, double a_fRes, bool a_fPass)
+ {
+ ParserTester::c_iCount++;
+
+ value_type vVarVal[] = {1, 2, 3}; // variable values
+ value_type fVal[2] = {-99, -999}; // results: initially should be different
+ int iRet(0);
+
+ try
+ {
+ ParserInt p;
+ p.DefineConst( _T("const1"), 1);
+ p.DefineConst( _T("const2"), 2);
+ p.DefineVar( _T("a"), &vVarVal[0]);
+ p.DefineVar( _T("b"), &vVarVal[1]);
+ p.DefineVar( _T("c"), &vVarVal[2]);
+
+ p.SetExpr(a_str);
+ fVal[0] = p.Eval(); // result from stringparsing
+ fVal[1] = p.Eval(); // result from bytecode
+
+ if (fVal[0]!=fVal[1])
+ throw Parser::exception_type( _T("Bytecode corrupt.") );
+
+ iRet = ( (a_fRes==fVal[0] && a_fPass) ||
+ (a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1;
+ if (iRet==1)
+ {
+ mu::console() << _T("\n fail: ") << a_str.c_str()
+ << _T(" (incorrect result; expected: ") << a_fRes
+ << _T(" ;calculated: ") << fVal[0]<< _T(").");
+ }
+ }
+ catch(Parser::exception_type &e)
+ {
+ if (a_fPass)
+ mu::console() << _T("\n ") << e.GetExpr() << _T(" : ") << e.GetMsg();
+ }
+ catch(...)
+ {
+ mu::console() << "\n fail: " << a_str.c_str() << " (unexpected exception)";
+ return 1; // exceptions other than ParserException are not allowed
+ }
+
+ return iRet;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Internal error in test class Test is going to be aborted. */
+ void ParserTester::Abort() const
+ {
+ mu::console() << _T("Test failed (internal error in test class)") << endl;
+ while (!getchar());
+ exit(-1);
+ }
+ } // namespace test
+} // namespace mu
+
+
+
diff --git a/muparser/muParserTest.h b/muparser/muParserTest.h
new file mode 100644
index 0000000..fe9bfdd
--- /dev/null
+++ b/muparser/muParserTest.h
@@ -0,0 +1,176 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MU_PARSER_TEST_H
+#define MU_PARSER_TEST_H
+
+#include <string>
+#include <numeric> // for accumulate
+#include "muParser.h"
+#include "muParserInt.h"
+
+
+namespace mu
+{
+ /** \brief Namespace for test cases. */
+ namespace Test
+ {
+ //------------------------------------------------------------------------------
+ /** \brief Test cases for unit testing.
+
+ (C) 2004-2006 Ingo Berg
+ */
+ class ParserTester // final
+ {
+ private:
+ // Multiarg callbacks
+ static value_type f1of1(value_type v) { return v;};
+
+ static value_type f1of2(value_type v, value_type ) {return v;};
+ static value_type f2of2(value_type , value_type v) {return v;};
+
+ static value_type f1of3(value_type v, value_type , value_type ) {return v;};
+ static value_type f2of3(value_type , value_type v, value_type ) {return v;};
+ static value_type f3of3(value_type , value_type , value_type v) {return v;};
+
+ static value_type f1of4(value_type v, value_type, value_type , value_type ) {return v;}
+ static value_type f2of4(value_type , value_type v, value_type , value_type ) {return v;}
+ static value_type f3of4(value_type , value_type, value_type v, value_type ) {return v;}
+ static value_type f4of4(value_type , value_type, value_type , value_type v) {return v;}
+
+ static value_type f1of5(value_type v, value_type, value_type , value_type , value_type ) { return v; }
+ static value_type f2of5(value_type , value_type v, value_type , value_type , value_type ) { return v; }
+ static value_type f3of5(value_type , value_type, value_type v, value_type , value_type ) { return v; }
+ static value_type f4of5(value_type , value_type, value_type , value_type v, value_type ) { return v; }
+ static value_type f5of5(value_type , value_type, value_type , value_type , value_type v) { return v; }
+
+ static value_type Min(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1<a_fVal2) ? a_fVal1 : a_fVal2; }
+ static value_type Max(value_type a_fVal1, value_type a_fVal2) { return (a_fVal1>a_fVal2) ? a_fVal1 : a_fVal2; }
+
+ static value_type plus2(value_type v1) { return v1+2; }
+ static value_type times3(value_type v1) { return v1*3; }
+ static value_type sqr(value_type v1) { return v1*v1; }
+
+ static value_type sign(value_type v) { return -v; }
+
+ static value_type Sum(const value_type* a_afArg, int a_iArgc)
+ {
+ if (!a_iArgc)
+ throw mu::Parser::exception_type( _T("too few arguments for function sum.") );
+
+ value_type fRes=0;
+ for (int i=0; i<a_iArgc; ++i) fRes += a_afArg[i];
+ return fRes;
+ }
+
+ static value_type Rnd(value_type v)
+ {
+ return (value_type)(1+(v*std::rand()/(RAND_MAX+1.0)));
+ }
+
+ static value_type RndWithString(const char_type*)
+ {
+ return (value_type)( 1 + (1000.0f * std::rand() / (RAND_MAX + 1.0) ) );
+ }
+
+ static value_type ValueOf(const char_type*)
+ {
+ return 123;
+ }
+
+ static value_type StrFun1(const char_type* v1)
+ {
+ int val(0);
+ stringstream_type(v1) >> val;
+ return val;
+ }
+
+ static value_type StrFun2(const char_type* v1, value_type v2)
+ {
+ int val(0);
+ stringstream_type(v1) >> val;
+ return val + v2;
+ }
+
+ static value_type StrFun3(const char_type* v1, value_type v2, value_type v3)
+ {
+ int val(0);
+ stringstream_type(v1) >> val;
+ return val + v2 + v3;
+ }
+
+ static value_type StrToFloat(const char_type* a_szMsg)
+ {
+ double val(0);
+ stringstream_type(a_szMsg) >> val;
+ return val;
+
+// using namespace std; // atof is for some compilers in std for some not...
+// return atof(a_szMsg);
+ }
+
+ // postfix operator callback
+ static value_type Milli(value_type v) { return v/(value_type)1e3; }
+
+ static int c_iCount;
+
+ int TestNames();
+ int TestSyntax();
+ int TestMultiArg();
+ int TestVolatile();
+ int TestPostFix();
+ int TestFormula();
+ int TestInfixOprt();
+ int TestBinOprt();
+ int TestVarConst();
+ int TestInterface();
+ int TestException();
+ int TestStrArg();
+
+ void Abort() const;
+
+ public:
+ typedef int (ParserTester::*testfun_type)();
+
+ ParserTester();
+ void Run();
+
+ private:
+ std::vector<testfun_type> m_vTestFun;
+ void AddTest(testfun_type a_pFun);
+
+ // Test Double Parser
+ int EqnTest(const string_type& a_str, double a_fRes, bool a_fPass);
+ int ThrowTest(const string_type& a_str, int a_iErrc, bool a_bFail = true);
+
+ // Test Int Parser
+ int EqnTestInt(const string_type& a_str, double a_fRes, bool a_fPass);
+ };
+ } // namespace Test
+} // namespace mu
+
+#endif
+
+
diff --git a/muparser/muParserToken.h b/muparser/muParserToken.h
new file mode 100644
index 0000000..b4c7e54
--- /dev/null
+++ b/muparser/muParserToken.h
@@ -0,0 +1,464 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MU_PARSER_TOKEN_H
+#define MU_PARSER_TOKEN_H
+
+#include <cassert>
+#include <string>
+#include <stack>
+#include <vector>
+#include <memory>
+
+#include "muParserError.h"
+#include "muParserCallback.h"
+
+
+namespace mu
+{
+
+/** \brief Encapsulation of the data for a single formula token.
+
+ Formula token implementation. Part of the Math Parser Package.
+ Formula tokens can be either one of the following:
+ <ul>
+ <li>value</li>
+ <li>variable</li>
+ <li>function with numerical arguments</li>
+ <li>functions with a string as argument</li>
+ <li>prefix operators</li>
+ <li>infix operators</li>
+ <li>binary operator</li>
+ </ul>
+
+ \author (C) 2004 Ingo Berg
+*/
+template<typename TBase, typename TString>
+class ParserToken
+{
+public:
+ /** \brief Additional token flags. */
+ enum ETokFlags
+ {
+ flVOLATILE = 1 ///< Mark a token that depends on a variable or a function that is not conservative
+ };
+
+private:
+ ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode.
+ ETypeCode m_iType;
+ void *m_pTok; ///< Stores Token pointer; not applicable for all tokens
+ int m_iFlags; ///< Additional flags for the token.
+ int m_iIdx; ///< An otional index to an external buffer storing the token data
+ TString m_strTok; ///< Token string
+ TString m_strVal; ///< Value for string variables
+ value_type m_fVal;
+ std::auto_ptr<ParserCallback> m_pCallback;
+
+public:
+
+ //---------------------------------------------------------------------------
+ /** \brief Constructor (default).
+
+ Sets token to an neutral state of type cmUNKNOWN.
+ \throw nothrow
+ \sa ECmdCode
+ */
+ ParserToken()
+ :m_iCode(cmUNKNOWN)
+ ,m_iType(tpVOID)
+ ,m_pTok(0)
+ ,m_iFlags(0)
+ ,m_iIdx(-1)
+ ,m_strTok()
+ ,m_pCallback()
+ {}
+
+ //------------------------------------------------------------------------------
+ /** \brief Create token from another one.
+
+ Implemented by calling Assign(...)
+ \throw nothrow
+ \post m_iType==cmUNKNOWN
+ \sa #Assign
+ */
+ ParserToken(const ParserToken &a_Tok)
+ {
+ Assign(a_Tok);
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Assignement operator.
+
+ Copy token state from another token and return this.
+ Implemented by calling Assign(...).
+ \throw nothrow
+ */
+ ParserToken& operator=(const ParserToken &a_Tok)
+ {
+ Assign(a_Tok);
+ return *this;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Copy token information from argument.
+
+ \throw nothrow
+ */
+ void Assign(const ParserToken &a_Tok)
+ {
+ m_iCode = a_Tok.m_iCode;
+ m_pTok = a_Tok.m_pTok;
+ m_iFlags = a_Tok.m_iFlags;
+ m_strTok = a_Tok.m_strTok;
+ m_iIdx = a_Tok.m_iIdx;
+ m_strVal = a_Tok.m_strVal;
+ m_iType = a_Tok.m_iType;
+ m_fVal = a_Tok.m_fVal;
+ // create new callback object if a_Tok has one
+ m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0);
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Add additional flags to the token.
+
+ Flags are currently used to mark volatile (non optimizeable) functions.
+ \sa m_iFlags, ETokFlags
+ */
+ void AddFlags(int a_iFlags)
+ {
+ m_iFlags |= a_iFlags;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Check if a certain flag ist set.
+
+ \throw nothrow
+ */
+ bool IsFlagSet(int a_iFlags) const
+ {
+ #if defined(_MSC_VER)
+ #pragma warning( disable : 4800 )
+ #endif
+
+ return (bool)(m_iFlags & a_iFlags);
+
+ #if defined(_MSC_VER)
+ #pragma warning( default : 4800 ) // int: Variable set to boolean value (may degrade performance)
+ #endif
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Assign a token type.
+
+ Token may not be of type value, variable or function. Those have seperate set functions.
+
+ \pre [assert] a_iType!=cmVAR
+ \pre [assert] a_iType!=cmVAL
+ \pre [assert] a_iType!=cmFUNC
+ \post m_fVal = 0
+ \post m_pTok = 0
+ */
+ ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString())
+ {
+ // The following types cant be set this way, they have special Set functions
+ assert(a_iType!=cmVAR);
+ assert(a_iType!=cmVAL);
+ assert(a_iType!=cmFUNC);
+
+ m_iCode = a_iType;
+ m_iType = tpVOID;
+ m_pTok = 0;
+ m_iFlags = 0;
+ m_strTok = a_strTok;
+ m_iIdx = -1;
+
+ return *this;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Set Callback type. */
+ ParserToken& Set(const ParserCallback &a_pCallback, const TString &a_sTok)
+ {
+ assert(a_pCallback.GetAddr());
+
+ m_iCode = a_pCallback.GetCode();
+ m_iType = tpVOID;
+ m_strTok = a_sTok;
+ m_pCallback.reset(new ParserCallback(a_pCallback));
+
+ m_pTok = 0;
+ m_iFlags = 0;
+ m_iIdx = -1;
+
+ if (!m_pCallback->IsOptimizable())
+ AddFlags(flVOLATILE);
+
+ return *this;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Make this token a value token.
+
+ Member variables not necessary for value tokens will be invalidated.
+ \throw nothrow
+ */
+ ParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString())
+ {
+ m_iCode = cmVAL;
+ m_iType = tpDBL;
+ m_fVal = a_fVal;
+ m_iFlags = 0;
+ m_strTok = a_strTok;
+ m_iIdx = -1;
+
+ m_pTok = 0;
+ m_pCallback.reset(0);
+
+ return *this;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief make this token a variable token.
+
+ Member variables not necessary for variable tokens will be invalidated.
+ \throw nothrow
+ */
+ ParserToken& SetVar(TBase *a_pVar, const TString &a_strTok)
+ {
+ m_iCode = cmVAR;
+ m_iType = tpDBL;
+ m_iFlags = 0;
+ m_strTok = a_strTok;
+ m_iIdx = -1;
+ m_pTok = (void*)a_pVar;
+ m_pCallback.reset(0);
+
+ AddFlags(ParserToken::flVOLATILE);
+ return *this;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Make this token a variable token.
+
+ Member variables not necessary for variable tokens will be invalidated.
+ \throw nothrow
+ */
+ ParserToken& SetString(const TString &a_strTok, std::size_t a_iSize)
+ {
+ m_iCode = cmSTRING; // cmSTRVAR;
+ m_iType = tpSTR;
+ m_iFlags = 0;
+ m_strTok = a_strTok;
+ m_iIdx = static_cast<int>(a_iSize);
+
+ m_pTok = 0;
+ m_pCallback.reset(0);
+
+ AddFlags(ParserToken::flVOLATILE);
+ return *this;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Make token a string token.
+
+ String tokens are used to store the value of string function arguments.
+ \param a_strTok the string content.
+ \post #m_iType==cmSTRING, #m_strTok==a_strTok
+ \throw nothrow
+ */
+ ParserToken& SetString(const string_type &a_strTok)
+ {
+ m_iCode = cmSTRING;
+ m_iType = tpSTR;
+ m_iFlags = 0;
+ m_iIdx = -1;
+
+ m_pTok = 0;
+ m_pCallback.reset(0);
+
+ m_strTok = a_strTok;
+
+ return *this;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Set an index associated with the token related data.
+
+ In cmSTRFUNC - This is the index to a string table in the main parser.
+ \param a_iIdx The index the string function result will take in the bytecode parser.
+ \throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING
+ */
+ void SetIdx(int a_iIdx)
+ {
+ if (m_iCode!=cmSTRING || a_iIdx<0)
+ throw ParserError(ecINTERNAL_ERROR);
+
+ m_iIdx = a_iIdx;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Return Index associated with the token related data.
+
+ In cmSTRFUNC - This is the index to a string table in the main parser.
+
+ \throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING
+ \return The index the result will take in the Bytecode calculatin array (#m_iIdx).
+ */
+ int GetIdx() const
+ {
+ if (m_iIdx<0 || m_iCode!=cmSTRING )
+ throw ParserError(ecINTERNAL_ERROR);
+
+ return m_iIdx;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Return the token type.
+
+ \return #m_iType
+ \throw nothrow
+ */
+ ECmdCode GetCode() const
+ {
+ if (m_pCallback.get())
+ {
+ return m_pCallback->GetCode();
+ }
+ else
+ {
+ return m_iCode;
+ }
+ }
+
+ //------------------------------------------------------------------------------
+ ETypeCode GetType() const
+ {
+ if (m_pCallback.get())
+ {
+ return m_pCallback->GetType();
+ }
+ else
+ {
+ return m_iType;
+ }
+ }
+
+ //------------------------------------------------------------------------------
+ int GetPri() const
+ {
+ if ( !m_pCallback.get())
+ throw ParserError(ecINTERNAL_ERROR);
+
+ if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX)
+ throw ParserError(ecINTERNAL_ERROR);
+
+ return m_pCallback->GetPri();
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Return the address of the callback function assoziated with
+ function and operator tokens.
+
+ \return The pointer stored in #m_pTok.
+ \throw exception_type if token type is non of:
+ <ul>
+ <li>cmFUNC</li>
+ <li>cmSTRFUNC</li>
+ <li>cmPOSTOP</li>
+ <li>cmINFIXOP</li>
+ <li>cmOPRT_BIN</li>
+ </ul>
+ \sa ECmdCode
+ */
+ void* GetFuncAddr() const
+ {
+ return (m_pCallback.get()) ? m_pCallback->GetAddr() : 0;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \biref Get value of the token.
+
+ Only applicable to variable and value tokens.
+ \throw exception_type if token is no value/variable token.
+ */
+ TBase GetVal() const
+ {
+ switch (m_iCode)
+ {
+ case cmVAL: return m_fVal;
+ case cmVAR: return *((TBase*)m_pTok);
+ default: throw ParserError(ecVAL_EXPECTED);
+ }
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Get address of a variable token.
+
+ Valid only if m_iType==CmdVar.
+ \throw exception_type if token is no variable token.
+ */
+ TBase* GetVar() const
+ {
+ if (m_iCode!=cmVAR)
+ throw ParserError(ecINTERNAL_ERROR);
+
+ return (TBase*)m_pTok;
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Return the number of function arguments.
+
+ Valid only if m_iType==CmdFUNC.
+ */
+ int GetArgCount() const
+ {
+ assert(m_pCallback.get());
+
+ if (!m_pCallback->GetAddr())
+ throw ParserError(ecINTERNAL_ERROR);
+
+ return m_pCallback->GetArgc();
+ }
+
+ //------------------------------------------------------------------------------
+ /** \brief Return the token identifier.
+
+ If #m_iType is cmSTRING the token identifier is the value of the string argument
+ for a string function.
+ \return #m_strTok
+ \throw nothrow
+ \sa m_strTok
+ */
+ const TString& GetAsString() const
+ {
+ return m_strTok;
+ }
+};
+
+} // namespace mu
+
+#endif
+
+
diff --git a/muparser/muParserTokenReader.cpp b/muparser/muParserTokenReader.cpp
new file mode 100644
index 0000000..99c0a0a
--- /dev/null
+++ b/muparser/muParserTokenReader.cpp
@@ -0,0 +1,822 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <map>
+#include <stack>
+#include <string>
+
+#include "muParserTokenReader.h"
+#include "muParserBase.h"
+
+
+namespace mu
+{
+
+ // Forward declaration
+ class ParserBase;
+
+ //---------------------------------------------------------------------------
+ /** \brief Copy constructor.
+
+ \sa Assign
+ \throw nothrow
+ */
+ ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader)
+ {
+ Assign(a_Reader);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Assignement operator.
+
+ Self assignement will be suppressed otherwise #Assign is called.
+
+ \param a_Reader Object to copy to this token reader.
+ \throw nothrow
+ */
+ ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader)
+ {
+ if (&a_Reader!=this)
+ Assign(a_Reader);
+
+ return *this;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Assign state of a token reader to this token reader.
+
+ \param a_Reader Object from which the state should be copied.
+ \throw nothrow
+ */
+ void ParserTokenReader::Assign(const ParserTokenReader &a_Reader)
+ {
+ m_pParser = a_Reader.m_pParser;
+ m_strFormula = a_Reader.m_strFormula;
+ m_iPos = a_Reader.m_iPos;
+ m_iSynFlags = a_Reader.m_iSynFlags;
+
+ m_UsedVar = a_Reader.m_UsedVar;
+ m_pFunDef = a_Reader.m_pFunDef;
+ m_pConstDef = a_Reader.m_pConstDef;
+ m_pVarDef = a_Reader.m_pVarDef;
+ m_pStrVarDef = a_Reader.m_pStrVarDef;
+ m_pPostOprtDef = a_Reader.m_pPostOprtDef;
+ m_pInfixOprtDef = a_Reader.m_pInfixOprtDef;
+ m_pOprtDef = a_Reader.m_pOprtDef;
+ m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar;
+ m_vIdentFun = a_Reader.m_vIdentFun;
+ m_pFactory = a_Reader.m_pFactory;
+ m_pFactoryData = a_Reader.m_pFactoryData;
+ m_iBrackets = a_Reader.m_iBrackets;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Constructor.
+
+ Create a Token reader and bind it to a parser object.
+
+ \pre [assert] a_pParser may not be NULL
+ \post #m_pParser==a_pParser
+ \param a_pParent Parent parser object of the token reader.
+ */
+ ParserTokenReader::ParserTokenReader(ParserBase *a_pParent)
+ :m_pParser(a_pParent)
+ ,m_strFormula()
+ ,m_iPos(0)
+ ,m_iSynFlags(0)
+ ,m_bIgnoreUndefVar(false)
+ ,m_pFunDef(NULL)
+ ,m_pPostOprtDef(NULL)
+ ,m_pInfixOprtDef(NULL)
+ ,m_pOprtDef(NULL)
+ ,m_pConstDef(NULL)
+ ,m_pStrVarDef(NULL)
+ ,m_pVarDef(NULL)
+ ,m_pFactory(NULL)
+ ,m_pFactoryData(NULL)
+ ,m_vIdentFun()
+ ,m_UsedVar()
+ ,m_fZero(0)
+ ,m_iBrackets(0)
+ {
+ assert(m_pParser);
+ SetParent(m_pParser);
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Destructor (trivial).
+
+ \throw nothrow
+ */
+ ParserTokenReader::~ParserTokenReader()
+ {}
+
+ //---------------------------------------------------------------------------
+ /** \brief Create instance of a ParserTokenReader identical with this
+ and return its pointer.
+
+ This is a factory method the calling function must take care of the object destruction.
+
+ \return A new ParserTokenReader object.
+ \throw nothrow
+ */
+ ParserTokenReader* ParserTokenReader::Clone(ParserBase *a_pParent) const
+ {
+ std::auto_ptr<ParserTokenReader> ptr(new ParserTokenReader(*this));
+ ptr->SetParent(a_pParent);
+ return ptr.release();
+ }
+
+ //---------------------------------------------------------------------------
+ void ParserTokenReader::AddValIdent(identfun_type a_pCallback)
+ {
+ m_vIdentFun.push_back(a_pCallback);
+ }
+
+ //---------------------------------------------------------------------------
+ void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData)
+ {
+ m_pFactory = a_pFactory;
+ m_pFactoryData = pUserData;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Return the current position of the token reader in the formula string.
+
+ \return #m_iPos
+ \throw nothrow
+ */
+ int ParserTokenReader::GetPos() const
+ {
+ return m_iPos;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Return a reference to the formula.
+
+ \return #m_strFormula
+ \throw nothrow
+ */
+ const string_type& ParserTokenReader::GetFormula() const
+ {
+ return m_strFormula;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Return a map containing the used variables only. */
+ const varmap_type& ParserTokenReader::GetUsedVar() const
+ {
+ return m_UsedVar;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Initialize the token Reader.
+
+ Sets the formula position index to zero and set Syntax flags to default for initial formula parsing.
+ \pre [assert] triggered if a_szFormula==0
+ */
+ void ParserTokenReader::SetFormula(const string_type &a_strFormula)
+ {
+ m_strFormula = a_strFormula;
+ ReInit();
+ }
+
+ //---------------------------------------------------------------------------
+ void ParserTokenReader::SetDefs( const funmap_type *a_pFunDef,
+ const funmap_type *a_pOprtDef,
+ const funmap_type *a_pInfixOprtDef,
+ const funmap_type *a_pPostOprtDef,
+ varmap_type *a_pVarDef,
+ const strmap_type *a_pStrVarDef,
+ const valmap_type *a_pConstDef )
+ {
+ m_pFunDef = a_pFunDef;
+ m_pOprtDef = a_pOprtDef;
+ m_pInfixOprtDef = a_pInfixOprtDef;
+ m_pPostOprtDef = a_pPostOprtDef;
+ m_pVarDef = a_pVarDef;
+ m_pStrVarDef = a_pStrVarDef;
+ m_pConstDef = a_pConstDef;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Set Flag that contronls behaviour in case of undefined variables beeing found.
+
+ If true, the parser does not throw an exception if an undefined variable is found.
+ otherwise it does. This variable is used internally only!
+ It supresses a "undefined variable" exception in GetUsedVar().
+ Those function should return a complete list of variables including
+ those the are not defined by the time of it's call.
+ */
+ void ParserTokenReader::IgnoreUndefVar(bool bIgnore)
+ {
+ m_bIgnoreUndefVar = bIgnore;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Reset the token reader to the start of the formula.
+
+ The syntax flags will be reset to a value appropriate for the
+ start of a formula.
+ \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR
+ \throw nothrow
+ \sa ESynCodes
+ */
+ void ParserTokenReader::ReInit()
+ {
+ m_iPos = 0;
+ m_iSynFlags = noOPT | noBC | noPOSTOP | noASSIGN;
+ m_iBrackets = 0;
+ m_UsedVar.clear();
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Read the next token from the string. */
+ ParserTokenReader::token_type ParserTokenReader::ReadNextToken()
+ {
+ assert(m_pParser);
+
+ std::stack<int> FunArgs;
+ const char_type *szFormula = m_strFormula.c_str();
+ token_type tok;
+
+ while (szFormula[m_iPos]==' ')
+ ++m_iPos;
+
+ if ( IsEOF(tok) ) return tok; // Check for end of formula
+ if ( IsOprt(tok) ) return tok; // Check for user defined binary operator
+ if ( IsBuiltIn(tok) ) return tok; // Check built in operators / tokens
+ if ( IsFunTok(tok) ) return tok; // Check for function token
+ if ( IsValTok(tok) ) return tok; // Check for values / constant tokens
+ if ( IsVarTok(tok) ) return tok; // Check for variable tokens
+ if ( IsStrVarTok(tok) ) return tok; // Check for string variables
+ if ( IsString(tok) ) return tok; // Check for String tokens
+ if ( IsInfixOpTok(tok) ) return tok; // Check for unary operators
+ if ( IsPostOpTok(tok) ) return tok; // Check for unary operators
+
+ // Check String for undefined variable token. Done only if a
+ // flag is set indicating to ignore undefined variables.
+ // This is a way to conditionally avoid an error if
+ // undefined variables occur.
+ // The GetUsedVar function must supress the error for
+ // undefined variables in order to collect all variable
+ // names including the undefined ones.
+ if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) return tok;
+
+ // Check for unknown token
+ //
+ // !!! From this point on there is no exit without an exception possible...
+ //
+ string_type strTok;
+ int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
+ if (iEnd!=m_iPos)
+ Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok);
+
+ Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos));
+ return token_type(); // never reached
+ }
+
+ //---------------------------------------------------------------------------
+ void ParserTokenReader::SetParent(ParserBase *a_pParent)
+ {
+ m_pParser = a_pParent;
+ m_pFunDef = &a_pParent->m_FunDef;
+ m_pOprtDef = &a_pParent->m_OprtDef;
+ m_pInfixOprtDef = &a_pParent->m_InfixOprtDef;
+ m_pPostOprtDef = &a_pParent->m_PostOprtDef;
+ m_pVarDef = &a_pParent->m_VarDef;
+ m_pStrVarDef = &a_pParent->m_StrVarDef;
+ m_pConstDef = &a_pParent->m_ConstDef;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Extract all characters that belong to a certain charset.
+
+ \param a_szCharSet [in] Const char array of the characters allowed in the token.
+ \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet.
+ \param a_iPos [in] Position in the string from where to start reading.
+ \return The Position of the first character not listed in a_szCharSet.
+ \throw nothrow
+ */
+ int ParserTokenReader::ExtractToken( const char_type *a_szCharSet,
+ string_type &a_sTok, int a_iPos ) const
+ {
+ int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos);
+
+ if (iEnd==(int)string_type::npos)
+ iEnd = (int)m_strFormula.length();
+
+ a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd);
+ a_iPos = iEnd;
+ return iEnd;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check if a built in operator or other token can be found
+ \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token.
+ \return true if an operator token has been found.
+ */
+ bool ParserTokenReader::IsBuiltIn(token_type &a_Tok)
+ {
+ const char_type **pOprtDef = m_pParser->GetOprtDef();
+ const char_type* szFormula = m_strFormula.c_str();
+
+ // Compare token with function and operator strings
+ // check string for operator/function
+ for (int i=0; pOprtDef[i]; i++)
+ {
+#if !defined _UNICODE
+ std::size_t len = std::strlen( pOprtDef[i] );
+ if ( !std::strncmp(&szFormula[m_iPos], pOprtDef[i], len) )
+#else
+ // this would work for both UNICODE and char but it's so god damn ugly!!
+ // apart from this this cant be fast
+ std::size_t len( std::char_traits<char_type>::length(pOprtDef[i]) );
+ if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) )
+#endif
+ {
+ switch(i)
+ {
+ case cmAND:
+ case cmOR:
+ case cmXOR:
+ case cmLT:
+ case cmGT:
+ case cmLE:
+ case cmGE:
+ case cmNEQ:
+ case cmEQ:
+ case cmADD:
+ case cmSUB:
+ case cmMUL:
+ case cmDIV:
+ case cmPOW:
+ case cmASSIGN:
+ // The assignement operator need special treatment
+ if (i==cmASSIGN && m_iSynFlags & noASSIGN)
+ Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
+
+ if (!m_pParser->HasBuiltInOprt()) continue;
+ if (m_iSynFlags & noOPT)
+ {
+ // Maybe its an infix operator not an operator
+ // Both operator types can share characters in
+ // their identifiers
+ if ( IsInfixOpTok(a_Tok) )
+ return true;
+
+ Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
+ }
+
+ m_iSynFlags = noBC | noOPT | noCOMMA | noPOSTOP | noASSIGN;
+ m_iSynFlags |= ( (i != cmEND) && ( i != cmBC) ) ? noEND : 0;
+ break;
+
+ case cmCOMMA:
+ if (m_iSynFlags & noCOMMA)
+ Error(ecUNEXPECTED_COMMA, m_iPos, pOprtDef[i]);
+
+ m_iSynFlags = noBC | noOPT | noEND | noCOMMA | noPOSTOP | noASSIGN;
+ break;
+
+ case cmBO:
+ if (m_iSynFlags & noBO)
+ Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
+
+ m_iSynFlags = noBC | noOPT | noEND | noCOMMA | noPOSTOP | noASSIGN;
+ ++m_iBrackets;
+ break;
+
+ case cmBC:
+ if (m_iSynFlags & noBC)
+ Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
+
+ m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN;
+
+ if (--m_iBrackets<0)
+ Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
+ break;
+
+ default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing...
+ Error(ecINTERNAL_ERROR);
+ } // switch operator id
+
+ m_iPos += (int)len;
+ a_Tok.Set( (ECmdCode)i, pOprtDef[i] );
+ return true;
+ } // if operator string found
+ } // end of for all operator strings
+
+ return false;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check for End of Formula.
+
+ \return true if an end of formula is found false otherwise.
+ \param a_Tok [out] If an eof is found the corresponding token will be stored there.
+ \throw nothrow
+ \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok
+ */
+ bool ParserTokenReader::IsEOF(token_type &a_Tok)
+ {
+ const char_type* szFormula = m_strFormula.c_str();
+
+ // check for EOF
+ if ( !szFormula[m_iPos] || szFormula[m_iPos] == '\n')
+ {
+ if ( m_iSynFlags & noEND )
+ Error(ecUNEXPECTED_EOF, m_iPos);
+
+ if (m_iBrackets>0)
+ Error(ecMISSING_PARENS, m_iPos, _T(")"));
+
+ m_iSynFlags = 0;
+ a_Tok.Set(cmEND);
+ return true;
+ }
+
+ return false;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check if a string position contains a unary infix operator.
+ \return true if a function token has been found false otherwise.
+ */
+ bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok)
+ {
+ string_type sTok;
+ int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos);
+ if (iEnd==m_iPos)
+ return false;
+
+ funmap_type::const_iterator item = m_pInfixOprtDef->find(sTok);
+ if (item==m_pInfixOprtDef->end())
+ return false;
+
+ a_Tok.Set(item->second, sTok);
+ m_iPos = (int)iEnd;
+
+ if (m_iSynFlags & noINFIXOP)
+ Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
+
+ m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN;
+ return true;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check whether the token at a given position is a function token.
+ \param a_Tok [out] If a value token is found it will be placed here.
+ \throw ParserException if Syntaxflags do not allow a function at a_iPos
+ \return true if a function token has been found false otherwise.
+ \pre [assert] m_pParser!=0
+ */
+ bool ParserTokenReader::IsFunTok(token_type &a_Tok)
+ {
+ string_type strTok;
+ int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
+ if (iEnd==m_iPos)
+ return false;
+
+ funmap_type::const_iterator item = m_pFunDef->find(strTok);
+ if (item==m_pFunDef->end())
+ return false;
+
+ a_Tok.Set(item->second, strTok);
+
+ m_iPos = (int)iEnd;
+ if (m_iSynFlags & noFUN)
+ Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString());
+
+ m_iSynFlags = noANY ^ noBO;
+ return true;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check if a string position contains a binary operator.
+ \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token.
+ \return true if an operator token has been found.
+ */
+ bool ParserTokenReader::IsOprt(token_type &a_Tok)
+ {
+ string_type strTok;
+ int iEnd = ExtractToken(m_pParser->ValidOprtChars(), strTok, m_iPos);
+ if (iEnd==m_iPos)
+ return false;
+
+ funmap_type::const_iterator item = m_pOprtDef->find(strTok);
+ if (item==m_pOprtDef->end())
+ return false;
+
+ a_Tok.Set(item->second, strTok);
+
+ if (m_iSynFlags & noOPT)
+ {
+ // An operator was found but is not expected to occur at
+ // this position of the formula, maybe it is an infix
+ // operator, not a binary operator. Both operator types
+ // can share characters in their identifiers.
+ if ( IsInfixOpTok(a_Tok) ) return true;
+ // nope, no infix operator
+ Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
+ }
+
+ m_iPos = (int)iEnd;
+ m_iSynFlags = noBC | noOPT | noCOMMA | noPOSTOP | noEND | noBC | noASSIGN;
+ return true;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check if a string position contains a unary post value operator. */
+ bool ParserTokenReader::IsPostOpTok(token_type &a_Tok)
+ {
+ // Tricky problem with equations like "3m+5":
+ // m is a postfix operator, + is a valid sign for postfix operators and
+ // for binary operators parser detects "m+" as operator string and
+ // finds no matching postfix operator.
+ //
+ // This is a special case so this routine slightly differs from the other
+ // token readers.
+
+ // Test if there could be a postfix operator
+ string_type sTok;
+ int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos);
+ if (iEnd==m_iPos)
+ return false;
+
+ // iteraterate over all postfix operator strings
+ funmap_type::const_iterator item = m_pPostOprtDef->begin();
+ for (item=m_pPostOprtDef->begin(); item!=m_pPostOprtDef->end(); ++item)
+ {
+ if (sTok.find(item->first)!=0)
+ continue;
+
+ a_Tok.Set(item->second, sTok);
+ m_iPos += (int)item->first.length();
+
+ if (m_iSynFlags & noPOSTOP)
+ Error(ecUNEXPECTED_OPERATOR, m_iPos-(int)item->first.length(), item->first);
+
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN;
+ return true;
+ }
+
+ return false;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check whether the token at a given position is a value token.
+
+ Value tokens are either values or constants.
+
+ \param a_Tok [out] If a value token is found it will be placed here.
+ \return true if a value token has been found.
+ */
+ bool ParserTokenReader::IsValTok(token_type &a_Tok)
+ {
+ assert(m_pConstDef);
+ assert(m_pParser);
+
+ #if defined(_MSC_VER)
+ #pragma warning( disable : 4244 )
+ #endif
+
+ string_type strTok;
+ value_type fVal(0);
+ int iEnd(0);
+
+ // 2.) Check for user defined constant
+ // Read everything that could be a constant name
+ iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
+ if (iEnd!=m_iPos)
+ {
+ valmap_type::const_iterator item = m_pConstDef->find(strTok);
+ if (item!=m_pConstDef->end())
+ {
+ m_iPos = iEnd;
+ a_Tok.SetVal(item->second, strTok);
+
+ if (m_iSynFlags & noVAL)
+ Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
+
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
+ return true;
+ }
+ }
+
+ // 3.call the value recognition functions provided by the user
+ // Call user defined value recognition functions
+ std::vector<identfun_type>::const_iterator item = m_vIdentFun.begin();
+ for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item)
+ {
+ int iStart = m_iPos;
+ if ( (*item)(m_strFormula.c_str() + m_iPos, m_iPos, fVal) )
+ {
+ strTok.assign(m_strFormula.c_str(), iStart, m_iPos);
+ if (m_iSynFlags & noVAL)
+ Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
+
+ a_Tok.SetVal(fVal, strTok);
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
+ return true;
+ }
+ }
+
+ return false;
+
+ #if defined(_MSC_VER)
+ #pragma warning( default : 4244 )
+ #endif
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check wheter a token at a given position is a variable token.
+ \param a_Tok [out] If a variable token has been found it will be placed here.
+ \return true if a variable token has been found.
+ */
+ bool ParserTokenReader::IsVarTok(token_type &a_Tok)
+ {
+ if (!m_pVarDef->size())
+ return false;
+
+ string_type strTok;
+ int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
+ if (iEnd==m_iPos)
+ return false;
+
+ varmap_type::const_iterator item = m_pVarDef->find(strTok);
+ if (item==m_pVarDef->end())
+ return false;
+
+ if (m_iSynFlags & noVAR)
+ Error(ecUNEXPECTED_VAR, m_iPos, strTok);
+
+ m_iPos = iEnd;
+ a_Tok.SetVar(item->second, strTok);
+ m_UsedVar[item->first] = item->second; // Add variable to used-var-list
+
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR;
+ return true;
+ }
+
+ //---------------------------------------------------------------------------
+ bool ParserTokenReader::IsStrVarTok(token_type &a_Tok)
+ {
+ if (!m_pStrVarDef || !m_pStrVarDef->size())
+ return false;
+
+ string_type strTok;
+ int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
+ if (iEnd==m_iPos)
+ return false;
+
+ strmap_type::const_iterator item = m_pStrVarDef->find(strTok);
+ if (item==m_pStrVarDef->end())
+ return false;
+
+ if (m_iSynFlags & noSTR)
+ Error(ecUNEXPECTED_VAR, m_iPos, strTok);
+
+ m_iPos = iEnd;
+ if (!m_pParser->m_vStringVarBuf.size())
+ Error(ecINTERNAL_ERROR);
+
+ a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() );
+
+ m_iSynFlags = m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noCOMMA);
+ return true;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check wheter a token at a given position is an undefined variable.
+
+ \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here.
+ \return true if a variable token has been found.
+ \throw nothrow
+ */
+ bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok)
+ {
+ string_type strTok;
+ int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
+ if (iEnd==m_iPos)
+ return false;
+
+ if (m_iSynFlags & noVAR)
+ {
+ // <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the
+ // token identifier.
+ Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok);
+ }
+
+ // If a factory is available implicitely create new variables
+ if (m_pFactory)
+ {
+ value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData);
+ a_Tok.SetVar(fVar, strTok );
+
+ // Do not use m_pParser->DefineVar( strTok, fVar );
+ // in order to define the new variable, it will clear the
+ // m_UsedVar array which will kill previousely defined variables
+ // from the list
+ // This is safe because the new variable can never override an existing one
+ // because they are checked first!
+ (*m_pVarDef)[strTok] = fVar;
+ m_UsedVar[strTok] = fVar; // Add variable to used-var-list
+ }
+ else
+ {
+ a_Tok.SetVar((value_type*)&m_fZero, strTok);
+ m_UsedVar[strTok] = 0; // Add variable to used-var-list
+ }
+
+ m_iPos = iEnd;
+
+ // Call the variable factory in order to let it define a new parser variable
+ m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR;
+ return true;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Check wheter a token at a given position is a string.
+
+ \param a_Tok [out] If a variable token has been found it will be placed here.
+ \return true if a string token has been found.
+ \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok
+ \throw nothrow
+ */
+ bool ParserTokenReader::IsString(token_type &a_Tok)
+ {
+ if (m_strFormula[m_iPos]!='"')
+ return false;
+
+ string_type strBuf(&m_strFormula[m_iPos+1]);
+ std::size_t iEnd(0), iSkip(0);
+
+ // parser over escaped '\"' end replace them with '"'
+ for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd))
+ {
+ if (strBuf[iEnd-1]!='\\') break;
+ strBuf.replace(iEnd-1, 2, _T("\"") );
+ iSkip++;
+ }
+
+ if (iEnd==string_type::npos)
+ Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") );
+
+ string_type strTok(strBuf.begin(), strBuf.begin()+iEnd);
+
+ if (m_iSynFlags & noSTR)
+ Error(ecUNEXPECTED_STR, m_iPos, strTok);
+
+ m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer
+ a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size());
+
+ m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 wg Anführungszeichen; +iSkip für entfernte escape zeichen
+ m_iSynFlags = m_iSynFlags = noANY ^ ( noCOMMA | noBC | noOPT | noEND );
+
+ return true;
+ }
+
+ //---------------------------------------------------------------------------
+ /** \brief Create an error containing the parse error position.
+
+ This function will create an Parser Exception object containing the error text and its position.
+
+ \param a_iErrc [in] The error code of type #EErrorCodes.
+ \param a_iPos [in] The position where the error was detected.
+ \param a_strTok [in] The token string representation associated with the error.
+ \throw ParserException always throws thats the only purpose of this function.
+ */
+ void ParserTokenReader::Error( EErrorCodes a_iErrc,
+ int a_iPos,
+ const string_type &a_sTok) const
+ {
+ m_pParser->Error(a_iErrc, a_iPos, a_sTok);
+ }
+} // namespace mu
+
diff --git a/muparser/muParserTokenReader.h b/muparser/muParserTokenReader.h
new file mode 100644
index 0000000..122586e
--- /dev/null
+++ b/muparser/muParserTokenReader.h
@@ -0,0 +1,156 @@
+/*
+ __________
+ _____ __ __\______ \_____ _______ ______ ____ _______
+ / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
+ | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
+ |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
+ \/ \/ \/ \/
+ Copyright (C) 2004-2006 Ingo Berg
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ software and associated documentation files (the "Software"), to deal in the Software
+ without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or
+ substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MU_PARSER_TOKEN_READER_H
+#define MU_PARSER_TOKEN_READER_H
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <map>
+#include <memory>
+#include <stack>
+#include <string>
+
+#include "muParserDef.h"
+#include "muParserToken.h"
+
+
+namespace mu
+{
+
+ // Forward declaration
+ class ParserBase;
+
+ /** \brief Token reader for the ParserBase class.
+
+ */
+ class ParserTokenReader
+ {
+ private:
+ typedef ParserToken<value_type, string_type> token_type;
+
+ private:
+ ParserBase *m_pParser;
+ string_type m_strFormula;
+ int m_iPos;
+ int m_iSynFlags;
+ bool m_bIgnoreUndefVar;
+
+ const funmap_type *m_pFunDef;
+ const funmap_type *m_pPostOprtDef;
+ const funmap_type *m_pInfixOprtDef;
+ const funmap_type *m_pOprtDef;
+ const valmap_type *m_pConstDef;
+ const strmap_type *m_pStrVarDef;
+ varmap_type *m_pVarDef; ///< The only non const pointer to parser internals
+ facfun_type m_pFactory;
+ void *m_pFactoryData;
+ std::vector<identfun_type> m_vIdentFun; ///< Value token identification function
+ varmap_type m_UsedVar;
+ value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables
+ int m_iBrackets;
+
+ //
+ // private Functions
+ //
+ private:
+
+ /** \brief Syntax codes.
+
+ The syntax codes control the syntax check done during the first time parsing of
+ the expression string. They are flags that indicate which tokens are allowed next
+ if certain tokens are identified.
+ */
+ enum ESynCodes
+ {
+ noBO = 1 << 0, ///< to avoid i.e. "cos(7)("
+ noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()"
+ noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14"
+ noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a"
+ noCOMMA = 1 << 4, ///< to avoid i.e. ",," or "+," ...
+ noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin"
+ noOPT = 1 << 6, ///< to avoid i.e. "(+)"
+ noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!"
+ noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4"
+ noEND = 1 << 9, ///< to avoid unexpected end of formula
+ noSTR = 1 << 10, ///< to block numeric arguments on string functions
+ noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7"
+ noANY = ~0 ///< All of he above flags set
+ };
+
+ ParserTokenReader(const ParserTokenReader &a_Reader);
+ ParserTokenReader& operator=(const ParserTokenReader &a_Reader);
+ void Assign(const ParserTokenReader &a_Reader);
+
+ public:
+ ParserTokenReader(ParserBase *a_pParent);
+ ~ParserTokenReader();
+ ParserTokenReader* Clone(ParserBase *a_pParent) const;
+
+ void AddValIdent(identfun_type a_pCallback);
+ void SetVarCreator(facfun_type a_pFactory, void *pUserData);
+ int GetPos() const;
+ const string_type& GetFormula() const;
+ const varmap_type& GetUsedVar() const;
+ void SetFormula(const string_type &a_strFormula);
+ void SetDefs( const funmap_type *a_pFunDef,
+ const funmap_type *a_pOprtDef,
+ const funmap_type *a_pInfixOprtDef,
+ const funmap_type *a_pPostOprtDef,
+ varmap_type *a_pVarDef,
+ const strmap_type *a_pStrVarDef,
+ const valmap_type *a_pConstDef );
+ void IgnoreUndefVar(bool bIgnore);
+ void ReInit();
+ token_type ReadNextToken();
+
+ //
+ // private functions
+ //
+ private:
+
+ void SetParent(ParserBase *a_pParent);
+ int ExtractToken( const char_type *a_szCharSet,
+ string_type &a_strTok, int a_iPos ) const;
+ bool IsBuiltIn(token_type &a_Tok);
+ bool IsEOF(token_type &a_Tok);
+ bool IsInfixOpTok(token_type &a_Tok);
+ bool IsFunTok(token_type &a_Tok);
+ bool IsPostOpTok(token_type &a_Tok);
+ bool IsOprt(token_type &a_Tok);
+ bool IsValTok(token_type &a_Tok);
+ bool IsVarTok(token_type &a_Tok);
+ bool IsStrVarTok(token_type &a_Tok);
+ bool IsUndefVarTok(token_type &a_Tok);
+ bool IsString(token_type &a_Tok);
+ void Error( EErrorCodes a_iErrc, int a_iPos = -1,
+ const string_type &a_sTok = string_type() ) const;
+ };
+} // namespace mu
+
+#endif
+
+