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

📄 muparsertest.cpp

📁 Mathematical expressions parser library
💻 CPP
📖 第 1 页 / 共 3 页
字号:
      iStat += EqnTest("2^log2(4)", 4, true);
	    iStat += EqnTest("-(sin(0)+1)", -1, true);
	    iStat += EqnTest("-(2^1.1)", -2.14354692, true);

	    iStat += EqnTest("(cos(2.41)/b)", -0.372056, true);

	    // 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("1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12", -7995810.09926, 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);
 	    
      if (iStat==0) 
        *m_stream << "passed" << endl;  
	    else 
        *m_stream << "\n  failed with " << iStat << " errors" << endl;

      return iStat;
	}


  //---------------------------------------------------------------------------
	int ParserTester::TestException()
	{
      int  iStat = 0;
      *m_stream << "testing error codes...";
    
      iStat += ThrowTest("3+",        ecUNEXPECTED_EOF);
      iStat += ThrowTest("3+)",       ecUNEXPECTED_PARENS);
      iStat += ThrowTest("sin(3,4)",  ecTOO_MANY_PARAMS);
      iStat += ThrowTest("3,4",       ecUNEXPECTED_COMMA);
      iStat += ThrowTest("if(3)",     ecTOO_FEW_PARAMS);
      iStat += ThrowTest("(1+2",      ecMISSING_PARENS);
      iStat += ThrowTest("sin(3)3",   ecUNEXPECTED_VAL);
      iStat += ThrowTest("sin(3)xyz", ecUNASSIGNABLE_TOKEN);
      iStat += ThrowTest("sin(3)cos(3)", ecUNEXPECTED_FUN);

      // String function related
      iStat += ThrowTest("valueof(\"xxx\")",  999, false);
      iStat += ThrowTest("valueof()",          ecUNEXPECTED_PARENS);
      iStat += ThrowTest("valueof(\"abc\"",    ecMISSING_PARENS);
      iStat += ThrowTest("valueof(\"abc",      ecUNTERMINATED_STRING);
      iStat += ThrowTest("valueof(\"abc\",3)", ecUNEXPECTED_COMMA);
      iStat += ThrowTest("valueof(3)",         ecSTRING_EXPECTED);
      iStat += ThrowTest("sin(\"abc\")",       ecVAL_EXPECTED);
      iStat += ThrowTest("valueof(\"\\\"abc\\\"\")",  999, false);
      iStat += ThrowTest("\"hello world\"",    ecSTR_RESULT);
      iStat += ThrowTest("(\"hello world\")",  ecSTR_RESULT);
      iStat += ThrowTest("\"abcd\"+100",       ecOPRT_TYPE_CONFLICT);
      iStat += ThrowTest("\"a\"+\"b\"",        ecOPRT_TYPE_CONFLICT);

      // assignement operator
      iStat += ThrowTest("3=4", ecUNEXPECTED_OPERATOR);
      iStat += ThrowTest("sin(8)=4", ecUNEXPECTED_OPERATOR);
      iStat += ThrowTest("\"test\"=a", ecUNEXPECTED_OPERATOR);
      iStat += ThrowTest("sin=9", ecUNEXPECTED_OPERATOR);
      iStat += ThrowTest("(8)=5", ecUNEXPECTED_OPERATOR);
      iStat += ThrowTest("(a)=5", ecUNEXPECTED_OPERATOR);
      iStat += ThrowTest("a=\"tttt\"", ecOPRT_TYPE_CONFLICT);

      if (iStat==0) 
        *m_stream << "passed" << endl;
	    else 
        *m_stream << "\n  failed with " << iStat << " errors" << endl;

      return iStat;
  }

  
  //---------------------------------------------------------------------------
	void ParserTester::AddTest(testfun_type a_pFun)
	{
		m_vTestFun.push_back(a_pFun);
	}

  //---------------------------------------------------------------------------
  /** \brief Set the stream that takes the output of the test session. */
  void ParserTester::SetStream(std::ostream *a_stream)
  {
    assert(a_stream);

    m_stream = a_stream;
  }

  //---------------------------------------------------------------------------
	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)
    {
      *m_stream << e.GetMsg() << endl;
      *m_stream << e.GetToken() << endl;
      Abort();
    }
    catch(std::exception &e)
    {
      *m_stream << e.what() << endl;
      Abort();
    }
    catch(...)
    {
      *m_stream << "Internal error";
      Abort();
    }

	  if (iStat==0) 
    {
      *m_stream << "Test passed (" <<  ParserTester::c_iCount << " expressions)" << endl;
    }
    else 
    {
      *m_stream << "Test failed with " << iStat 
                << " errors (" <<  ParserTester::c_iCount 
                << " expressions)" << endl;
    }
    ParserTester::c_iCount = 0;
	}


  //---------------------------------------------------------------------------
  int ParserTester::ThrowTest(const std::string &a_str, int a_iErrc, bool a_bFail)
  {
    double fRes(0);
    
    ParserTester::c_iCount++;
    
    try
    {
      double fVal=0;
      Parser p;

      p.DefineVar("a", &fVal);
      p.DefineFun("valueof", ValueOf);
		  p.SetExpr(a_str);
      fRes = p.Eval();
    }
    catch(Parser::exception_type &e)
    {
      // output the formula in case of an failed test
      if (a_bFail==true && a_iErrc!=e.GetCode() )
      {
        cout << "\n  " 
             << "Expression: " << a_str 
             << "  Code:" << e.GetCode() 
             << "  Expected:" << a_iErrc;
      }

      return (a_iErrc==e.GetCode()) ? 0 : 1;
    }

    // if a_bFail==false no exception is expected
    return (a_bFail==false) ? 0 : 1; 
  }

  //---------------------------------------------------------------------------
	/** \brief Evaluate a tet expression. 

      \return 1 in case of a failure, 0 otherwise.
  */
  int ParserTester::EqnTest(const std::string &a_str, double a_fRes, bool a_fPass)
  {
    ParserTester::c_iCount++;

    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("pi", (value_type)PARSER_CONST_PI);
	    p1->DefineConst("e", (value_type)PARSER_CONST_E);
      p1->DefineConst("const", 1);
      p1->DefineConst("const1", 2);
      p1->DefineConst("const2", 3);
      // variables
      value_type vVarVal[] = { 1, 2, 3, -2};
      p1->DefineVar("a", &vVarVal[0]);
      p1->DefineVar("aa", &vVarVal[1]);
      p1->DefineVar("b", &vVarVal[1]);
      p1->DefineVar("c", &vVarVal[2]);
      p1->DefineVar("d", &vVarVal[3]);
      // functions
      p1->DefineFun("f1of1", f1of1);  // one parameter
	    p1->DefineFun("f1of2", f1of2);  // two parameter
      p1->DefineFun("f2of2", f2of2);
      p1->DefineFun("f1of3", f1of3);  // three parameter
      p1->DefineFun("f2of3", f2of3);
      p1->DefineFun("f3of3", f3of3);
      p1->DefineFun("f1of4", f1of4);   // four parameter 
      p1->DefineFun("f2of4", f2of4);
      p1->DefineFun("f3of4", f3of4);
      p1->DefineFun("f4of4", f4of4);
      p1->DefineFun("f1of5", f1of5);   // five parameter
      p1->DefineFun("f2of5", f2of5);
      p1->DefineFun("f3of5", f3of5);
      p1->DefineFun("f4of5", f4of5);
      p1->DefineFun("f5of5", f5of5);
      // sample functions
      p1->DefineFun("min", Min);
      p1->DefineFun("max", Max);
      p1->DefineFun("sum", Sum);
      p1->DefineFun("valueof", ValueOf);
      p1->DefineFun("atof", StrToFloat);

      // infix / postfix operator
      p1->DefineInfixOprt("~", plus2);
      p1->DefinePostfixOprt("m", Milli);
      p1->DefinePostfixOprt("#", times3);
	    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("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(exception &e)
	    {
	      *m_stream << "\n  " << e.what() << "\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));
	  	}

      return ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
	  }
    catch(Parser::exception_type &e)
	  {
	    if (a_fPass)
        *m_stream << "\n  " << e.GetExpr() << " : " << e.GetMsg();	
	  }
    catch(std::exception &e)
    {
     *m_stream << "\n  " << a_str << " : " << e.what() << "\n";
     
      // always return a failure since this exception is not expected
      return 1;
    }
    catch(...)
	  {
      // exceptions other than ParserException are not allowed
      
      *m_stream << "\n  \"" << a_str << "\" : " << "Unexpected Eception";
      return 1;
    }

	  return (a_fPass==false) ? 0 : 1;
	}

  //---------------------------------------------------------------------------
  int ParserTester::EqnTestInt(const std::string &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
    
    try
	  {
	    ParserInt p;
	    p.DefineConst("const1", 1);
	    p.DefineConst("const2", 2);
      p.DefineVar("a", &vVarVal[0]);
      p.DefineVar("b", &vVarVal[1]);
      p.DefineVar("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("Bytecode corrupt.");

		  return ( (a_fRes==fVal[0] &&  a_fPass) || 
               (a_fRes!=fVal[0] && !a_fPass) ) ? 0 : 1;
	  }
    catch(Parser::exception_type &e)
	  {
	    if (a_fPass)
        *m_stream << "\n  " << e.GetExpr() << " : " << e.GetMsg();	
	  }
	  catch(...)
	  {
      return 1;
    }

    return (a_fPass==false) ? 0 : 1;
	}

  //---------------------------------------------------------------------------
  /** \brief Internal error in test class Test is going to be aborted. */
  void ParserTester::Abort() const
  {
    *m_stream << "Test failed (internal error in test class)" << endl;
    while (!getchar());
    exit(-1);
  }

} // namespace test

} // namespace mu



⌨️ 快捷键说明

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