主要是进行字符串处理,可以这样,假定str存放着那个字符串表达式‘mysum(7,5) + mysum(6,3)’ 那么 function Calcular(str:string):integer; var ii,i:integer; ss,d,k:integer; begin ss:=0; if pos('mysum',str)=0 then begin i:=pos('(',str);//查找左括号位置 ii:=pos(',',str);//查找逗号位置 d:=strtoint(copy(str,i+1,ii-i-1));//取得第一个参数 i:=pos(')',str);//查找右括号位置 k:=strtoint(copy(str,ii+1,i-ii-1));//取得第二个参数 ss:=ss+mysum(d,k); delete(str,1,i);//从字符串把第一个函数删除掉,以便继续处理 end; if pos('+',str)=0 then //判断后面的是不是加号,如果是再处理 begin end; ...如此处理下去就可以了,当然我上面仅仅给你处理了下那个mysum函数,其它的你照着进行就可以了... end;
TO suton 不太明白你的意思。能不能说得再详细点?TO hys_427 你的方法只能处理这个特定的表达式。而我要处理的表达式是用户随机输入的,而且函数也不止这一个啊,再者还可能函数嵌套。我需要一个完善解决的方法。各位请多多指教啊。
function TCalculator.Calc(const Expression: String): Double; begin CalcExpression := Expression; Result := Calc; end;function TCalculator.CalcBool: Boolean; var FR: Double; begin FR := Calc; Result := not IsZero(FR, CONST_EPSILON); end;function TCalculator.CalcBool(const Expression: String): Boolean; var FR: Double; begin FR := Calc(Expression); Result := not IsZero(FR, CONST_EPSILON); end;procedure TCalculator.ClearParam; begin SetLength(FParamArray, 0); end;constructor TCalculator.Create; begin ClearParam; AddParam('INF', Infinity); AddParam('PI', PI); end;destructor TCalculator.Destroy; begin ClearParam; inherited; end;procedure TCalculator.DoCalc; function CalcSingle(const AOperator: TOperator): Double; // 单目操作符 var iLoop: Integer; Base: Double; begin Result := 0.00; Base := PopNumber; case AOperator of // case oNot: Result := IfThen(IsZero(Base, CONST_EPSILON), 1, 0); // oABS: Result := Abs(Base); oSqr: Result := Sqr(Base); oSqt: Result := Sqrt(Abs(Base)); oLn: Result := Ln(Base); oFact: begin Result := Round(Base); for iLoop := Round(Base) - 1 downto 1 do try Result := Result * iLoop; except Result := Infinity; end; end; oSin: Result := Sin(Base); oCos: Result := Cos(Base); oTan: Result := Tan(Base); oCot: Result := Cot(Base); end; // end case end; function CalcDouble(const AOperator: TOperator): Double; // 双目操作符 var Base, Exponent: Double; begin Result := 0.00; Exponent := PopNumber; Base := PopNumber; case AOperator of // case oPower, oPow: Result := Power(Base, Exponent); oMulitiple: Result := Base * Exponent; oDevide: if SameValue(Exponent, 0) then Result := Infinity else Result := Base / Exponent; oMod: if SameValue(Round(Exponent), 0) then Result := Infinity else Result := Round(Base) mod Round(Exponent); oAdd: Result := Base + Exponent; oSub: Result := Base - Exponent; oLog: Result := LogN(Base, Exponent); oLdexp: Result := Ldexp(Base, Round(Exponent)); oGreater: Result := IfThen(Base > Exponent, 1, 0); oLess: Result := IfThen(Base < Exponent, 1, 0); oNoGreater: Result := IfThen(Base <= Exponent, 1, 0); oNoLess: Result := IfThen(Base >= Exponent, 1, 0); oEqual: Result := IfThen((Base = Exponent) or SameValue(Base, Exponent, CONST_EPSILON), 1, 0); oUnEqual: Result := IfThen((Base = Exponent) or SameValue(Base, Exponent, CONST_EPSILON), 0, 1); oAnd: Result := IfThen((Base > CONST_EPSILON) and (Exponent > CONST_EPSILON), 1, 0); oOr: Result := IfThen((Base > CONST_EPSILON) or (Exponent > CONST_EPSILON), 1, 0); end; end;var Operator: TOperator; FCalcResult: Double; begin Operator := PopOperator; if not (Operator in [oBracketL, oBracketR]) then begin case Operators[Operator].OperandCount of // case 1: FCalcResult := CalcSingle(Operator); 2: FCalcResult := CalcDouble(Operator); else FCalcResult := 0.00; // case else end; // end case PushNumber(FCalcResult); // 计算结果入栈 end; end;function TCalculator.GetOperatorType(const AChar: Char): TOperator; var iLoop: TOperator; begin Result := TOperator(-1); for iLoop := Low(TOperator) to High(TOperator) do // Iterate if AChar = Operators[iLoop].Operator then begin Result := iLoop; Break; end; end;procedure TCalculator.ParseChar(const AChar: Char); function GetCalcCharState(const AChar: Char): TCalcState; begin Result := csParam; if AChar in SetOfNumber then Result := csNumber else if GetOperatorType(AChar) in [Low(TOperator)..High(TOperator)] then Result := csOperator; end; var CalcCharState: TCalcState; TempDouble: Double; begin CalcCharState := GetCalcCharState(AChar); try case CalcCharState of // case csNumber, csParam: FCalcString := FCalcString + AChar; csOperator: begin case FCalcState of // case csNumber: if TryStrToFloat(FCalcString, TempDouble) then PushNumber(TempDouble) else raise Exception.Create('Invalid Number Input!'); csParam: if not PushParam(FCalcString) then raise Exception.Create('Invalid Parameter Input!'); end; // end case FCalcString := ''; if not PushOperator(GetOperatorType(AChar)) then raise Exception.Create('Invalid Operator Input!'); end; end; // end case finally FCalcState := CalcCharState; // 保存当前字符类型 end; end;function TCalculator.PeekOperator: TOperator; begin Result := TOperator(FStackOperators.Peek); end;function TCalculator.PopNumber: Double; begin Result := Double(FStackNumbers.Pop); end;function TCalculator.PopOperator: TOperator; begin Result := TOperator(FStackOperators.Pop); end;function TCalculator.PushNumber(const ANumber: Double): Boolean; begin Result := FStackNumbers.Push(ANumber); end;function TCalculator.PushOperator(const AOperator: TOperator): Boolean; function OperatorCanPush: Boolean; var oOperator: TOperator; begin Result := True; if FStackOperators.Count > 0 then begin oOperator := PeekOperator; // 得到栈顶操作符 Result := (oOperator = oBracketL) or (Operators[AOperator].Rights < Operators[oOperator].Rights); end; end;begin Result := True; if AOperator <> oComma then begin { 判断入栈操作符与栈顶操作符优先级 } while not OperatorCanPush do DoCalc; if AOperator <> oBracketR then Result := FStackOperators.Push(AOperator) else begin PopOperator; Result := True; end; end; end;
还有个尾巴function TCalculator.PushParam(const AParam: String): Boolean; var iLoop: Integer; begin Result := False; for iLoop := Low(FParamArray) to High(FParamArray) do // Iterate begin // SameText is not Case Sensitive if SameText(FParamArray[iLoop].Param, AParam) then begin Result := PushNumber(FParamArray[iLoop].Value); Break; end; end; // end for end;procedure TCalculator.SetCalcExpression(const Value: String); function StringReplaceEx(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string; var SearchStr, Patt, NewStr: string; Offset: Integer; begin if rfIgnoreCase in Flags then begin SearchStr := UpperCase(S); Patt := UpperCase(OldPattern); end else begin SearchStr := S; Patt := OldPattern; end; NewStr := S; Result := ''; while SearchStr <> '' do begin Offset := Pos(Patt, SearchStr); if Offset = 0 then begin Result := Result + NewStr; Break; end; Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); if not (rfReplaceAll in Flags) then begin Result := Result + NewStr; Break; end; SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); end; end;var iLoop: TOperator; PseudoCode: String; Operator: String; RFlag: TReplaceFlags; begin FCalcExpression := StringReplaceEx(Value, ' ', '', [rfReplaceAll]); // 替换伪代码 RFlag := [rfReplaceAll, rfIgnoreCase]; for iLoop := Low(TOperator) to High(TOperator) do begin PseudoCode := Trim(Operators[iLoop].Pseudocode); if Length(PseudoCode) <> 0 then begin Operator := Operators[iLoop].Operator; FCalcExpression := StringReplaceEx(FCalcExpression, Pseudocode, Operator, RFlag); end; end; end;end.
TO budded 这么工整的代码啊,我一定得好好看看。谢谢了。
{首先向楼上各位无私奉献的朋友学习了然后我也写了一段, 只是提供一个思路, 通用性极不强, 楼主可以无视而过}unit Unit1;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure Test(Str: string); published function MyFunc1(A, B: integer): integer; function MyFunc2(A, B: integer): integer; end;var Form1: TForm1;implementation{$R *.dfm}{ TForm1 }function TForm1.MyFunc1(A, B: integer): integer; begin Result := A + B; end;function TForm1.MyFunc2(A, B: integer): integer; begin Result := A * B; end;procedure TForm1.Test(Str: string); var I, J: integer; FuncName: string; Var1, Var2: integer; SS: TStringList; pFunc: Pointer; Rst: integer; begin Str := StringReplace(Str, #32, '', [rfReplaceAll]); FuncName := Copy(Str, 1, Pos('(', Str)-1); SS := TStringList.Create; I := Pos('(', Str); J := Pos(')', Str); SS.Text := StringReplace(Copy(Str, I+1, J-I-1), ',', #10, [rfReplaceAll]); try Var1 := StrtoInt(SS[0]); except Var1 := PInteger(Self.FieldAddress(SS[0]))^; end; try Var2 := StrtoInt(SS[1]); except Var2 := PInteger(Self.FieldAddress(SS[1]))^; end; pFunc := Self.MethodAddress(FuncName); asm mov eax, Self mov edx, Var1 mov ecx, Var2 call [pFunc] mov Rst, eax end; Showmessage(InttoStr(Rst)); SS.Free; end;procedure TForm1.Button1Click(Sender: TObject); begin Test('MyFunc1(55,44)'); Test('MyFunc2(3,5)'); end;end.
使用显示加载的方式.
在GetProcAddress函数里面,可以将函数名以文本的方式传进去
那么
function Calcular(str:string):integer;
var
ii,i:integer;
ss,d,k:integer;
begin
ss:=0;
if pos('mysum',str)=0 then
begin
i:=pos('(',str);//查找左括号位置
ii:=pos(',',str);//查找逗号位置
d:=strtoint(copy(str,i+1,ii-i-1));//取得第一个参数
i:=pos(')',str);//查找右括号位置
k:=strtoint(copy(str,ii+1,i-ii-1));//取得第二个参数
ss:=ss+mysum(d,k);
delete(str,1,i);//从字符串把第一个函数删除掉,以便继续处理
end;
if pos('+',str)=0 then //判断后面的是不是加号,如果是再处理
begin
end;
...如此处理下去就可以了,当然我上面仅仅给你处理了下那个mysum函数,其它的你照着进行就可以了...
end;
不太明白你的意思。能不能说得再详细点?TO hys_427
你的方法只能处理这个特定的表达式。而我要处理的表达式是用户随机输入的,而且函数也不止这一个啊,再者还可能函数嵌套。我需要一个完善解决的方法。各位请多多指教啊。
2、调用函数,取得返回值,然后按照运算法则进行运算,求得结果。现在关键是如何在用户输入的字符串中找到这个mysum函数,并获得这个函数的变量。
1:只是求值的可用Colin Wilson 的 TExpressionEvaluator,那个可以计算一般表达式的值,但不能定义函数
2:可自定义函数的,可用RxLib的TRxCalculator,它可定义函数,但功能一般
3:可直接运行VBScript/JAVAScript的MicroSoft Script Control,它可以直接在delphi中安装,并能在delphi中运行VBScript/JAVAScript。
你的实现:
ScriptControl1.Language:='JavaScript';
ScriptControl1.ExecuteStatement('x=10;y=100');
ScriptControl1.ExecuteStatement('function mysum(a,b) { return a+b; }');
ShowMessage(ScriptControl1.Eval('mysum(7,5) + mysum(6,3)'));
4.pascal_interpreter:支持简单的Pascal Scrip,可在用户界面编译运行pascal脚本
5.更强大的可使用RemObjects Pascal Script,它支持强大的pascal脚本(inno setup就用它)
我没太明白2楼的意思,你明白吗?
你的思路和hys_427相似,可以通过字符串比较判断是否是函数名,然后调用相应函数求值。不过这种方法似乎不够科学,也不知道能不能处理所有情况。
果然高手。
1是不行的
2我没试过,你说功能一般,估计不能满足我的要求。
3我听说过,没用过,不知道处理复杂函数好用不好用,再就是如果里面有变量怎么处理?变量可能来自于程序的其他部分。
4、5 我就不知道了,得研究研究了。
希望这里面有满足需要的方案。
谢谢啊。希望高手们能给出更多更好的解决方案。讨论出一个既简单又完善的结果来。
procedure TForm1.FormActivate(Sender: TObject);
begin
ScriptControl1.Language:='JavaScript';
ScriptControl1.ExecuteStatement('function mysum(a,b) { return a+b; }');
//你还可以定义更多的函数
end;procedure TForm1.Button1Click(Sender: TObject);
begin
Edit2.Text:= ScriptControl1.Eval(Edit1.Text);
end;你在Edit1中写mysum(7,5) + mysum(6,3),按Button1,Edit2就为21
当然,你可以在Edit1中写任何符合JAVAScript的表达式,都可以,如:
x=1;y=2;x+100*y 结果为201
你甚至可以在edit1中写自己的函数,如
function test(x,y) { return x-y; } ; test(100,2)
结果为98
再写test(1,2)
结果为-1
当然,你可以将计算写在程序中,如:
procedure TForm1.Button2Click(Sender: TObject);
var
s:string;
begin
s:='mysum(7,5) + mysum(6,3)';
Edit2.Text:= ScriptControl1.Eval(s);
end;结果为21;
:----->
JAVAScript是一门语言,任何复杂的函数基本都能处理,何况它自己有一套函数
---------------------------
再就是如果里面有变量怎么处理?变量可能来自于程序的其他部分
:--->
当然可以,就按上面的例子:
rocedure TForm1.Button2Click(Sender: TObject);
var
x1,y1:integer;
x2,y2:integer;
s:string;
begin
x1:=7;
y1:=5;
x2:=6;
y2:=3;
s:=format('mysum(%d,%d) + mysum(%d,%d)',[x1,y1,x2,y2]);
Edit2.Text:= ScriptControl1.Eval(s);
end;
遇到问题,首先要根据问题选择顺手的工具。
再比如,要做一个动画,还是Flash方便;要处理一幅图,可以用PhotoShop。
函数作为一个字符串传给ScriptControl,可是字符串长度有限,函数体很长怎么处理?我试了,ScriptControl1.ExecuteStatement('function mysum(a,b)');
ScriptControl1.ExecuteStatement('{ return a+b; }');
这样写执行会出错啊。
如果都是基本类型,MicroSoft Script Control可以处理,如double,你也可转成string传给MSC
但如果是复杂类型,你要将它传给MSC,就比较繁了(但不是不能处理)
如果楼主一定要一个符合PASCAL的角本,那可以好好研究下RemObjects Pascal Script,如果用过inno setup
就可以知道它的强大功能了
我要实现的这个功能是一个程序的一部分,所以就局限在delphi的开发工具上了。
我也只想能解决当前的需求就好,可是这个需求比我在题目中说的复杂,我在“地基”那里只是举了个例子。
实际上字符串表达式里包括自定义函数,函数参数可能是指针或者记录类型也可能是个全局变量,这样一个综合的表达式求值问题才是我要解决的。
还请多多指教。
{ @UnitName : uStack.pas }
{ @Project : Common }
{ @Copyright : Budded Software Studio }
{ @Author : Budded }
{ @Description : }
{ @FileVersion : 1.0.0.0 }
{ @CreateDate : 2005-03-01 }
{ @Comment : }
{ @LastUpdate : Budded, 2005-03-01 }
{ @History : Created By Budded, 2005-03-01 11:00 }
{******************************************************************************}
unit uStack;interfaceuses
Classes, Variants;type
TArrayVariant = array of Variant; TStack = class
private
FList: TArrayVariant;
function GetCount: Integer;
public
constructor Create;
destructor Destroy; override; property Count: Integer read GetCount;
function Push(const Value: Variant): Boolean;
function Peek: Variant;
function Pop: Variant;
end;
implementationuses SysUtils;{ TStack }const
CONST_ERROR_NODATA = 'Error: There''s no data in the Stack!';constructor TStack.Create;
begin
SetLength(FList, 0);
end;destructor TStack.Destroy;
begin
SetLength(FList, 0); inherited;
end;function TStack.GetCount: Integer;
begin
Result := Length(FList);
end;function TStack.Peek: Variant;
begin
if Count > 0 then
Result := FList[Count - 1]
else raise Exception.Create(CONST_ERROR_NODATA);
end;function TStack.Pop: Variant;
begin
if Count > 0 then
begin
Result := FList[Count - 1];
SetLength(FList, Count - 1);
end
else raise Exception.Create(CONST_ERROR_NODATA);
end;function TStack.Push(const Value: Variant): Boolean;
begin
Result := True;
try
SetLength(FList, Count + 1);
FList[Count - 1] := Value;
except // wrap up
Result := False;
end; // try / except
end;end.
{ @UnitName : uCalculator.pas }
{ @Project : Common }
{ @Copyright : Budded Software Studio }
{ @Author : Budded }
{ @Description : 算术表达式解析器 }
{ @FileVersion : 1.0.0.0 }
{ @CreateDate : 2005-03-01 }
{ @Comment : 表达式自左向右解析,遵循左结合法则 }
{ @LastUpdate : Budded, 2005-03-01 }
{ @History : Created By Budded, 2005-03-01 11:00 }
{******************************************************************************}
unit uCalculator;interfaceuses
SysUtils, Classes, Types, uStack;type
// 参数类型
TParam = record
Param: String; // 参数
Value: Double; // 参数值
end;
TParamArray = array of TParam; // 参数列表类型 // 计算数据类型:None, 操作符,操作数,参数
TCalcState = (csNone, csOperator, csNumber, csParam); // // 操作符类型
TOperator = (
oPower, oMulitiple, oDevide, oMod, oAdd, oSub, // 数学算子
oABS, oPow, oSqr, oSqt, oLog, oLn, oLdexp, oFact, //
oSin, oCos, oTan, oCot, // 三角函数
oGreater, oLess, oNoGreater, oNoLess, oEqual, oUnEqual, // 关系算子
oAnd, oOr, oNot, // 逻辑算子
oComma, oBracketL, oBracketR); // 操作符类型
TOperatorRight = record
Operator: Char; // 操作符
Rights: Byte; // 运算优先级
Pseudocode: String[5]; // 伪代码
OperandCount: Byte; // 操作数个数
end; TCalculator = class(TObject)
private
FStackOperators: TStack; // 操作符堆栈
FStackNumbers: TStack; // 操作数堆栈 FCalcState: TCalcState; // 当前操作数类型
FCalcString: String; // 当前操作数零时变量 FParamArray: TParamArray; // 参数列表
FCalcExpression: String;
procedure SetCalcExpression(const Value: String);
function GetOperatorType(const AChar: Char): TOperator;
protected
procedure DoCalc; // 双目计算
procedure ParseChar(const AChar: Char); // 解析表达式中字符 function PushOperator(const AOperator: TOperator): Boolean; // 操作符入栈
function PushNumber(const ANumber: Double): Boolean; // 操作数入栈
function PushParam(const AParam: String): Boolean; // 变量入栈 function PopOperator: TOperator; // 操作符出栈
function PopNumber: Double; // 操作数出栈 function PeekOperator: TOperator; // 查看操作符
public
constructor Create;
destructor Destroy; override; // 计算表达式
property CalcExpression: String read FCalcExpression write SetCalcExpression;
function Calc: Double; overload;
function CalcBool: Boolean; overload;
function Calc(const Expression: String): Double; overload;
function CalcBool(const Expression: String): Boolean; overload; // 添加参数
procedure AddParam(const Param: String; const Value: Double);
procedure ClearParam;
end;
implementationuses
Math;{ TCalculator }const
CONST_EPSILON = 1e-10; SetOfNumber: Set of Char = ['0'..'9', '.']; // 操作数集合 Operators: array[TOperator]of TOperatorRight = // 操作符表
(
// 数学运算符
(Operator: '^'; Rights: 20; Pseudocode: ''; OperandCount: 2), // 乘方
(Operator: '*'; Rights: 30; Pseudocode: ''; OperandCount: 2), // 乘
(Operator: '/'; Rights: 30; Pseudocode: 'Div'; OperandCount: 2), // 除
(Operator: '%'; Rights: 30; Pseudocode: 'Mod'; OperandCount: 2), // 取模
(Operator: '+'; Rights: 40; Pseudocode: 'Plus'; OperandCount: 2), // 加
(Operator: '-'; Rights: 40; Pseudocode: 'Sub'; OperandCount: 2), // 减 // 扩展数学运算符 Operator预留段:#180--#255
(Operator: #180; Rights: 10; Pseudocode: 'ABS'; OperandCount: 1), // ABS(X)
(Operator: #181; Rights: 10; Pseudocode: 'Pow'; OperandCount: 2), // Pow(X, Y)
(Operator: #182; Rights: 10; Pseudocode: 'Sqr'; OperandCount: 1), // Sqr(X)
(Operator: #183; Rights: 10; Pseudocode: 'Sqt'; OperandCount: 1), // Sqrt(X)
(Operator: #184; Rights: 10; Pseudocode: 'Log'; OperandCount: 2), // Log(Base, Exp)
(Operator: #185; Rights: 10; Pseudocode: 'Ln'; OperandCount: 1), // Ln(X)
(Operator: #186; Rights: 10; Pseudocode: 'Ldexp'; OperandCount: 1), // Ldexp
(Operator: #187; Rights: 10; Pseudocode: 'Fact'; OperandCount: 1), // Factorial // 三角函数 预留段:#150--#179
(Operator: #150; Rights: 10; Pseudocode: 'Sin'; OperandCount: 1), // Sin
(Operator: #151; Rights: 10; Pseudocode: 'Cos'; OperandCount: 1), // Cos
(Operator: #152; Rights: 10; Pseudocode: 'Tan'; OperandCount: 1), // Tan
(Operator: #153; Rights: 10; Pseudocode: 'Cot'; OperandCount: 1), // Cotan // 关系运算符 预留段:#128--#149
(Operator: '>'; Rights: 50; Pseudocode: ''; OperandCount: 2), // 大于
(Operator: '<'; Rights: 50; Pseudocode: ''; OperandCount: 2), // 小于
(Operator: #128; Rights: 50; Pseudocode: '<='; OperandCount: 2), // 不大于
(Operator: #129; Rights: 50; Pseudocode: '>='; OperandCount: 2), // 不小于
(Operator: '='; Rights: 60; Pseudocode: ''; OperandCount: 2), // 等于
(Operator: #130; Rights: 60; Pseudocode: '<>'; OperandCount: 2), // 不等于 // 逻辑运算符
(Operator: '&'; Rights: 87; Pseudocode: 'and'; OperandCount: 2), // And
(Operator: '|'; Rights: 88; Pseudocode: 'or'; OperandCount: 2), // or
(Operator: '!'; Rights: 15; Pseudocode: 'not'; OperandCount: 1), // not, 单目操作符 // 其它运算符
(Operator: ','; Rights: 99; Pseudocode: ''; OperandCount: 0), // 逗号
(Operator: '('; Rights: 0; Pseudocode: ''; OperandCount: 0), // 左括号
(Operator: ')'; Rights: 100; Pseudocode: ''; OperandCount: 0) // 右括号
);
procedure TCalculator.AddParam(const Param: String; const Value: Double);
var
Len: Integer;
begin
if Length(Param) > 0 then
begin
Len := Length(FParamArray);
SetLength(FParamArray, Len + 1); FParamArray[Len].Param := Param;
FParamArray[Len].Value := Value;
end;
end;function TCalculator.Calc: Double;
var
iLoop: Integer;
begin
Result := 0.00;
FStackOperators := TStack.Create;
FStackNumbers := TStack.Create;
try
FCalcState := csNone;
for iLoop := 1 to Length(CalcExpression) do // Iterate
ParseChar(CalcExpression[iLoop]); ParseChar(Operators[oComma].Operator); while FStackOperators.Count > 0 do // 计算剩余
DoCalc; if FStackNumbers.Count = 1 then
Result := PopNumber; // 从栈中获取计算结果 if IsZero(Result, CONST_EPSILON) then
Result := 0.00;
finally // wrap up
FStackOperators.Free;
FStackNumbers.Free;
end; // try / finally
end;
begin
CalcExpression := Expression;
Result := Calc;
end;function TCalculator.CalcBool: Boolean;
var
FR: Double;
begin
FR := Calc;
Result := not IsZero(FR, CONST_EPSILON);
end;function TCalculator.CalcBool(const Expression: String): Boolean;
var
FR: Double;
begin
FR := Calc(Expression);
Result := not IsZero(FR, CONST_EPSILON);
end;procedure TCalculator.ClearParam;
begin
SetLength(FParamArray, 0);
end;constructor TCalculator.Create;
begin
ClearParam;
AddParam('INF', Infinity);
AddParam('PI', PI);
end;destructor TCalculator.Destroy;
begin
ClearParam; inherited;
end;procedure TCalculator.DoCalc; function CalcSingle(const AOperator: TOperator): Double; // 单目操作符
var
iLoop: Integer;
Base: Double;
begin
Result := 0.00;
Base := PopNumber; case AOperator of // case
oNot:
Result := IfThen(IsZero(Base, CONST_EPSILON), 1, 0); // oABS:
Result := Abs(Base);
oSqr:
Result := Sqr(Base);
oSqt:
Result := Sqrt(Abs(Base));
oLn:
Result := Ln(Base);
oFact:
begin
Result := Round(Base);
for iLoop := Round(Base) - 1 downto 1 do
try
Result := Result * iLoop;
except
Result := Infinity;
end;
end;
oSin:
Result := Sin(Base);
oCos:
Result := Cos(Base);
oTan:
Result := Tan(Base);
oCot:
Result := Cot(Base);
end; // end case
end;
function CalcDouble(const AOperator: TOperator): Double; // 双目操作符
var
Base, Exponent: Double;
begin
Result := 0.00; Exponent := PopNumber;
Base := PopNumber; case AOperator of // case
oPower, oPow:
Result := Power(Base, Exponent);
oMulitiple:
Result := Base * Exponent;
oDevide:
if SameValue(Exponent, 0) then
Result := Infinity
else Result := Base / Exponent;
oMod:
if SameValue(Round(Exponent), 0) then
Result := Infinity
else Result := Round(Base) mod Round(Exponent);
oAdd:
Result := Base + Exponent;
oSub:
Result := Base - Exponent;
oLog:
Result := LogN(Base, Exponent);
oLdexp:
Result := Ldexp(Base, Round(Exponent)); oGreater:
Result := IfThen(Base > Exponent, 1, 0);
oLess:
Result := IfThen(Base < Exponent, 1, 0);
oNoGreater:
Result := IfThen(Base <= Exponent, 1, 0);
oNoLess:
Result := IfThen(Base >= Exponent, 1, 0);
oEqual:
Result := IfThen((Base = Exponent) or SameValue(Base, Exponent, CONST_EPSILON), 1, 0);
oUnEqual:
Result := IfThen((Base = Exponent) or SameValue(Base, Exponent, CONST_EPSILON), 0, 1); oAnd:
Result := IfThen((Base > CONST_EPSILON) and (Exponent > CONST_EPSILON), 1, 0);
oOr:
Result := IfThen((Base > CONST_EPSILON) or (Exponent > CONST_EPSILON), 1, 0);
end;
end;var
Operator: TOperator;
FCalcResult: Double;
begin
Operator := PopOperator;
if not (Operator in [oBracketL, oBracketR]) then
begin
case Operators[Operator].OperandCount of // case
1: FCalcResult := CalcSingle(Operator);
2: FCalcResult := CalcDouble(Operator);
else FCalcResult := 0.00; // case else
end; // end case PushNumber(FCalcResult); // 计算结果入栈
end;
end;function TCalculator.GetOperatorType(const AChar: Char): TOperator;
var
iLoop: TOperator;
begin
Result := TOperator(-1);
for iLoop := Low(TOperator) to High(TOperator) do // Iterate
if AChar = Operators[iLoop].Operator then
begin
Result := iLoop;
Break;
end;
end;procedure TCalculator.ParseChar(const AChar: Char); function GetCalcCharState(const AChar: Char): TCalcState;
begin
Result := csParam;
if AChar in SetOfNumber then
Result := csNumber
else if GetOperatorType(AChar) in [Low(TOperator)..High(TOperator)] then
Result := csOperator;
end;
var
CalcCharState: TCalcState;
TempDouble: Double;
begin
CalcCharState := GetCalcCharState(AChar);
try
case CalcCharState of // case
csNumber, csParam:
FCalcString := FCalcString + AChar;
csOperator:
begin
case FCalcState of // case
csNumber:
if TryStrToFloat(FCalcString, TempDouble) then
PushNumber(TempDouble)
else raise Exception.Create('Invalid Number Input!');
csParam:
if not PushParam(FCalcString) then
raise Exception.Create('Invalid Parameter Input!');
end; // end case FCalcString := '';
if not PushOperator(GetOperatorType(AChar)) then
raise Exception.Create('Invalid Operator Input!');
end;
end; // end case
finally
FCalcState := CalcCharState; // 保存当前字符类型
end;
end;function TCalculator.PeekOperator: TOperator;
begin
Result := TOperator(FStackOperators.Peek);
end;function TCalculator.PopNumber: Double;
begin
Result := Double(FStackNumbers.Pop);
end;function TCalculator.PopOperator: TOperator;
begin
Result := TOperator(FStackOperators.Pop);
end;function TCalculator.PushNumber(const ANumber: Double): Boolean;
begin
Result := FStackNumbers.Push(ANumber);
end;function TCalculator.PushOperator(const AOperator: TOperator): Boolean; function OperatorCanPush: Boolean;
var
oOperator: TOperator;
begin
Result := True;
if FStackOperators.Count > 0 then
begin
oOperator := PeekOperator; // 得到栈顶操作符
Result := (oOperator = oBracketL) or
(Operators[AOperator].Rights < Operators[oOperator].Rights);
end;
end;begin
Result := True;
if AOperator <> oComma then
begin
{ 判断入栈操作符与栈顶操作符优先级 }
while not OperatorCanPush do
DoCalc; if AOperator <> oBracketR then
Result := FStackOperators.Push(AOperator)
else begin
PopOperator;
Result := True;
end;
end;
end;
var
iLoop: Integer;
begin
Result := False;
for iLoop := Low(FParamArray) to High(FParamArray) do // Iterate
begin
// SameText is not Case Sensitive
if SameText(FParamArray[iLoop].Param, AParam) then
begin
Result := PushNumber(FParamArray[iLoop].Value);
Break;
end;
end; // end for
end;procedure TCalculator.SetCalcExpression(const Value: String); function StringReplaceEx(const S, OldPattern, NewPattern: string;
Flags: TReplaceFlags): string;
var
SearchStr, Patt, NewStr: string;
Offset: Integer;
begin
if rfIgnoreCase in Flags then
begin
SearchStr := UpperCase(S);
Patt := UpperCase(OldPattern);
end else
begin
SearchStr := S;
Patt := OldPattern;
end;
NewStr := S;
Result := '';
while SearchStr <> '' do
begin
Offset := Pos(Patt, SearchStr);
if Offset = 0 then
begin
Result := Result + NewStr;
Break;
end;
Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern;
NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt);
if not (rfReplaceAll in Flags) then
begin
Result := Result + NewStr;
Break;
end;
SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt);
end;
end;var
iLoop: TOperator;
PseudoCode: String;
Operator: String;
RFlag: TReplaceFlags;
begin
FCalcExpression := StringReplaceEx(Value, ' ', '', [rfReplaceAll]); // 替换伪代码
RFlag := [rfReplaceAll, rfIgnoreCase];
for iLoop := Low(TOperator) to High(TOperator) do
begin
PseudoCode := Trim(Operators[iLoop].Pseudocode);
if Length(PseudoCode) <> 0 then
begin
Operator := Operators[iLoop].Operator;
FCalcExpression := StringReplaceEx(FCalcExpression, Pseudocode, Operator, RFlag);
end;
end;
end;end.
这么工整的代码啊,我一定得好好看看。谢谢了。
{首先向楼上各位无私奉献的朋友学习了然后我也写了一段, 只是提供一个思路, 通用性极不强, 楼主可以无视而过}unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations } procedure Test(Str: string); published function MyFunc1(A, B: integer): integer;
function MyFunc2(A, B: integer): integer; end;var
Form1: TForm1;implementation{$R *.dfm}{ TForm1 }function TForm1.MyFunc1(A, B: integer): integer;
begin
Result := A + B;
end;function TForm1.MyFunc2(A, B: integer): integer;
begin
Result := A * B;
end;procedure TForm1.Test(Str: string);
var
I, J: integer;
FuncName: string;
Var1, Var2: integer;
SS: TStringList;
pFunc: Pointer;
Rst: integer;
begin
Str := StringReplace(Str, #32, '', [rfReplaceAll]);
FuncName := Copy(Str, 1, Pos('(', Str)-1);
SS := TStringList.Create;
I := Pos('(', Str);
J := Pos(')', Str);
SS.Text := StringReplace(Copy(Str, I+1, J-I-1), ',', #10, [rfReplaceAll]);
try
Var1 := StrtoInt(SS[0]);
except
Var1 := PInteger(Self.FieldAddress(SS[0]))^;
end;
try
Var2 := StrtoInt(SS[1]);
except
Var2 := PInteger(Self.FieldAddress(SS[1]))^;
end;
pFunc := Self.MethodAddress(FuncName);
asm
mov eax, Self
mov edx, Var1
mov ecx, Var2
call [pFunc]
mov Rst, eax
end;
Showmessage(InttoStr(Rst));
SS.Free;
end;procedure TForm1.Button1Click(Sender: TObject);
begin
Test('MyFunc1(55,44)');
Test('MyFunc2(3,5)');
end;end.
那段汇编以及它前面一句 的作用是:寻到Func地址,然后将参数传入寄存器,并调用这个Func,返回值放入Rst。
如果有多个参数(不固定),可以通过计算,多余参数压栈处理----这个倒不是难关。现在问题有一个最大的难关是:前面的实现方法(包括我的),貌似都不能实现变量的处理。这是最大的难关。因为Delphi程序编译后,普通变量名字已不复存在,通过名字又何处去寻?即使象Func那样,可以利用RTTI,但普通变量做不到,至少需要成员变量是类类型的,或者接口类型的----但你要的是普通变量。
不太明白你的意思。处理这个问题不涉及到编译后的问题吧?
有变量的话也是在编译前就确定好的了,怎么涉及到编译后按变量名寻址呢?
1、你的程序如果用Delphi写,总是要编译后才能运行2、你的需求是:要在编译后运行过程中找源程序代码中的“变量”并让它参与运算3、Delphi程序编译后,在Pascal源代码中声明的变量名字(如var X:integer中的X),在可执行程序中已经不存在了,编译器直接把它们处理为地址。4、也正是因为如此,在无数层楼之前,我就建议你全部采用解释型的编程语言。解释型语言有真正意义上的宏替换可供你使用。宏替换
呵呵,是啊,忘了你说的这个第二条了。的确是编译后的寻址问题。
有进展了会告诉大家。
可以实现变量的传递,记录类型的支持,可惜不支持指针。使用RemObject Pascal Script,字符串表达式不用自己分析,所以代码写起来也比较容易。我准备采用这种方式了。积极讨论的我都想给分,可惜分数不多,大家多担待吧。