⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 muparserbase.cpp

📁 Mathematical expressions parser library
💻 CPP
📖 第 1 页 / 共 3 页
字号:
  #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 + -