Visual Basic, C & C++
분류 Delphi

델파이 eval 함수 비슷하게 구현

페이지 정보

본문

{

 You asked for something simple. But to evaluate an expression it's not that simple 'cause

 it envolves parsing a string and deal with all those tokens within an expression.

 // 

 Now. It's done. It is that simple..

 //

 Label.Caption := IntToStr( Eval( '(10   -2) + 50   (3+5)' ));

 //

 As you see this code supports parenteses and negative numbers.

 //





}





//>>>>

// This a support unit...

unit Stack;



INTERFACE



Uses Windows, Classes;



Const

  // This is more than enough for an expression.

  MaxStackSize = 1023;



Type

  TStack  =  class( TObject )

  private

     items : Array[0..MaxStackSize] of Integer;

     StkPtr : Integer;

  public

     procedure Reset;

     procedure AddItem( Item : Integer );

     function GetItem : Integer;

     function StackSize : Integer;

     function TestItem : Integer;

  end;



implementation



procedure TStack.Reset;

 StkPtr := MaxStackSize;

end;



procedure TStack.AddItem( Item : Integer );

begin

 Items[ StkPtr ] := Item;

 Dec( StkPtr );

end;



function TStack.GetItem : Integer;

begin

 Inc( StkPtr );

 GetItem := Items[ StkPtr ];

end;



function TStack.TestItem : Integer;

begin

 TestItem := Items[ StkPtr + 1 ];

end;



function TStack.StackSize : Integer;

begin

 StackSize := MaxStackSize - StkPtr;

end;



end.

// eof support unit

//>>>





//>>>

//  This is the main program...

// There is a label and a button on this form..

//

unit EvalUnit1;

interface



uses

 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Stack,

 StdCtrls;





Const

  Number = 0;

  TokError = 1;

  Plus = 2;

  Minus = 3;

  Times = 4;

  Divide = 5;

  LParen = 6;

  RParen = 7;



type

 TForm1 = class(TForm)

   Label1: TLabel;

   Button1: TButton;

   procedure FormDestroy(Sender: TObject);

   procedure FormCreate(Sender: TObject);

   procedure Button1Click(Sender: TObject);

 private

    Expression  : String;

    i, Code     : Integer;

    TokenPos    : Integer;

    Token       : String;

    TokenType   : Integer;

    MinusFlag   : Boolean;

    Arg1,Arg2   : Integer;

    procedure GetToken;

    function Eval( ExpressionToEvaluate : String ) : Integer;

 public

    Numbers     : TStack;

    Operators   : TStack;

 end;



var

 Form1: TForm1;



implementation

{$R  .DFM}



{Get the token the expression string}

procedure TForm1.GetToken;

begin

 {Clear the token string }

 Token := '';

 { if the expression has a digit, it's a number }

 if ( Ord( Expression[TokenPos]) >= Ord('0'))

     AND ( Ord( Expression[TokenPos] ) <= Ord('9')) then

  begin

       { Keep getting digits }

       repeat

          Token := Token + Expression[TokenPos];

          Inc(TokenPos);

       until ( Ord(Expression[TokenPos] ) < Ord('0'))

               or ( Ord(Expression[TokenPos] ) > Ord('9'))

               or ( TokenPos > Length( Expression ));

       { Mark the token Type as a Number }

       TokenType := Number;

     end

     { See if it's a plus sign }

     else if Expression[ TokenPos ] = '+' then

     begin

       TokenType := Plus;

       Inc( TokenPos );

     end

     { See if it's minus sign }

     else if Expression[ TokenPos ] = '-' then

     begin

       TokenType := Minus;

       Inc( TokenPos );

     end

     { See if it's a multiply sign }

     else if Expression[ TokenPos ] = ' ' then

     begin

       TokenType := Times;

       Inc( TokenPos );

     end

     { See if it's a divide sign }

     else if Expression[ TokenPos ] = '/' then

     begin

       TokenType := Times;

       Inc( TokenPos );

     end

     { See if it's a left parent sign }

     else if Expression[ TokenPos ] = '(' then

     begin

       TokenType := LParen;

       Inc( TokenPos );

     end

     { See if it's a right parent sign }

     else if Expression[ TokenPos ] = ')' then

     begin

       TokenType := RParen;

       Inc( TokenPos );

     end

     { None of that. So it's a junk }

     else

        TokenType := TokError;

end;



Function StripOff( ch : char; Str : String ) : String;

Var

 posi : byte;

begin

 posi := Pos( ch, str );

 while posi <> 0 do

 begin

   posi := Pos( ch, str );

   delete( str, posi, 1 );

 end;

 Result := str;

end;





function TForm1.Eval( ExpressionToEvaluate : String ) : Integer;

begin

  { Initialize the number and operator stacks }

  TokenPos := 1;



  { Make sure is something at the operators stack }

  Operators.AddItem( LParen );



  { Set the stack pointer }

  Numbers.Reset;

  Operators.Reset;



  { Strip all the spaces off } 

  Expression := StripOff(' ', ExpressionToEvaluate );





  while TokenPos <= Length( Expression ) do

  begin

     GetToken;

     While TokenType = LParen do

     begin

       Operators.AddItem( LParen );

       GetToken;

     end;

     { Check for negative number }

     if TokenType = Minus then

     begin

        MinusFlag := true;

        GetToken;

     end

     else

        MinusFlag := false;

     if TokenType = Number then

     begin

       Val( Token, i, code );

       if MinusFlag then

          i := -i;

       Numbers.AddItem( i );

       { See if at the end of the expression }

       if TokenPos <= Length( Expression ) then

       begin

         { Get the operators }

         repeat

            GetToken;

            if Operators.TestItem <>  LParen then

               { Do operations of higher precedence up to the left paren }

               while ( Operators.TestItem <> LParen ) and

                       ((( Operators.TestItem DIV 2 ) >= ( TokenType DIV 2 ))

                       or ( TokenType = RParen )) do

                       begin

                         Arg1 := Numbers.GetItem;

                         Arg2 := Numbers.GetItem;

                         case Operators.GetItem of

                              Plus   : Numbers.AddItem( Arg2 + Arg1 );

                              Minus  : Numbers.AddItem( Arg2 - Arg1 );

                              Times  : Numbers.AddItem( Arg2   Arg1 );

                              Divide : Numbers.AddItem( Arg2 DIV Arg1 );

                         end;

                       end;

                       if TokenType = RParen then

                          i := Operators.GetItem;

         until ( TokenType <> RParen )

                 or ( TokenPos >= Length( Expression ));

         Operators.AddItem( TokenType );

         end;

         end

         else

            TokenType := TokError;

         if Tokentype = TokError then

         begin

            TokenPos := Length( Expression ) + 1;

            Numbers.AddItem( 0 );

         end;

      end;

      while Operators.StackSize > 1 do

      begin

        Arg1 := Numbers.GetItem;

        Arg2 := Numbers.GetItem;

        repeat

           i := Operators.GetItem;

        until ( i <> LParen ) and ( i <> RParen );

        case i of

           Plus   : Numbers.AddItem( Arg2 + Arg1 );

           Minus  : Numbers.AddItem( Arg2 - Arg1 );

           Times  : Numbers.AddItem( Arg2   Arg1 );

           Divide : Numbers.AddItem( Arg2 DIV Arg1 );

       end;

    end;

    Result := Numbers.GetItem;

end;





// Link this to FormDestroy method..

procedure TForm1.FormDestroy(Sender: TObject);

begin

    Numbers.Free;

    Operators.Free;

end;



// Link this to FormCreate method..

procedure TForm1.FormCreate(Sender: TObject);

begin

    Numbers := TStack.Create;

    Operators := TStack.Create;

end;



// And this to Button1Click...

procedure TForm1.Button1Click(Sender: TObject);

begin

    Label1.Caption := IntToStr( Eval( '(10   -2) + 50   (3+5)' ));

end;





end.




 There it is... Hope it helps.







 Reginaldo Ap. Rigo

 São Paulo, SP Brazil

 virtual@alphanet.com.br





 )

관련자료

등록된 댓글이 없습니다.
프로그래밍
Today's proverb
행복해지고 싶다면, 잠시 동안만이라도 가슴에 손을 얹고 생각해 보라. 그러면 진정한 즐거움은, 발치에 돋아나는 잡초나 아침 햇살에 빛나는 꽃의 이술과 같이 우리 주변에 무수히 널려 있다는 것을 알 수 있을 것이다. 《하루 5분 생각이 인생을 결정한다 》 (이범준)