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

📄 muparserbase.cpp

📁 Mathematical expressions parser library
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//---------------------------------------------------------------------------
/** \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)a_FunTok.GetFuncAddr())(a_vArg[0].GetVal()) );  break; 
    case 2: valTok.SetVal( ((fun_type2)a_FunTok.GetFuncAddr())(a_vArg[1].GetVal(),
		                                                           a_vArg[0].GetVal()) );  break;
    case 3: valTok.SetVal( ((fun_type3)a_FunTok.GetFuncAddr())(a_vArg[2].GetVal(), 
		                                                           a_vArg[1].GetVal(), 
														                                   a_vArg[0].GetVal()) );  break;
    case 4: valTok.SetVal( ((fun_type4)a_FunTok.GetFuncAddr())(a_vArg[3].GetVal(), 
	                                                             a_vArg[2].GetVal(), 
				   	  	                                               a_vArg[1].GetVal(),
													                                     a_vArg[0].GetVal()) );  break;
    case 5: valTok.SetVal( ((fun_type5)a_FunTok.GetFuncAddr())(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);
  }

  // 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,
                                                token_type &a_Arg) const
{
  if (a_Arg.GetCode()!=cmSTRING)
    Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString());

  strfun_type1 pFunc = (strfun_type1)a_FunTok.GetFuncAddr();
  assert(pFunc);
  
  value_type fResult = pFunc( a_Arg.GetAsString().c_str() );
  
  // Formula optimization
  if ( m_bOptimize &&        !a_FunTok.IsFlagSet(token_type::flVOLATILE) ) 	{
    m_vByteCode.AddVal( fResult );
	}
	else 
	{ 
    // operation dosnt depends on a variable or the function is flagged unoptimizeable
    // we cant optimize here...
    m_vByteCode.AddStrFun((void*)pFunc, a_FunTok.GetArgCount(), a_Arg.GetIdx());
	}
  
  a_Arg.SetVal(fResult);
  
  return a_Arg;
}

//---------------------------------------------------------------------------
/** \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()==cmBINOP ) ? funTok.GetArgCount() : a_iArgCount;

  if (funTok.GetArgCount()>0 && iArgCount>funTok.GetArgCount()) 
	    Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());

	if ( funTok.GetCode()!=cmBINOP && iArgCount<funTok.GetArgCount() )
	    Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString());

  // Collect the 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());
  }

#ifdef __BORLANDC__
  // Borland C++ Compiler does not support taking references on
  // unnamed temporaries
  if (funTok.GetType()==tpSTR) {
    ParserToken<double,std::string> pt = ApplyStrFunc(funTok, stArg.back());
    a_stVal.push(pt);
  }
  else {
    ParserToken<double,std::string> pt = ApplyNumFunc(funTok, stArg);
    a_stVal.push(pt);
  }
#else
  // String functions accept only one parameter
  a_stVal.push( (funTok.GetType()==tpSTR) ?
                      ApplyStrFunc(funTok, stArg.back()) :
                      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()==cmBINOP)
  {
     ApplyFunc(a_stOpt, a_stVal, 2);
  }
  else
  {
    // internal binary operator
    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);
                    
                  double *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);
    }

    // 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;
  int_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, "", m_pTokenReader->GetFormula(), -1);
  }
#endif
//  assert(idx<99); // Formula too complex

  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 cmBINOP: 
           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]) );
		        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:
            {
              i++; // skip the unused argument count
              strfun_type1 pFun = *(strfun_type1*)(&m_pCmdCode[i]);
              i += m_vByteCode.GetPtrSize();

              int iIdxStack = (int)m_pCmdCode[i++];
#if defined(_DEBUG)  
              if ( (iIdxStack<0) || (iIdxStack>=(int)m_vStringBuf.size()) )
                Error(ecINTERNAL_ERROR);
#endif  
              Stack[idx] = pFun(m_vStringBuf[iIdxStack].c_str());
            }
            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);

                  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);
            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)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -