www.gusucode.com > 一个VC++ GUI测试程序-源码程序 > 一个VC++ GUI测试程序-源码程序/code/MathParser.cpp

    //unit Parser;
// Download by http://www.codefans.net
/*==========================================================================*/
/* Expression Evaluator v1.4 for Delphi                                     */
/* (16 & 32 bits)                                                           */
/*                                                                          */
/* Copyright ? 1997 by BitSoft Development, L.L.C.                          */
/* All rights reserved                                                      */
/*                                                                          */
/* Web:     http://www.bitsoft.com                                          */
/* E-mail:  info@bitsoft.com                                                */
/* Support: tech-support@bitsoft.com                                        */
/*--------------------------------------------------------------------------*/
/* Portions Copyright ? 1992 by Borland International, Inc.                 */
/* All rights reserved                                                      */
/*--------------------------------------------------------------------------*/
/* This file is distributed as freeware and without warranties of any kind. */
/* You can use it in your own applications at your own risk.                */
/* See the License Agreement for more information.                          */
/*==========================================================================*/

/*===========PASCAL => C++*       WUZHIQIANG 1999/2/8 ======================*/


#include "stdafx.h"
#include "MathParser.h"
#include "math.h"


CMathParser::CMathParser(CString s)
{
	FInput = s;
}

CMathParser::~CMathParser()
{
	while(m_VarList.IsEmpty() != TRUE)
		delete m_VarList.RemoveHead();
}


WORD CMathParser::GotoState(WORD Production)/* Finds the new state based on the just-completed production and the top state. */
{
  WORD  State;
  WORD  ResultGotoState;	

  State = Stack[StackTop].State;

  if (Production <= 3) 
  {
	  switch(State)
	  {
		  case 0 : ResultGotoState = 1;
					break;	
		  case 9 : ResultGotoState = 19;
					break;
		  case 20 : ResultGotoState = 28;
					break;
	  }
  }
  else if(Production <= 6)
  {
	  switch(State)
	  {
	  case 0:
	  case 9:
	  case 20: 
		  ResultGotoState = 2;
		  break;
      case 12 : 
		  ResultGotoState = 21;
		  break;
      case 13 : 
		  ResultGotoState = 22;
		  break;
    
	  }
  }
  else if( (Production <= 8) || (Production == 100))
  { //begin
    switch(State)
	{
	case 0:
	case 9:
	case 12:
	case 13:
	case 20:
		ResultGotoState = 3;
		break;
    case 14 : 
		ResultGotoState = 23;
		break;
    case 15 : 
		ResultGotoState = 24;
		break;
    case 16 : 
		ResultGotoState = 25;
		break;
    case 40 : 
		ResultGotoState = 80;
		break;
    }
  }
  else if (Production <= 10)
  {//  begin
	switch(State)
	{
    case 0:
	case 9:
	case 12:
	case 13:
	case 14:
	case 15:
	case 16:
	case 20:
	case 40:
		ResultGotoState = 4;
	}
  }
  else if( Production <= 12 )
  {
	  switch(State)
	  {
	  case 0:
	  case 9:
	  case 12:
	  case 13:
	  case 14:
	  case 15:
	  case 16:
	  case 20:
	  case 40:
		ResultGotoState = 6;
		break;
	  case 5:
		ResultGotoState = 17;
	  }
  }
  else 
  {
    switch(State)
	{
	case 0:
	case 5:
	case 9:
	case 12:
	case 13:
	case 14:
	case 15:
	case 16:
	case 20:
	case 40:
      ResultGotoState = 8;
    }
  }

  return ResultGotoState;
} 

BOOL CMathParser::IsFunc(CString S)//{ Checks to see if the parser is about to read a function }
{
  WORD P, SLen;
  CString FuncName;
  BOOL bIsFunc;

  P = Position;
  FuncName = "";

  while (P < FInput.GetLength())// && (FInput[P] in ['A'..'Z', 'a'..'z', '0'..'9', '_']) 
  {
	  if(!((FInput.GetAt(P) <= 'Z' && FInput.GetAt(P) >= 'A')
		  ||(FInput.GetAt(P) <= 'z' && FInput.GetAt(P) >= 'a')
		  ||(FInput.GetAt(P) <= '9' && FInput.GetAt(P) >= '0')
		  ||(FInput.GetAt(P) == '_')))
		  break;

	 //FInput.SetAt(P, FInput.GetAt(P));
     FuncName = FuncName + FInput.GetAt(P);//[P];
     P++;//Inc(P);
  }//  end; { while }

  FuncName.MakeUpper();
  if (FuncName ==S )//Uppercase(FuncName) = S
  {
      SLen = S.GetLength();
      CurrToken.FuncName = FInput.Mid(Position, SLen);
	  CurrToken.FuncName.MakeUpper();
	  Position += SLen;
      //Inc(Position, SLen);
      bIsFunc = TRUE;
  }
  else bIsFunc = FALSE;

  return bIsFunc;
}

BOOL CMathParser::IsVar(Extended &Value)
{
  CString VarName;
  BOOL VarFound;

  VarFound = FALSE;
  VarName = "";

  while ((Position < FInput.GetLength()) && (
	  (FInput.GetAt(Position) >= 'A' && FInput.GetAt(Position) <= 'Z')
	  ||(FInput.GetAt(Position) >= 'a' && FInput.GetAt(Position) <= 'z')
	  ||(FInput.GetAt(Position) >= '0' && FInput.GetAt(Position) <= '9')
	  ||(FInput.GetAt(Position) == '_')
	  ))//	  in ['A'..'Z',  'a'..'z', '0'..'9', '_']) do
  {
    VarName = VarName + FInput.GetAt(Position);
    Position++;
  }
  
  if( GetVar(VarName, Value) == TRUE)
	  return TRUE;
     
  return FALSE;
}

TokenTypes CMathParser::NextToken()//{ Gets the next Token from the Input stream }
{
  CString NumString;// : String[80];
  WORD FormLen, Place, TLen, NumLen ;
  int Check ;//: Integer;
  char Ch;//, FirstChar;
  BOOL Decimal ;
  TokenTypes ResultNextToken;

   while ((Position < FInput.GetLength()) && (FInput.GetAt(Position) == ' '))
     Position++;
   TokenLen = Position;
   if (Position >= FInput.GetLength())
   {
     ResultNextToken = EOL;
     TokenLen = 0;
     return ResultNextToken;
   }

   FInput.MakeUpper();

   Ch = FInput.GetAt(Position);
   if (Ch== '!')
   {
      ResultNextToken = ERR;
      TokenLen = 0;
      return ResultNextToken ;
   }

   if((Ch >= '0' && Ch <= '9') || Ch == '.')//   if Ch in ['0'..'9', '.'] then
   {
     NumString = "";
     TLen = Position;
     Decimal = FALSE;

     while ((TLen < FInput.GetLength()) &&
           ((FInput.GetAt(TLen) >= '0' && FInput.GetAt(TLen) <= '9' ) ||
            ((FInput.GetAt(TLen) == '.') && (!Decimal)))) 
     {
       NumString = NumString + FInput.GetAt(TLen);
       if (Ch == '.')// then
         Decimal = TRUE;
       TLen++;//Inc(TLen);
     }

     if ((TLen == 2) && (Ch == '.'))// then
     {
       ResultNextToken = BAD;
       TokenLen = 0;
       return ResultNextToken ;
     }

     if ((TLen < FInput.GetLength()) && ((FInput.GetAt(TLen)) == 'E'))// then
	 {
       NumString = NumString + 'E';
       TLen++;
       
	   if( FInput.GetAt(TLen) == '+' || FInput.GetAt(TLen) == '-')// in ['+', '-'] then
       {
         NumString.SetAt(TLen, FInput.GetAt(TLen));//= NumString + FInput[TLen];
         TLen++;
       }

       NumLen = 1;
       while ((TLen < FInput.GetLength()) && (FInput.GetAt(TLen) >= '0' && FInput.GetAt(TLen) <= '9') &&
             (NumLen <= MaxExpLen)) 
       {
         NumString = NumString + FInput.GetAt(TLen);
         NumLen++;//Inc(NumLen);
         TLen++;//Inc(TLen);
       }
     }

     if (NumString[0] == '.')// then
       NumString = '0' + NumString;

	 CurrToken.Value = atof(NumString);
     //Val(NumString, CurrToken.Value, Check);

     /*//if (Check != 0 )
	 {//    begin
         MathError = TRUE;
         TokenError = ErrInvalidNum;
		 Position += Pred(Check);
         //Inc(Position, Pred(Check));
     }//  end { if }
     else*/
     {//  begin
         ResultNextToken = NUM;
		 Position += NumString.GetLength();
         //Inc(Position, System.Length(NumString));
         TokenLen = Position - TokenLen;
      }// end; { else }
     return ResultNextToken;
   }//end { if }
   else if ((Ch>='a' && Ch <= 'z')
	   || (Ch>='A' && Ch <= 'Z'))//in Letters then
   {//   begin
     if (IsFunc("ABS") ||
        IsFunc("ATAN") ||
        IsFunc("COS") ||
        IsFunc("EXP") ||
        IsFunc("LN") ||
        IsFunc("ROUND") ||
        IsFunc("SIN") ||
        IsFunc("SQRT") ||
        IsFunc("SQR") ||
        IsFunc("TRUNC")||
		IsFunc("NOT")||// then//EXPAND
		IsFunc("BOOL")||
		IsFunc("SGN")
		)
     {
       ResultNextToken = FUNC;
       TokenLen = Position - TokenLen;
       return ResultNextToken ;
     }

     if (IsFunc("MOD")) 
     {
       ResultNextToken = MODU;
       TokenLen = Position - TokenLen;
       return ResultNextToken ;
     }
     if (IsVar(CurrToken.Value))
     {
        ResultNextToken = NUM;
        TokenLen = Position - TokenLen;
        return ResultNextToken;
     }
     else 
	 {
       ResultNextToken = BAD;
       TokenLen = 0;
       return ResultNextToken ;
      }
   }
   else 
   {//   begin
	   switch(Ch)
	   {
     
      case  '+' : ResultNextToken = PLUS; break;
      case  '-' : ResultNextToken = MINUS; break;
      case  '*' : ResultNextToken = TIMES; break;
      case  '/' : ResultNextToken = DIVIDE; break;
      case  '^' : ResultNextToken = EXPO; break;
      case  '(' : ResultNextToken = OPAREN; break;
      case  ')' : ResultNextToken = CPAREN; break;
      default:
         ResultNextToken = BAD;
         TokenLen = 0;
         return ResultNextToken ;
       
     }//end; { case }
     Position++;
     TokenLen = Position - TokenLen;
     return ResultNextToken ;
   }//end; { else if }
}//end; { NextToken }

void CMathParser::Pop(TokenRec &Token)//{ Pops the top Token off of the stack }
{
  Token = Stack[StackTop];
  StackTop--;
}

void CMathParser::Push(TokenRec Token)//{ Pushes a new Token onto the stack }
{
  if (StackTop == ParserStackSize-1)// then
    TokenError = ErrParserStack;
  else 
  {
	StackTop++; 
    Stack[StackTop] = Token;
  }
}

void CMathParser::Parse()//{ Parses an input stream }
{

  TokenRec FirstToken ;
  BOOL Accepted;

  Position = 0;//1
  StackTop = -1;
  TokenError = 0;
  MathError = FALSE;
  ParseError = FALSE;
  Accepted = FALSE;
  FirstToken.State = 0;
  FirstToken.Value = 0;

  Push(FirstToken);
  TokenType = NextToken();

  do{//repeat
	  switch(Stack[StackTop].State)
	  {
	  case 0:
	  case 9:
	  case 12:
	  case 13:
	  case 14:
	  case 15:
	  case 16:
	  case 20:
	  case 40 : 
		{//begin
        if (TokenType == NUM)
          Shift(10);
        else if (TokenType == FUNC)
          Shift(11);
        else if (TokenType == MINUS)
          Shift(5);
        else if (TokenType == OPAREN)
          Shift(9);
        else if (TokenType == ERR)
		{//    begin
             MathError = TRUE;
             Accepted = TRUE;
         }// end { else if }
        else 
		{//begin
          TokenError = ErrExpression;
		  Position -= TokenLen;
          //Dec(Position, TokenLen);
        }//end; { else }
		break;
      }//end; { case of }
      case 1 : 
		{//begin
        if (TokenType == EOL)
          Accepted = TRUE;
        else if (TokenType == PLUS)
          Shift(12);
        else if (TokenType == MINUS)
          Shift(13);
        else 
		{//begin
          TokenError = ErrOperator;
		  Position -= TokenLen;
          //Dec(Position, TokenLen);
		}//end { else }
		break;
      }//end; { case of }
     case 2 : 
	{//begin
        if (TokenType == TIMES)
          Shift(14);
        else if (TokenType == DIVIDE)
          Shift(15);
        else
          Reduce(3);
		break;
      }//end; { case of }
     case 3 :
	{
       if( TokenType == MODU)
         Shift(40);
       else
         Reduce(6);
	   break;
      }//end; { case of }
     case 4 : 
	{//begin
       if (TokenType == EXPO)
         Shift(16);
       else
         Reduce(8);
	   break;
      }//end; { case of }
     case 5 : 
	{//begin
        if (TokenType == NUM)
          Shift(10);
        else if (TokenType = FUNC )
          Shift(11);
        else if (TokenType = OPAREN)
          Shift(9);
        else
		{
            TokenError = ErrExpression;
			Position -= TokenLen;
            //Dec(Position, TokenLen);
         }// end; { else }
		break;
	}//  end; { case of }
     case 6 : Reduce(10); break;
     case 7 : Reduce(13); break;
     case 8 : Reduce(12); break;
     case 10 : Reduce(15); break;
     case 11 : 
	{//begin
        if (TokenType == OPAREN)
          Shift(20);
        else
		{//          begin
            TokenError = ErrOpenParen;
			Position -= TokenLen;
            //Dec(Position, TokenLen);
         }//end; { else }
		break;
      }//end; { case of }
    case 17 : Reduce(9); break;
    case  18 : break;//raise Exception.Create('Bad token state'); break;
    case  19 : 
	{//begin
        if (TokenType == PLUS)
          Shift(12);
        else if (TokenType == MINUS)
          Shift(13);
        else if (TokenType == CPAREN)
          Shift(27);
        else
		{//begin
            TokenError = ErrOpCloseParen;
			Position -= TokenLen;
            //Dec(Position, TokenLen);
		}// end;
		break;
      }//end; { case of }
     case 21 : 
	 {// begin
        if (TokenType == TIMES)
          Shift(14);
        else if (TokenType == DIVIDE)
          Shift(15);
        else
          Reduce(1);
		break;
      }//end; { case of }
     case 22 : //begi
	 {
        if (TokenType == TIMES)
          Shift(14);
        else if (TokenType == DIVIDE)
          Shift(15);
        else
          Reduce(2);
		break;
      }//end; { case of }
     case 23 : Reduce(4); break;
     case 24 : Reduce(5); break;
     case 25 : Reduce(7); break;
     case 26 : Reduce(11); break;
     case 27 : Reduce(14); break;
     case 28 : 
	{
        if (TokenType == PLUS)
          Shift(12);
        else if (TokenType == MINUS)
          Shift(13);
        else if (TokenType == CPAREN)
          Shift(29);
        else
		{//  begin
            TokenError = ErrOpCloseParen;
			Position -= TokenLen;
            //Dec(Position, TokenLen);
         }// end; { else }
		break;
      }//end; { case of }
     case 29 : Reduce(16); break;
     case 80 : Reduce(100); break;
	 }
    }while( !Accepted && (TokenError == 0));//end; { case }

  if (TokenError != 0 )
  {//  begin
      if (TokenError == ErrBadRange )
		  Position -= TokenLen;
        //Dec(Position, TokenLen);
      //if( Assigned(FOnParseError))
        //FOnParseError(Self, TokenError);
  }//end; { if }
  if (MathError || (TokenError != 0))// then
  {//  begin
    ParseError = TRUE;
    ParseValue = 0;
    return;
  }//end; { if }
  ParseError = FALSE;
  ParseValue = Stack[StackTop].Value;
}//end; { Parse }

void CMathParser::Reduce(WORD  Reduction)//{ Completes a reduction }
{
  TokenRec Token1, Token2;


  switch(Reduction)
  {
  case 1 : 
	  {
      Pop(Token1);
      Pop(Token2);
      Pop(Token2);
      CurrToken.Value = Token1.Value + Token2.Value;
	  break;
	  }//  end;
   case 2 : {//begin
      Pop(Token1);
      Pop(Token2);
      Pop(Token2);
      CurrToken.Value = Token2.Value - Token1.Value;
	  break;
	}//    end;
   case 4 :// begin
	{
      Pop(Token1);
      Pop(Token2);
      Pop(Token2);
      CurrToken.Value = Token1.Value * Token2.Value;
	  break;
	}//    end;
   case 5 : //begin
	{
      Pop(Token1);
      Pop(Token2);
      Pop(Token2);
      if (fabs(Token1.Value) < 0.000001 )
        MathError = TRUE;
      else
        CurrToken.Value = Token2.Value / Token1.Value;
	  break;
	}//    end;

    //{ MOD operator }
    case 100 : //begin
	{
      Pop(Token1);
      Pop(Token2);
      Pop(Token2);
      if (fabs(Token1.Value) < 0.000001)
        MathError = TRUE;
      else
        CurrToken.Value = Round(Token2.Value) % Round(Token1.Value);
	  break;
    }//end;

    case 7 :
	{
      Pop(Token1);
      Pop(Token2);
      Pop(Token2);
      if (Token2.Value < 0.0)
        MathError = TRUE;
      else if ((Token1.Value * log(Token2.Value) < -ExpLimit) ||
              (Token1.Value * log(Token2.Value) > ExpLimit)) 
        MathError = TRUE;
      else
        CurrToken.Value = exp(Token1.Value * log(Token2.Value));
	  break;
    }//end;
    case 9 : 
	{//begin
      Pop(Token1);
      Pop(Token2);
      CurrToken.Value = -Token1.Value;
	  break;
    }//end;
    case 11 : break;//raise Exception.Create('Invalid reduction'); break;
    case 13 : break;//raise Exception.Create('Invalid reduction'); break;
    case 14 : 
	{//begin
      Pop(Token1);
      Pop(CurrToken);
      Pop(Token1);
	  break;
    }//end;
    case 16 : 
	{//begin
      Pop(Token1);
      Pop(CurrToken);
      Pop(Token1);
      Pop(Token1);
      if( Token1.FuncName == "ABS")
        CurrToken.Value = fabs(CurrToken.Value);
      else if (Token1.FuncName == "ATAN")
        CurrToken.Value = atan(CurrToken.Value);
      else if (Token1.FuncName == "COS")
	  {//      begin
         if ((CurrToken.Value < -9E18) || (CurrToken.Value > 9E18))
            MathError = TRUE;
         else
            CurrToken.Value = cos(CurrToken.Value);
	  }//end {...if Token1.FuncName = 'SIN' }
      else if (Token1.FuncName == "EXP")
	  {//      begin
        if ((CurrToken.Value < -ExpLimit) || (CurrToken.Value > ExpLimit))// then
          MathError = TRUE;
        else
          CurrToken.Value = exp(CurrToken.Value);
      }//end
      else if (Token1.FuncName == "LN")// then
	  {//      begin
        if (CurrToken.Value <= 0)
          MathError = TRUE;
        else
          CurrToken.Value = log(CurrToken.Value);
      }//end
      else if (Token1.FuncName == "ROUND")
	  {//     begin
        if ((CurrToken.Value < -1E9) || (CurrToken.Value > 1E9))
          MathError = TRUE;
        else
          CurrToken.Value = Round(CurrToken.Value);
      }//end
      else if (Token1.FuncName == "SIN")
	  {//      begin
         if( (CurrToken.Value < -9E18) || (CurrToken.Value > 9E18))
            MathError = TRUE;
         else
            CurrToken.Value = sin(CurrToken.Value);
		 }//end {...if Token1.FuncName = 'SIN' }
      else if (Token1.FuncName == "SQRT")
      {//begin
        if( CurrToken.Value < 0 )//then
          MathError = TRUE;
        else
          CurrToken.Value = sqrt(CurrToken.Value);
      }//end
      else if (Token1.FuncName == "SQR")
      {//begin
        if ((CurrToken.Value < -SQRLIMIT) || (CurrToken.Value > SQRLIMIT))// then
          MathError = TRUE;
        else
          CurrToken.Value = sqrt(CurrToken.Value);
      }//end
      else if (Token1.FuncName == "TRUNC")
      {//begin
        if ((CurrToken.Value < -1E9) || (CurrToken.Value > 1E9))
          MathError = TRUE;
        else
          CurrToken.Value = (int)(CurrToken.Value);//Trunc
      }
	  else if(Token1.FuncName == "NOT")//end;//EXPAND
	  {
		if (CurrToken.Value < 0.001 && CurrToken.Value > -0.001)
			CurrToken.Value = 1.0;
		else 
			CurrToken.Value = 0.0;
	  }
	  else if(Token1.FuncName == "BOOL")//end;//EXPAND
	  {
		if (CurrToken.Value < 0.001 && CurrToken.Value > -0.001)
			CurrToken.Value = 0.0;
		else 
			CurrToken.Value = 1.0;
	  }
	  else if(Token1.FuncName == "SGN")//end;//EXPAND
	  {
		if (CurrToken.Value > 0.0)
			CurrToken.Value = 1.0;
		else 
			CurrToken.Value = 0;
	  }
	  break;
    }//end;
	case 3:
	case 6:
	case 8:
	case 10:
	case 12:
	case 15 : Pop(CurrToken); break;
  }//  end; { case }

  CurrToken.State = GotoState(Reduction);
  Push(CurrToken);
}

void CMathParser::Shift(WORD State)//{ Shifts a Token onto the stack }
{
   CurrToken.State = State;
   Push(CurrToken);
   TokenType = NextToken();
}


int CMathParser::Round(double value)
{
	int result1, result2;
	if(value > 0.0)
	{
		result1 = (int)value;
		result2 = result1 + 1;
		if( value - (double)result1 > (double)result2 - value)
			return result2;
		else result1;
	}
	else
	{
		result1 = (int)value;
		result2 = result1 - 1;
		if( value - (double)result2 > (double)result1 - value)
			return result1;
		else result2;
	}
	return 0;
}

void CMathParser::AddVar(Extended Value, CString  VarName)
{
	VARSTRU *pvar = new VARSTRU;

	pvar->Value = Value;
	lstrcpy(pvar->VarName, VarName.GetBuffer(29));
	m_VarList.AddTail(pvar);
}

BOOL CMathParser::GetVar(CString VarName, Extended &Value)
{
	BOOL bFound;
	POSITION pos;

	if(m_VarList.IsEmpty() == TRUE)  return FALSE;

	bFound = FALSE;
	VarName.MakeUpper();
	
	VARSTRU *pvar;
	CString str;

	for( pos = m_VarList.GetHeadPosition(); pos != NULL; )    
	{
		pvar = (VARSTRU *)m_VarList.GetNext( pos );
		str = CString(pvar->VarName);

		str.MakeUpper();
		if(str == VarName)
		{
			Value =  pvar->Value;
			bFound = TRUE;
			break;
		}
	}

	return bFound;

}