老大们,帮偶写一个函数吧(300分)

  • 主题发起人 主题发起人 狐狸精
  • 开始时间 开始时间

狐狸精

Unregistered / Unconfirmed
GUEST, unregistred user!
取得一个数学表达式,里面只有数字和简单的加、减、乘、除以及括号。
如:(1+3*4-8)+(5+6)*9/10
这个数学表达式是以字符串的方式取得的,我现在要求出它的值,这个函数
我写了好几遍都没做好,我希望得到帮助。
先给300分吧。
 
《数据结构》书里有伪代码嘛,你的要求也不高自己改造一下就出来了
劝你不好直接提出来让别人给你写,可能受谴责的哦
不如把你没写好的代码贴出来让大家找错,我认为这样最好。
 
数据结构的书上很多嘛
 
给你一个思路吧,程序最好自己写
1,根据字符串长度做循环
2、每次取一个字符,判字符,是运算符,还是数据
3,如是运算,则存入变量,ELSE,继续读字符。
注:先建一个运算优先表,取出运算符时,做个小FUNCTION先判一下。
 
其实算法我也知道,就是写的时候出不来结果
 
我的E_mail为:yanleigis@21cn.com
给我发E_mail,告诉你的E_mail,我给发
 
应该是用栈,然后定义运算符的优先级,大二的时候就做过啊。。
现在忘了。。。查查数据结构的书,在栈跟队列那一章就有!
 
编译原理里的东东
 
用这个:

unit Parser;

{==========================================================================}
{ Expression Evaluator v1.0 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. }
{==========================================================================}

interface

uses
{$ifdef Win32}
Windows,
{$else}
WinProcs, Wintypes,
{$endif}
SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs;

type
TGetVarEvent = procedure(Sender : TObject; VarName : string; var
Value : Extended; var Found : Boolean) of object;

TParseErrorEvent = procedure(Sender : TObject; ParseError : Integer)
of object;

const
ParserStackSize = 15;
MaxFuncNameLen = 5;
ExpLimit = 11356;
SqrLimit = 1E2466;
MaxExpLen = 4;
TotalErrors = 7; //changed from 6
ErrParserStack = 1;
ErrBadRange = 2;
ErrExpression = 3;
ErrOperator = 4;
ErrOpenParen = 5;
ErrOpCloseParen = 6;
ErrDivZero = 7; //added

type
ErrorRange = 0..TotalErrors;

TokenTypes = (Plus, Minus, Times, Divide, Expo, OParen, CParen, Num,
Func, EOL, Bad, ERR);

TokenRec = record
State : Byte;
case Byte of
0 : (Value : Extended);
2 : (FuncName : String[MaxFuncNameLen]);
end; { TokenRec }

type
TMathParser = class(TComponent)
private
{ Private declarations }
FInput : string;
FOnGetVar : TGetVarEvent;
FOnParseError : TParseErrorEvent;
protected
{ Protected declarations }
CurrToken : TokenRec;
MathError : Boolean;
Stack : array[1..ParserStackSize] of TokenRec;
StackTop : 0..ParserStackSize;
TokenError : ErrorRange;
TokenLen : Word;
TokenType : TokenTypes;
function GotoState(Production : Word) : Word;
function IsFunc(S : String) : Boolean;
function IsVar(var Value : Extended) : Boolean;
function NextToken : TokenTypes;
procedure Push(Token : TokenRec);
procedure Pop(var Token : TokenRec);
procedure Reduce(Reduction : Word);
procedure Shift(State : Word);
public
{ Public declarations }
Position : Word;
ParseError : Boolean;
ParseValue : Extended;
constructor Create(AOwner: TComponent); override;
procedure Parse;
published
{ Published declarations }
property OnGetVar : TGetVarEvent read FOnGetVar write FOnGetVar;
property OnParseError : TParseErrorEvent read FOnParseError
write FOnParseError;
property ParseString : string read FInput write FInput;
end;

//procedure Register;

implementation

const
Letters : set of Char = ['A'..'Z', 'a'..'z'];
// Numbers : set of Char = ['0'..'9'];

constructor TMathParser.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
{ defaults }
FInput := '';
end;

function TMathParser.GotoState(Production : Word) : Word;
{ Finds the new state based on the just-completed production and the
top state. }
var
State : Word;
begin
GotoState:= 0;
State := Stack[StackTop].State;
if (Production <= 3) then
begin
case State of
0 : GotoState := 1;
9 : GotoState := 19;
20 : GotoState := 28;
end; { case }
end
else if Production <= 6 then
begin
case State of
0, 9, 20 : GotoState := 2;
12 : GotoState := 21;
13 : GotoState := 22;
end; { case }
end
else if Production <= 8 then
begin
case State of
0, 9, 12, 13, 20 : GotoState := 3;
14 : GotoState := 23;
15 : GotoState := 24;
16 : GotoState := 25;
end; { case }
end
else if Production <= 10 then
begin
case State of
0, 9, 12..16, 20 : GotoState := 4;
end; { case }
end
else if Production <= 12 then
begin
case State of
0, 9, 12..16, 20 : GotoState := 6;
5 : GotoState := 17;
end; { case }
end
else begin
case State of
0, 5, 9, 12..16, 20 : GotoState := 8;
end; { case }
end;
end; { GotoState }

function TMathParser.IsFunc(S : String) : Boolean;
{ Checks to see if the parser is about to read a function }
var
P, SLen : Word;
FuncName : string;
begin
P := Position;
FuncName := '';
while (P <= Length(FInput)) and (FInput[P] in ['A'..'Z', 'a'..'z', '0'..'9',
'_']) do
begin
FuncName := FuncName + FInput[P];
Inc(P);
end; { while }
if Uppercase(FuncName) = S
then begin
SLen := Length(S);
CurrToken.FuncName := UpperCase(Copy(FInput, Position, SLen));
Inc(Position, SLen);
IsFunc := True;
end { if }
else IsFunc := False;
end; { IsFunc }

function TMathParser.IsVar(var Value : Extended) : Boolean;
var
VarName : string;
VarFound : Boolean;
begin
VarFound := False;
VarName := '';
while (Position <= Length(FInput)) and (FInput[Position] in ['A'..'Z',
'a'..'z', '0'..'9', '_']) do
begin
VarName := VarName + FInput[Position];
Inc(Position);
end; { while }
if Assigned(FOnGetVar)
then FOnGetVar(Self, VarName, Value, VarFound);
IsVar := VarFound;
end; { IsVar }

function TMathParser.NextToken : TokenTypes;
{ Gets the next Token from the Input stream }
var
NumString : String[80];
TLen, NumLen : Word;
Check : Integer;
Ch : Char;
Decimal : Boolean;
begin
while (Position <= Length(FInput)) and (FInput[Position] = ' ') do
Inc(Position);
TokenLen := Position;
if Position > Length(FInput) then
begin
NextToken := EOL;
TokenLen := 0;
Exit;
end; { if }
Ch := UpCase(FInput[Position]);
if Ch in ['!'] then
begin
NextToken := ERR;
TokenLen := 0;
Exit;
end; { if }
if Ch in ['0'..'9', '.'] then
begin
NumString := '';
TLen := Position;
Decimal := False;
while (TLen <= Length(FInput)) and
((FInput[TLen] in ['0'..'9']) or
((FInput[TLen] = '.') and (not Decimal))) do
begin
NumString := NumString + FInput[TLen];
if Ch = '.' then
Decimal := True;
Inc(TLen);
end; { while }
if (TLen = 2) and (Ch = '.') then
begin
NextToken := BAD;
TokenLen := 0;
Exit;
end; { if }
if (TLen <= Length(FInput)) and (UpCase(FInput[TLen]) = 'E') then
begin
NumString := NumString + 'E';
Inc(TLen);
if FInput[TLen] in ['+', '-'] then
begin
NumString := NumString + FInput[TLen];
Inc(TLen);
end; { if }
NumLen := 1;
while (TLen <= Length(FInput)) and (FInput[TLen] in ['0'..'9']) and
(NumLen <= MaxExpLen) do
begin
NumString := NumString + FInput[TLen];
Inc(NumLen);
Inc(TLen);
end; { while }
end; { if }
if NumString[1] = '.' then
NumString := '0' + NumString;
Val(NumString, CurrToken.Value, Check);
if Check <> 0 then
MathError := True;
NextToken := NUM;
Inc(Position, System.Length(NumString));
TokenLen := Position - TokenLen;
Exit;
end { if }
else if Ch in Letters then
begin
if IsFunc('ABS') or
IsFunc('ATAN') or
IsFunc('COS') or
IsFunc('EXP') or
IsFunc('LN') or
IsFunc('ROUND') or
IsFunc('SIN') or
IsFunc('SQRT') or
IsFunc('SQR') or
IsFunc('TRUNC') then
begin
NextToken := FUNC;
TokenLen := Position - TokenLen;
Exit;
end; { if }
if IsVar(CurrToken.Value)
then begin
NextToken := NUM;
TokenLen := Position - TokenLen;
Exit;
end { if }
else begin
NextToken := BAD;
TokenLen := 0;
Exit;
end; { else }
end { if }
else begin
case Ch of
'+' : NextToken := PLUS;
'-' : NextToken := MINUS;
'*' : NextToken := TIMES;
'/' : NextToken := DIVIDE;
'^' : NextToken := EXPO;
'(' : NextToken := OPAREN;
')' : NextToken := CPAREN;
else begin
NextToken := BAD;
TokenLen := 0;
Exit;
end; { case else }
end; { case }
Inc(Position);
TokenLen := Position - TokenLen;
Exit;
end; { else if }
end; { NextToken }

procedure TMathParser.Pop(var Token : TokenRec);
{ Pops the top Token off of the stack }
begin
Token := Stack[StackTop];
Dec(StackTop);
end; { Pop }

procedure TMathParser.Push(Token : TokenRec);
{ Pushes a new Token onto the stack }
begin
if StackTop = ParserStackSize then
TokenError := ErrParserStack
else begin
Inc(StackTop);
Stack[StackTop] := Token;
end; { else }
end; { Push }

procedure TMathParser.Parse;
{ Parses an input stream }
var
FirstToken : TokenRec;
Accepted : Boolean;
begin
Position := 1;
StackTop := 0;
TokenError := 0;
MathError := False;
ParseError := False;
Accepted := False;
FirstToken.State := 0;
FirstToken.Value := 0;
Push(FirstToken);
TokenType := NextToken;
repeat
case Stack[StackTop].State of
0, 9, 12..16, 20 : begin
if TokenType = NUM then
Shift(10)
else if TokenType = FUNC then
Shift(11)
else if TokenType = MINUS then
Shift(5)
else if TokenType = OPAREN then
Shift(9)
else if TokenType = ERR then
begin
MathError := True;
Accepted := True;
end { else if }
else begin
TokenError := ErrExpression;
Dec(Position, TokenLen);
end; { else }
end; { case of }
1 : begin
if TokenType = EOL then
Accepted := True
else if TokenType = PLUS then
Shift(12)
else if TokenType = MINUS then
Shift(13)
else begin
TokenError := ErrOperator;
Dec(Position, TokenLen);
end; { else }
end; { case of }
2 : begin
if TokenType = TIMES then
Shift(14)
else if TokenType = DIVIDE then
Shift(15)
else
Reduce(3);
end; { case of }
3 : Reduce(6);
4 : begin
if TokenType = EXPO then
Shift(16)
else
Reduce(8);
end; { case of }
5 : begin
if TokenType = NUM then
Shift(10)
else if TokenType = FUNC then
Shift(11)
else if TokenType = OPAREN then
Shift(9)
else
begin
TokenError := ErrExpression;
Dec(Position, TokenLen);
end; { else }
end; { case of }
6 : Reduce(10);
7 : Reduce(13);
8 : Reduce(12);
10 : Reduce(15);
11 : begin
if TokenType = OPAREN then
Shift(20)
else
begin
TokenError := ErrOpenParen;
Dec(Position, TokenLen);
end; { else }
end; { case of }
17 : Reduce(9);
18 : raise Exception.Create('Bad token state');
19 : begin
if TokenType = PLUS then
Shift(12)
else if TokenType = MINUS then
Shift(13)
else if TokenType = CPAREN then
Shift(27)
else
begin
TokenError := ErrOpCloseParen;
Dec(Position, TokenLen);
end;
end; { case of }
21 : begin
if TokenType = TIMES then
Shift(14)
else if TokenType = DIVIDE then
Shift(15)
else
Reduce(1);
end; { case of }
22 : begin
if TokenType = TIMES then
Shift(14)
else if TokenType = DIVIDE then
Shift(15)
else
Reduce(2);
end; { case of }
23 : Reduce(4);
24 : Reduce(5);
25 : Reduce(7);
26 : Reduce(11);
27 : Reduce(14);
28 : begin
if TokenType = PLUS then
Shift(12)
else if TokenType = MINUS then
Shift(13)
else if TokenType = CPAREN then
Shift(29)
else
begin
TokenError := ErrOpCloseParen;
Dec(Position, TokenLen);
end; { else }
end; { case of }
29 : Reduce(16);
end; { case }
until Accepted or (TokenError <> 0);
if TokenError <> 0 then
begin
if TokenError = ErrBadRange then
Dec(Position, TokenLen);
if Assigned(FOnParseError)
then FOnParseError(Self, TokenError);
end; { if }
if MathError or (TokenError <> 0) then
begin
ParseError := True;
ParseValue := 0;
Exit;
end; { if }
ParseError := False;
ParseValue := Stack[StackTop].Value;
end; { Parse }

procedure TMathParser.Reduce(Reduction : Word);
{ Completes a reduction }
var
Token1, Token2 : TokenRec;
begin
case Reduction of
1 : begin
Pop(Token1);
Pop(Token2);
Pop(Token2);
CurrToken.Value := Token1.Value + Token2.Value;
end;
2 : begin
Pop(Token1);
Pop(Token2);
Pop(Token2);
CurrToken.Value := Token2.Value - Token1.Value;
end;
4 : begin
Pop(Token1);
Pop(Token2);
Pop(Token2);
CurrToken.Value := Token1.Value * Token2.Value;
end;
5 : begin
Pop(Token1);
Pop(Token2);
Pop(Token2);
if Token1.Value = 0 then
begin
MathError := True;
TokenError:= ErrDivZero; //Added
end
else
CurrToken.Value := Token2.Value / Token1.Value;
end;
7 : begin
Pop(Token1);
Pop(Token2);
Pop(Token2);
if Token2.Value <= 0 then
MathError := True
else if (Token1.Value * Ln(Token2.Value) < -ExpLimit) or
(Token1.Value * Ln(Token2.Value) > ExpLimit) then
MathError := True
else
CurrToken.Value := Exp(Token1.Value * Ln(Token2.Value));
end;
9 : begin
Pop(Token1);
Pop(Token2);
CurrToken.Value := -Token1.Value;
end;
11 : raise Exception.Create('Invalid reduction');
13 : raise Exception.Create('Invalid reduction');
14 : begin
Pop(Token1);
Pop(CurrToken);
Pop(Token1);
end;
16 : begin
Pop(Token1);
Pop(CurrToken);
Pop(Token1);
Pop(Token1);
if Token1.FuncName = 'ABS' then
CurrToken.Value := Abs(CurrToken.Value)
else if Token1.FuncName = 'ATAN' then
CurrToken.Value := ArcTan(CurrToken.Value)
else if Token1.FuncName = 'COS' then
begin
if (CurrToken.Value < -9E18) or (CurrToken.Value > 9E18) then
MathError := True
else
CurrToken.Value := Cos(CurrToken.Value)
end {...if Token1.FuncName = 'SIN' }
else if Token1.FuncName = 'EXP' then
begin
if (CurrToken.Value < -ExpLimit) or (CurrToken.Value > ExpLimit) then
MathError := True
else
CurrToken.Value := Exp(CurrToken.Value);
end
else if Token1.FuncName = 'LN' then
begin
if CurrToken.Value <= 0 then
MathError := True
else
CurrToken.Value := Ln(CurrToken.Value);
end
else if Token1.FuncName = 'ROUND' then
begin
if (CurrToken.Value < -1E9) or (CurrToken.Value > 1E9) then
MathError := True
else
CurrToken.Value := Round(CurrToken.Value);
end
else if Token1.FuncName = 'SIN' then
begin
if (CurrToken.Value < -9E18) or (CurrToken.Value > 9E18) then
MathError := True
else
CurrToken.Value := Sin(CurrToken.Value)
end {...if Token1.FuncName = 'SIN' }
else if Token1.FuncName = 'SQRT' then
begin
if CurrToken.Value < 0 then
MathError := True
else
CurrToken.Value := Sqrt(CurrToken.Value);
end
else if Token1.FuncName = 'SQR' then
begin
if (CurrToken.Value < -SQRLIMIT) or (CurrToken.Value > SQRLIMIT) then
MathError := True
else
CurrToken.Value := Sqr(CurrToken.Value);
end
else if Token1.FuncName = 'TRUNC' then
begin
if (CurrToken.Value < -1E9) or (CurrToken.Value > 1E9) then
MathError := True
else
CurrToken.Value := Trunc(CurrToken.Value);
end;
end;
3, 6, 8, 10, 12, 15 : Pop(CurrToken);
end; { case }
CurrToken.State := GotoState(Reduction);
Push(CurrToken);
end; { Reduce }

procedure TMathParser.Shift(State : Word);
{ Shifts a Token onto the stack }
begin
CurrToken.State := State;
Push(CurrToken);
TokenType := NextToken;
end; { Shift }

procedure Register;
begin
RegisterComponents('Other', [TMathParser]);
end;

end.
 
高级开发语言都支持数学表达式的算法,不必编写。

你如需要,我可以写一个汇编的。
 
笨方法:
1. 建立一个Access数据库,内有表aaa(只有一个字段gg,数据类型任意)
2. 在你的程序中通过ADOQuery访问表aaa, SQLd的语句为
"select *, ((1+3*4-8)+(5+6)*9/10) as kk from aaa"
3. 执行ADOQuery.open后,kk字段的值就是你字符串的值了.
如果你不想写复杂的算法,又对计算精度没有严格要求,就可以使用这种方法了!
 
虽然还没一个答案可以用的,但我已经得到了很多算法方面得提示,故我把分还是分下去。
大家还可以继续讨论(没有分噜)
 
给个我编的类你,希望能帮上忙:
用法:
var
exp: TExpressionString;
begin
exp := TExpressionString.Create('3*2(8-1)-2/(3+7*1)');
if exp.validvalue then
结果 := exp.value;

===========================================================
unit k_Expression;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, k_Public;

type
RExpCode = record
Code: String;
Value: Double;
IsValid: Boolean;
Tag: Integer;
end;

TExpCodes = class
private
FAddAllow: Boolean;
FCodes: array of RExpCode;
FCount: Integer;
function GetCodeByName(const Name: String): RExpCode;
function GetCodeNames(Index: Integer): String;
function GetCodes(index: Integer): RExpCode;
function GetCodeTag(Index: Integer): Integer;
function GetCodeValue(Index: Integer): Double;
function GetCodeValueByName(const Name: String): Double;
function GetIsValid: Boolean;
function GetNameIndex(const Name: String): Integer;
function IndexOfName(const Name: String): Integer;
procedure SetCodeByName(const Name: String; Value: RExpCode);
procedure SetCodeNames(Index: Integer; Value: String);
procedure SetCodeTag(Index, Value: Integer);
procedure SetCodeValue(Index: Integer; Value: Double);
procedure SetCodeValueByName(const Name: String; Value: Double);
procedure SetCodes(index: Integer; Value: RExpCode);
procedure SetCount(Value: Integer);
public
constructor Create(iCount: Integer = 0);
destructor Destroy; override;

function ExistsName(const Name: string): Boolean;
procedure Add(const Name: String); overload;
procedure Add(const Name: String; iValue: Double); overload;
procedure Delete(const iName: string);
procedure Rename(const iName, nName: string);
procedure Clear;

property AddAllow: Boolean read FAddAllow write FAddAllow;
property CodeByName[const Name: String]: RExpCode read GetCodeByName write SetCodeByName;
property CodeNames[Index: Integer]: String read GetCodeNames write SetCodeNames;
property Codes[index: Integer]: RExpCode read GetCodes write SetCodes; default;
property Count: Integer read FCount write SetCount;
property Indexs[const Name: String]: Integer read GetNameIndex;
property IsValid: Boolean read GetIsValid;
property CodeTag[Index: Integer]: Integer read GetCodeTag write SetCodeTag;
property CodeValue[Index: Integer]: Double read GetCodeValue write SetCodeValue;
property CodeValueByName[const Name: String]: Double read GetCodeValueByName write SetCodeValueByName;
end;

TBOItemType = (boitOpt, boitCode, boitValue, boitUnknow);
TOptStr = string[1];
RBOItem = record
case ItemType: TBOItemType of
boitOpt: (Opt: TOptStr;);
boitCode: (Idx: Integer;);
boitValue: (Val: Double;);
boitUnknow: ();
end;

TBOItems = class
private
FItems: array of RBOItem;
FCodes: TExpCodes;
FCount: Integer;
function GetCodeReady: Boolean;
function GetItems(Index: Integer): RBOItem;
procedure SetCount(Value: Integer);
procedure SetItems(Index: Integer; Value: RBOItem);
public
constructor Create(iCount: Integer = 0; iCodes: TExpCodes = nil);
destructor Destroy; override;

function AssignValueTo(iTarget: TBOItems): Boolean;

procedure Add(iOpt: String); overload;
procedure Add(iIdx: Integer); overload;
procedure Add(iVal: Double); overload;
procedure Assign(Source: TBOItems);
procedure Clear;

property CodeReady: Boolean read GetCodeReady;
property Codes: TExpCodes read FCodes write FCodes;
property Count: Integer read FCount write SetCount;
property Items[Index: Integer]: RBOItem read GetItems write SetItems; default;
end;

TExpressionString = class
private
// private
FBOItems: TBOItems;
FCodeAllow: Boolean;
FCodes: TExpCodes;
FCodesCount: Integer;
FExpStr: String;
FExtract: Boolean;
FNewCodes: Boolean;
FValidExp: Boolean;
FValidValue: Boolean;
FValue: Double;
FValueFractionDigits: Integer;
function Calculate(iBOList: TBOItems; var Value: Double): Boolean;
function GetBOExpStr: String;
function GetValidValue: Boolean;
function GetValue: Double;
function IsDigitString(iStr: String): Boolean;
function IsValidCode(iStr: String): Boolean;
function LevelOf(iOpt: String): Integer;
procedure SetCodeAllow(Value: Boolean);
procedure SetExpStr(Value: String);
procedure SetValueFractionDigits(Value: Integer);
protected
// protected
property BOItems: TBOItems read FBOItems;
public
// public
constructor Create(iExpr: String = ''; iCodeList: TExpCodes = nil);
destructor Destroy; override;

function ValueOfExpr(iExpr: string): Double;

property BOExpStr: string read GetBOExpStr;
property CodeAllow: Boolean read FCodeAllow write SetCodeAllow;
property Codes: TExpCodes read FCodes write FCodes;
property ExpStr: String read FExpStr write SetExpStr;
property Extract: Boolean read FExtract write FExtract;
property ValidExp: Boolean read FValidExp;
property ValidValue: Boolean read GetValidValue;
property Value: Double read GetValue;
property ValueFractionDigits: Integer read FValueFractionDigits write SetValueFractionDigits;
end;

implementation

//=========================================================================
//=========================================================================
// TExpCodes:
//=========================================================================
//=========================================================================
constructor TExpCodes.Create(iCount: Integer = 0);
begin
inherited Create;
FAddAllow := True;
FCount := 0;
Count := iCount;
end;

destructor TExpCodes.Destroy;
begin
inherited;
end;

function TExpCodes.ExistsName(const Name: string): Boolean;
begin
Result := IndexOfName(Name) > -1;
end;

function TExpCodes.GetCodeByName(const Name: String): RExpCode;
var
i: Integer;
begin
i := IndexOfName(Name);
if i > -1 then
Result := FCodes
else begin
Result.Code := '';
Result.Value := 0;
end;
end;

function TExpCodes.GetCodeNames(Index: Integer): String;
begin
if (Index > -1) and (Index < FCount) then
Result := FCodes[Index].Code
else
Result := '';
end;

function TExpCodes.GetCodes(index: Integer): RExpCode;
begin
Result := FCodes[index];
end;

function TExpCodes.GetIsValid: Boolean;
var
i: Integer;
begin
Result := True;
if FCount > 0 then begin
for i := 0 to FCount - 1 do
Result := Result and FCodes.IsValid;
end;
end;

function TExpCodes.GetCodeTag(Index: Integer): Integer;
begin
if (Index > -1) and (Index < FCount) then
Result := FCodes[Index].Tag
else
Result := -1;
end;

function TExpCodes.GetCodeValue(Index: Integer): Double;
begin
if (Index > -1) and (Index < FCount) then
Result := FCodes[Index].Value
else
Result := 0;
end;

function TExpCodes.GetCodeValueByName(const Name: String): Double;
var
i: Integer;
begin
i := IndexOfName(Name);
if i > -1 then
Result := FCodes.Value
else
Result := 0;
end;

function TExpCodes.GetNameIndex(const Name: String): Integer;
begin
Result := IndexOfName(Name);
if Result = -1 then
Add(Name);
end;

function TExpCodes.IndexOfName(const Name: String): Integer;
begin
for Result := 0 to FCount - 1 do
if FCodes[Result].Code = Name then
Break;
if Result = FCount then
Result := -1;
end;

procedure TExpCodes.Add(const Name: String);
begin
if FAddAllow then begin
SetCount(FCount + 1);
FCodes[FCount - 1].Code := Name;
end;
end;

procedure TExpCodes.Add(const Name: String; iValue: Double);
begin
if FAddAllow then begin
SetCount(FCount + 1);
with FCodes[FCount - 1] do begin
Code := Name;
Value := iValue;
IsValid := True;
end;
end;
end;

procedure TExpCodes.Clear;
begin
if FAddAllow then
SetCount(0);
end;

procedure TExpCodes.Delete(const iName: string);
var
i, x: Integer;
begin
x := IndexOfName(iName);
if x > -1 then begin
for i := x + 1 to FCount - 1 do
Codes[i - 1] := FCodes;
SetCount(FCount - 1);
end;
end;

procedure TExpCodes.Rename(const iName, nName: string);
begin
SetCodeNames(IndexOfName(iName), nName);
end;

procedure TExpCodes.SetCodeByName(const Name: String; Value: RExpCode);
begin
SetCodes(IndexOfName(Name), Value);
end;

procedure TExpCodes.SetCodeNames(Index: Integer; Value: String);
begin
if (Index > -1) and (Index < FCount) then
FCodes[Index].Code := Value;
end;

procedure TExpCodes.SetCodeTag(Index, Value: Integer);
begin
if (Index > -1) and (Index < FCount) then
FCodes[Index].Tag := Value;
end;

procedure TExpCodes.SetCodeValue(Index: Integer; Value: Double);
begin
if (Index > -1) and (Index < FCount) then begin
FCodes[Index].Value := Value;
FCodes[Index].IsValid := True;
end;
end;

procedure TExpCodes.SetCodeValueByName(const Name: String; Value: Double);
begin
SetCodeValue(IndexOfName(Name), Value);
end;

procedure TExpCodes.SetCodes(index: Integer; Value: RExpCode);
begin
if (Value.Code <> '') and (-1 < Index) and (Index < FCount) then begin
FCodes[Index].Code := Value.Code;
FCodes[Index].Value := Value.Value;
FCodes[Index].IsValid := Value.IsValid;
FCodes[Index].Tag := Value.Tag;
end;
end;

procedure TExpCodes.SetCount(Value: Integer);
var
i: Integer;
begin
if FAddAllow and (FCount <> Value) then begin
if Value <= 0 then begin
FCount := 0;
SetLength(FCodes, FCount);
end else begin
SetLength(FCodes, Value);
if FCount < Value then
for i := FCount to Value - 1 do
FCodes.IsValid := False;
FCount := Value;
end;
end;
end;

//=========================================================================
//=========================================================================
// TBOItems:
//=========================================================================
//=========================================================================
constructor TBOItems.Create(iCount: Integer = 0; iCodes: TExpCodes = nil);
begin
inherited Create;
FCount := 0;
SetCount(iCount);
FCodes := iCodes;
end;

destructor TBOItems.Destroy;
begin
inherited;
end;

function TBOItems.AssignValueTo(iTarget: TBOItems): Boolean;
var
i: Integer;
tboi: RBOItem;
begin
Result := (FCount > 0);
if Result then begin
if iTarget.Count <> FCount then
iTarget.Count := FCount;
for i := 0 to FCount - 1 do begin
case FItems.ItemType of
boitOpt:
begin
tboi.ItemType := boitOpt;
tboi.Opt := FItems.Opt;
end;
boitCode:
begin
if (FCodes <> nil) and FCodes[FItems.Idx].IsValid then begin
tboi.ItemType := boitValue;
tboi.Val := FCodes[FItems.Idx].Value;
end else begin
Result := False;
Break;
end;
end;
boitValue:
begin
tboi.ItemType := boitValue;
tboi.Val := FItems.Val;
end;
boitUnknow:
begin
Result := False;
Break;
end;
end;
iTarget := tboi;
end;
end;
end;

function TBOItems.GetCodeReady: Boolean;
var
i: Integer;
begin
Result := True;
for i := 0 to FCount - 1 do
if FItems.ItemType = boitCode then
Result := Result and FCodes[FItems.Idx].IsValid;
end;

function TBOItems.GetItems(Index: Integer): RBOItem;
begin
if (Index > -1) and (Index < FCount) then
Result := FItems[Index]
else
Result.ItemType := boitUnKnow;
end;

procedure TBOItems.Assign(Source: TBOItems);
var
i: Integer;
begin
if FCount <> Source.Count then
SetCount(Source.Count);
for i := 0 to FCount - 1 do begin
FItems.ItemType := Source.ItemType;
case FItems.ItemType of
boitOpt: FItems.Opt := Source.Opt;
boitCode: FItems.Idx := Source.Idx;
boitValue: FItems.Val := Source.Val;
end;
end;
end;

procedure TBOItems.SetCount(Value: Integer);
var
i: Integer;
begin
if FCount <> Value then
if FCount > 0 then begin
if Value <= 0 then begin
FItems := Copy(FItems, 0, 1);
FCount := 0;
end else begin
if FCount > Value then
FItems := Copy(FItems, 0, Value)
else begin
SetLength(FItems, Value);
for i := FCount - 1 to Value - 1 do
FItems.ItemType := boitUnKnow;
end;
FCount := Value;
end;
end else if Value > 0 then begin
SetLength(FItems, Value);
for i := 0 to Value - 1 do
FItems.ItemType := boitUnKnow;
FCount := Value;
end;
end;

procedure TBOItems.SetItems(Index: Integer; Value: RBOItem);
begin
if (Index > -1) and (Index < FCount) then begin
FItems[Index].ItemType := Value.ItemType;
case Value.ItemType of
boitOpt: FItems[Index].Opt := Value.Opt;
boitCode: FItems[Index].Idx := Value.Idx;
boitValue: FItems[Index].Val := Value.Val;
end;
end;
end;

procedure TBOItems.Add(iOpt: String);
begin
Inc(FCount);
SetLength(FItems, FCount);
FItems[FCount - 1].ItemType := boitOpt;
FItems[FCount - 1].Opt := iOpt;
end;

procedure TBOItems.Add(iIdx: Integer);
begin
Inc(FCount);
SetLength(FItems, FCount);
FItems[FCount - 1].ItemType := boitCode;
FItems[FCount - 1].Idx := iIdx;
end;

procedure TBOItems.Add(iVal: Double);
begin
Inc(FCount);
SetLength(FItems, FCount);
FItems[FCount - 1].ItemType := boitValue;
FItems[FCount - 1].Val := iVal;
end;

procedure TBOItems.Clear;
begin
SetCount(0);
end;

//=========================================================================
//=========================================================================
// TExpressionString:
//=========================================================================
//=========================================================================
constructor TExpressionString.Create(iExpr: String = ''; iCodeList: TExpCodes = nil);
begin
inherited Create;
FCodeAllow := False;
FValueFractionDigits := 0;
if iCodeList = nil then begin
FNewCodes := True;
FCodes := TExpCodes.Create;
end else begin
FNewCodes := False;
FCodes := iCodeList;
end;
FBOItems := TBOItems.Create(0, FCodes);
if iExpr = '' then
FCodesCount := 0
else
SetExpStr(iExpr);
end;

destructor TExpressionString.Destroy;
begin
if FNewCodes then
FCodes.Free;
inherited;
end;

function TExpressionString.Calculate(iBOList: TBOItems; var Value: Double): Boolean;
var
v1, v2: Double;
tv: array of Double;
i, n: Integer;
begin
n := 0;
Result := True;
for i := 0 to iBOList.Count - 1 do begin
case iBOList.ItemType of
boitOpt:
begin
if n > 1 then begin
v1 := tv[n - 2];
v2 := tv[n - 1];
Dec(n);
tv := Copy(tv, 0, n);
case iBOList.Opt[1] of
#33: //!
begin
if v2 = 0 then
v1 := 1
else
v1 := 0;
Inc(n);
SetLength(tv, n);
end;
#37: //%
begin
if v2 = 0 then begin
Result := False;
Break;
end else
v1 := v1 - (Trunc(v1 / v2) * v2);
end;
#38: //&
begin
if (v1 = 0) and (v2 = 0) then
v1 := 0
else
v1 := 1;
end;
#42: //*
v1 := v1 * v2;
#43: //+
v1 := v1 + v2;
#45: //-
v1 := v1 - v2;
#47: ///
begin
if v2 = 0 then begin
Result := False;
Break;
end else
v1 := v1 / v2;
end;
#58: //:
begin
if n < 2 then begin
Result := False;
Break;
end else begin
if tv[n - 2] = 0 then
v1 := v2;
Dec(n);
tv := Copy(tv, 0, n);
end;
end;
#60: //<
begin
if v1 < v2 then
v1 := 1
else
v1 := 0;
end;
#61: //=
begin
if v1 = v2 then
v1 := 1
else
v1 := 0;
end;
#62: //>
begin
if v1 > v2 then
v1 := 1
else
v1 := 0;
end;
#63: //?
begin
if v1 = 0 then
tv[n - 1] := 0
else
tv[n - 1] := 1;
Inc(n);
SetLength(tv, n);
v1 := v2;
end;
#92: ///
v1 := Trunc(v1 / v2);
#124: //|
begin
if (v1 <> 0) or (v2 <> 0) then
v1 := 1
else
v1 := 0;
end;
end;
tv[n - 1] := v1;
end else begin
if (n = 1) and (iBOList.Opt[1] = #33) then begin
if tv[0] = 0 then
tv[0] := 1
else
tv[0] := 0;
end else begin
Result := False;
Break;
end;
end;
end;
boitValue:
begin
Inc(n);
SetLength(tv, n);
tv[n - 1] := iBOList.Val;
end;
else
begin
Result := False;
Break;
end;
end;
end;
Result := Result and (n = 1);
if Result then
if FValueFractionDigits > 0 then
Value := FloatRound(tv[0], FValueFractionDigits)
else
Value := tv[0];
end;

function TExpressionString.GetBOExpStr: String;
var
i: Integer;
begin
Result := '';
if ValidExp then
for i := 0 to FBOItems.Count - 1 do begin
case FBOItems.ItemType of
boitOpt:
Result := Result + FBOItems.Opt;
boitCode:
Result := Result + FCodes[FBOItems.Idx].Code;
boitValue:
Result := Result + FloatToStr(FBOItems.Val);
else
Result := Result + '<?UNKNOW?>';
end;
end;
end;

function TExpressionString.GetValidValue: Boolean;
begin
Result := (FBOItems.Count > 0) and ((FCodesCount = 0) or (FBOItems.CodeReady));
FValidValue := False;
if Result then
GetValue;
end;

function TExpressionString.GetValue: Double;
var
til: TBOItems;
begin
if not FValidValue then begin
til := TBOItems.Create;
FValidValue := FBOItems.AssignValueTo(til) and Calculate(til, FValue);
til.Free;
end;
if FValidValue then
Result := FValue
else
Result := 0;
end;

function TExpressionString.IsDigitString(iStr: String): Boolean;
// '0':48, '9':57
// '+':43, '-':45
// '.':46
var
i, DotCnt: Integer;
a: Char;
begin
Result := True;
DotCnt := 0;
for i := 1 to Length(iStr) do begin
a := iStr;
if a = #46 then begin
Inc(DotCnt);
Result := (DotCnt = 1);
end else if (a < #48) or (a > #57) then
Result := ((a = #43) or (a = #45)) and (i = 1) and (Length(iStr) > 1);
if Result = False then
Break;
end;
end;

function TExpressionString.IsValidCode(iStr: String): Boolean;
begin
Result := (Length(iStr) > 0) and (iStr[1] in [#95, #65..#90, #97..#122, #128..#254]);
end;

{#33:!, #37:%, #38:&, #42:*, #43:+, #44:,, #45:-, #47:/
, #58::, #60:<, #61:=, #62:>, #63:?, #92:/, #124:|}
{?: | & ! <=> +- */%/
1 2 3 4 5 6}
function TExpressionString.LevelOf(iOpt: String): Integer;
begin
Result := -1;
case iOpt[1] of
#63, #58: Result := 1;
#124: Result := 2;
#38: Result := 3;
#33: Result := 4;
#60..#62: Result := 5;
#43, #45: Result := 6;
#42, #47, #37, #92: Result := 7;
end;
end;

function TExpressionString.ValueOfExpr(iExpr: string): Double;
begin
ExpStr := iExpr;
Result := Value
end;

procedure TExpressionString.SetCodeAllow(Value: Boolean);
begin
if FCodeAllow <> Value then begin
FCodeAllow := Value;
if FCodeAllow then begin
if FCodesCount > 0 then begin
FValidExp := FBOItems.Count > 0;
if FValidExp and FBOItems.CodeReady then
GetValue;
end;
end else
if FCodesCount > 0 then begin
FValidExp := False;
FValidValue := False;
end;
end;
end;

procedure TExpressionString.SetExpStr(Value: String);
var
i, j, kn, lt, ls: Integer;
c: Char;
t, cs, ts: string;
b, OptExpect: Boolean;
pvExpItems: TStrings;
stk: TStrings;
begin
FBOItems.Clear;
if FNewCodes then
FCodes.Clear;
FCodesCount := 0;
FExpStr := Value;
pvExpItems := TStringList.Create;
// FExtract: Boolean;
FValidExp := False;
FValidValue := False;
FValue := 0.0;
kn := 0;
t := '';
cs := ' ';
b := True;
OptExpect := False;
for i := 1 to Length(Value) do begin
c := Value;
cs[1] := c;
case c of
#32:
begin
if t = '' then
Continue
else if OptExpect then
b := False
else begin
pvExpItems.Add(t);
t := '';
end;
end;
#40:
begin
if OptExpect or (t <> '') then
b := False
else begin
Inc(kn);
pvExpItems.Add(cs);
end;
end;
#41:
begin
if kn = 0 then
b := False
else begin
if t = '' then
b := OptExpect
else if OptExpect then
b := False
else begin
pvExpItems.Add(t);
t := '';
end;
Dec(kn);
pvExpItems.Add(cs);
OptExpect := True;
end;
end;
{#33:!, #37:%, #38:&, #42:*, #43:+, #44:,, #45:-, #47:/
, #58::, #60:<, #61:=, #62:>, #63:?, #92:/, #124:|}
#43, #45:
begin
if OptExpect then begin
if t <> '' then
b := False
else begin
pvExpItems.Add(cs);
OptExpect := False;
end;
end else begin
if t <> '' then begin
pvExpItems.Add(t);
t := '';
end else
pvExpItems.Add('0');
pvExpItems.Add(cs);
end;
end;
#58:
begin
if pvExpItems.Count < 3 then
b := False
else begin
if t <> '' then begin
if OptExpect then
b := False
else begin
pvExpItems.Add(t);
t := '';
end;
end else
b := OptExpect;
if b then
for j := pvExpItems.Count - 1 downto 1 do
if pvExpItems[j] = '?' then
break
else if pvExpItems[j] = ':' then begin
b := False;
break;
end;
if b then
pvExpItems.Add(cs);
end;
end;
#33:
begin
b := (t = '') and (not OptExpect);
pvExpItems.Add(cs);
end;
#37, #38, #42, #47, #60, #61, #62, #63, #92, #124:
begin
if t = '' then
b := OptExpect
else if OptExpect then
b := False
else begin
pvExpItems.Add(t);
t := '';
end;
pvExpItems.Add(cs);
OptExpect := False;
end;
else
if (c = #46) or ((c > #47) and (c < #58)) or ((c > #64) and (c < #91)) or ((c > #96) and (c < #127)) or ((c > #127) and (c < #255)) then
t := t + cs
else
b := False;
end;
if not b then
Break;
end;
b := b and (kn = 0) and ((pvExpItems.Count > 0) or (t <> ''));
if b then begin
if t <> '' then
pvExpItems.Add(t);
stk := TStringList.Create;
for i := 0 to pvExpItems.Count - 1 do begin
ts := pvExpItems;
if IsDigitString(ts) then
FBOItems.Add(StrToFloat(ts))
else if IsValidCode(ts) then begin
if FNewCodes then begin
FCodes.Add(ts);
j := FCodes.Count - 1;
end else begin
j := FCodes.Indexs[ts];
if j < 0 then begin
b := False;
Break;
end;
end;
FCodes.CodeTag[j] := FBOItems.Count;
FBOItems.Add(j);
Inc(FCodesCount);
end else if (Length(ts) = 1) and (LevelOf(ts) > 0) then begin
if stk.Count > 0 then begin
lt := LevelOf(ts);
ls := LevelOf(stk[stk.Count - 1]);
while ls >= lt do begin
FBOItems.Add(stk[stk.Count - 1]);
stk.Delete(stk.Count - 1);
if stk.Count = 0 then
break
else
ls := LevelOf(stk[stk.Count - 1]);
end;
end;
stk.Add(ts);
end else if ts = '(' then
stk.Add(ts)
else if ts = ')' then begin
while (stk.Count > 0) and (stk[stk.Count - 1] <> '(') do begin
FBOItems.Add(stk[stk.Count - 1]);
stk.Delete(stk.Count - 1);
end;
if stk.Count > 0 then
stk.Delete(stk.Count - 1);
end else
Break;
end;
if b then begin
if stk.Count > 0 then
for i := stk.Count - 1 downto 0 do
FBOItems.Add(stk);
if FCodesCount = 0 then begin
FValidValue := Calculate(FBOItems, FValue);
FValidExp := FValidValue;
end else begin
FValidExp := FCodeAllow;
if FBOItems.CodeReady then
GetValue
else
FValidValue := False;
end;
end;
stk.Free;
end;
pvExpItems.Free;
end;

procedure TExpressionString.SetValueFractionDigits(Value: Integer);
begin
if FValueFractionDigits <> Value then begin
FValueFractionDigits := Value;
if FValidValue then
GetValue;
end;
end;

end.
 
国外有较好的脚本引擎,我刚用了一个CasScript,支持函数,对象,
你可以到torrys.net / vcl / tools / script找找。
 
好象已经把分给出了,怎么还要分一次呀???
 
后退
顶部