Delphi 분류
델파이 eval 함수 비슷하게 구현
컨텐츠 정보
- 29,493 조회
- 0 추천
- 목록
본문
{
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
등록된 댓글이 없습니다.