📄 muparserbase.cpp
字号:
/*
Copyright (C) 2004, 2005 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[] =
{
"<=", ">=", "!=", "==", "<", ">", "+", "-", "*", "/",
"^", "and", "or", "xor", "=", "(", ")", ",", 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)
{
m_pTokenReader->SetVarCreator(a_pFactory);
}
//---------------------------------------------------------------------------
/** \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_strName,
const string_type &a_szCharSet) const
{
if ( !a_strName.length() ||
(a_strName.find_first_not_of(a_szCharSet)!=string_type::npos) ||
(a_strName[0]>='0' && a_strName[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)
{
m_pTokenReader->SetFormula(a_sExpr);
ReInit();
}
//---------------------------------------------------------------------------
/** \brief Add a user defined operator.
\post Will reset the Parser to string parsing mode.
*/
void ParserBase::DefinePostfixOprt(const string_type &a_strName, fun_type1 a_pFun, bool a_bAllowOpt)
{
AddCallback( a_strName,
ParserCallback(a_pFun, a_bAllowOpt),
m_PostOprtDef,
ValidOprtChars() );
}
//---------------------------------------------------------------------------
/** \brief Add a user defined operator.
\post Will reset the Parser to string parsing mode.
*/
void ParserBase::DefineInfixOprt(const string_type &a_strName, fun_type1 a_pFun, bool a_bAllowOpt)
{
AddCallback( a_strName,
ParserCallback(a_pFun, a_bAllowOpt),
m_InfixOprtDef,
ValidOprtChars() );
}
//---------------------------------------------------------------------------
void ParserBase::DefineOprt( const string_type &a_strName,
fun_type2 a_pFun,
unsigned a_iPri,
bool a_bAllowOpt )
{
// Check for conflicts with built in operator names
for (int i=0; m_bBuiltInOp && i<cmCOMMA; ++i)
if (a_strName == string_type(c_DefaultOprt[i]))
Error(ecBUILTIN_OVERLOAD);
AddCallback( a_strName,
ParserCallback(a_pFun, a_bAllowOpt, a_iPri),
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 -4;
case cmCOMMA: return -3;
case cmBO :
case cmBC : return -2;
case cmASSIGN: return -1;
case cmAND:
case cmXOR:
case cmOR: return 1;
case cmLT :
case cmGT :
case cmLE :
case cmGE :
case cmNEQ:
case cmEQ : return 2;
case cmADD:
case cmSUB: return 3;
case cmMUL:
case cmDIV: return 4;
case cmPOW: return 5;
// user defined binary operators
case cmBINOP: return a_Tok.GetPri();
default: Error(ecINTERNAL_ERROR);
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -