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
셰익스피어는 그의 작품 대부분을 빵과 버터와 생활 경비를 얻기 위해 썼다. 처음부터 위대한 일을 계획하고 노력한 끝에 위대한 업적을 남긴 사람도 있지만, 사람의 일이란 늘 생활과 연결되는 법이다. (굴드)