📄 muparserbase.cpp
字号:
#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
int iBrackets(0); // bracket level counter
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()) );
// If there is a function token that is no binary operator
// it is an infix operator execute it now!
if (stOpt.size() && stOpt.top().GetCode()!=cmBINOP)
ApplyFunc(stOpt, stVal, 1);
break;
case cmVAL:
stVal.push(opt);
m_vByteCode.AddVal( opt.GetVal() );
// If there is a function token that is no binary operator
// it is an infix operator
if (stOpt.size() && stOpt.top().GetCode()!=cmBINOP)
ApplyFunc(stOpt, stVal, 1);
break;
//
// Next are the binary operator entries
//
case cmBC: // For closing brackets make some syntax checks
if ( --iBrackets < 0 )
Error(ecUNEXPECTED_PARENS, m_pTokenReader->GetPos(), opt.GetAsString());
// no break; Fall through behaviour!
case cmCOMMA:
case cmEND:
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 cmBINOP:
if (opt.GetCode()==cmCOMMA)
{
if (stArgCount.empty())
Error(ecUNEXPECTED_COMMA, m_pTokenReader->GetPos());
++stArgCount.top(); // Record number of arguments
}
// a binary operator, a comma, a closing bracket or an end of expression
// has been found. Now it is necessary to check if a function token
// for a postfix operator is in the stack at the preceding position.
// if yes this must be a postfix operator. Deal with it now...
if (stOpt.size() && stOpt.top().GetCode()!=cmBINOP )
{
ApplyFunc(stOpt, stVal, 1); // postfix operator
if (stOpt.size() && stOpt.top().GetCode()!=cmBINOP)
ApplyFunc(stOpt, stVal, 1); // infix operator
}
// There must be at least two operator tokens available before we can start
// the calculation. It's necessary to compare their priorities
// Get the previous operator from the operator stack in order to find
// out if this operator can be applied (must have a higher priority)
if ( !stOpt.size() && opt.GetCode()!=cmEND )
{
stOpt.push(opt);
break;
}
// Order does matter in the while statement because Priority will fail
// if iErrc is set!
while ( stOpt.size() &&
stOpt.top().GetCode() != cmBO &&
stOpt.top().GetCode() != cmCOMMA &&
GetOprtPri(stOpt.top()) >= GetOprtPri(opt) )
{
ApplyBinOprt(stOpt, stVal);
} // while ( ... )
// 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
if ( stOpt.size() && stOpt.top().GetCode()==cmBO && opt.GetCode()==cmBC )
{
// 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) )
Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos());
ApplyFunc(stOpt, stVal, iArgCount);
if (stOpt.size() && stOpt.top().GetCode()!=cmBINOP)
ApplyFunc(stOpt, stVal, 1); // infix operator
break;
} // if bracket content is evaluated
// The operator can't be evaluated right now, push back to the operator stack
// CmdEND, CmdCOMMA will not be pushed back, they have done their job now
// (and triggerd evaluation of the formula or an expression used as function argument)
if (opt.GetCode()!=cmEND && opt.GetCode()!=cmCOMMA)
stOpt.push(opt);
break;
//
// Last section contains functions and operators implicitely mapped to functions
//
case cmBO: ++iBrackets; stArgCount.push(1);
case cmFUNC:
case cmFUNC_STR:
stOpt.push(opt);
break;
default: Error(ecINTERNAL_ERROR);
} // end of switch operator-token
if ( opt.GetCode() == cmEND )
{
m_vByteCode.Finalize();
break;
}
#if defined(MU_PARSER_DUMP_STACK)
StackDump(stVal, stOpt);
#endif
} // while (true)
// Store pointer to start of bytecode
m_pCmdCode = m_vByteCode.GetRawData();
#if defined(MU_PARSER_DUMP_CMDCODE)
m_vByteCode.AsciiDump();
#endif
// check bracket counter
if (iBrackets>0)
Error(ecMISSING_PARENS, m_pTokenReader->GetPos(), c_DefaultOprt[cmBC]);
// get the last value (= final result) from the stack
if (stVal.size()!=1)
Error(ecINTERNAL_ERROR);
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_strTok) const
{
throw exception_type(a_iErrc, a_strTok, 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("");
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.
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().
\throw nothrow
\sa m_bBuiltInOp, 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(MU_PARSER_DUMP_STACK) | defined(MU_PARSER_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
{
using std::cout;
ParserStack<token_type> stOprt(a_stOprt),
stVal(a_stVal);
cout << "\nValue stack:\n";
while ( !stVal.empty() )
{
token_type val = stVal.pop();
cout << " " << val.GetVal() << " ";
}
cout << "\nOperator stack:\n";
while ( !stOprt.empty() )
{
if (stOprt.top().GetType()<=cmXOR)
{
cout << "OPRT_INTRNL \""
<< ParserBase::c_DefaultOprt[stOprt.top().GetType()]
<< "\" ";
}
else
{
switch(stOprt.top().GetCode())
{
case cmVAR: cout << "VAR\n"; break;
case cmVAL: cout << "VAL\n"; break;
case cmFUNC: cout << "FUNC_NUM \""
<< stOprt.top().GetAsString()
<< "\"\n"; break;
case cmBINOP: cout << "OPRT_BIN \""
<< stOprt.top().GetAsString()
<< "\"\n"; break;
case cmFUNC_STR: cout << "FUNC_STR\n"; break;
case cmEND: cout << "END\n"; break;
case cmUNKNOWN: cout << "UNKNOWN\n"; break;
case cmBO: cout << "BRACKET \"(\"\n"; break;
case cmBC: cout << "BRACKET \")\"\n"; break;
default: cout << stOprt.top().GetType() << " "; break;
}
}
stOprt.pop();
}
cout <<endl;
}
#endif
} // namespace mu
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -