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





 )

관련자료

댓글 0
등록된 댓글이 없습니다.
Today's proverb
"우리가 저지르는 가장 나쁜 잘못은 남의 잘못에 대해 선입견을 갖는 것이다." (칼릴 지브란)