计算一个加减乘除表达式的例子:unit compute;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Math;type TForm1 = class(TForm) Edit1: TEdit; Button1: TButton; Edit2: TEdit; procedure Button1Click(Sender: TObject); private { Private declarations } s: string; function GetNumber(): real; function comp(a, b: char): char; function cal(a, b: real; p: char): real; function expr(): real; public { Public declarations } end;var Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject); var r: real; begin s := edit1.Text; //edit1中为要求值的表达式 r := expr(); // 调用求值函数 edit2.Text := floattostr(r); //将求值结果写到eidt2中 end;function TForm1.cal(a, b: real; p: char): real; begin case p of '+': result := a + b; '-': result := a - b; '*': result := a * b; '/': begin if b = 0 then begin showmessage('除数为0'); result := 0; end else result := a / b; end; end; end;function TForm1.comp(a, b: char): char; begin if not (a in ['+', '-', '*', '/', '(', ')', '#']) or not (b in ['+', '-', '*', '/', '(', ')', '#']) then result := 'e' else case a of '+', '-': case b of '*', '/', '(': result := '<'; else result := '>'; end; '*', '/': if b = '(' then result := '<' else result := '>'; '(': if b = ')' then result := '=' else if b = '#' then result := 'e' else result := '<'; ')': if b = '(' then result := 'e' else result := '>'; '#': if b = ')' then result := 'e' else if b = '#' then result := 'R' else result := '<'; end; end; function TForm1.expr(): real; var res, ch: char; oprTop, numTop: integer; opr: array[1..100] of char; num: array[1..100] of real;begin opr[1] := '#'; s := s + '#'; oprTop := 1; numTop := 0; res := ' '; repeat if s[1] in ['0'..'9'] then begin inc(numTop); num[numTop] := GetNumber(); end else begin ch := s[1]; delete(s, 1, 1); repeat res := comp(opr[oprTop], ch); case res of '>': begin num[numTop - 1] := cal(num[numTop - 1], num[numtop], opr[oprTop]); dec(numTop); dec(oprTop); end; '<': begin inc(oprTop); opr[oprTop] := ch; end; '=': begin dec(oprTop); end; 'e': begin showmessage('表达式出错!'); result := 0; exit; end; 'R': begin result := num[numTop]; end; end; until res <> '>'; end; until res = 'R'; end; function TForm1.GetNumber(): real; var i, code: integer; begin i := 1; while (i <= length(s)) and (s[i] in ['0'..'9', '.']) do inc(i); val(copy(s, 1, i - 1), result, code); delete(s, 1, i - 1); end; end.
你一些思路,希望对你有些帮助:语法分析方法:递归下降分析方法 语法规则: SimpleStatement ->Designator ':=' Expression Expression -> SimpleExpression [RelOp SimpleExpression]... SimpleExpression -> ['+' | '-'] Term [AddOp Term]... Term -> Factor [MulOp Factor]... Factor -> Designator ['(' ExprList ')'] -> '@' Designator -> Number -> String -> NIL 分析子程序: function ExprList:pTreeNode; function Exp:pTreeNode; function Simple_exp:pTreeNode; function Term:pTreeNode; function Factor:pTreeNode; .... function TParserTree.Term:pTreeNode;//term分析子程序 var t,p:pTreeNode; begin t:=factor; while (AToken.Token.TokenKind=tkmult) or(AToken.Token.TokenKind=tkdiv) do begin p:=newExpNode(opk); if p<>nil then begin p.LChild:=t; p.operator:=AToken.Token.Data; p.IdName:=Atoken.Token.Data; t:=p; match(AToken.Token.TokenKind); t.RChild:=factor; end; end; result:=t; end;
这个问题其实很简单,有两种思路 思路(1): 1。词法分析 2、语法分析可以采用底归下降底分析方法,在语法分析过程中构造出一颗二叉树 其节点数据结构定义: type pTreeNode=^TTreeNode; TTreeNode=record Val : Double; // 节点的值 operator:string[20]; // 操作符 IdName:string[20]; // 标识符的值 NodeType:ExpKind; // 结点类型 Lchild:pTreeNode; // 左孩子节点 Rchild:pTreeNode; // 右孩子节点 end; 3:进行计算,通过后续遍历这颗二叉树进行计算 我现在做的这个表达式计算,可以支持自定义函数,并且支持不定参数的计算,如sum(a,b...任意多个),而且表达式里面也可以嵌套表达式,如sum(a,sum(a,b,c))+4/5 这种思路最关键的是要在内存中构造出一颗二叉树,通过递归调用,计算出表达式的值。 function TParserTree.ComputerTree(Tree:pTreeNode;var ParamList:string):Double; //后续计算表达式的值; var ret1,ret2:double; arr:mytype; i:integer; ret:double; begin if Tree<>nil then begin ret1:=ComputerTree(Tree^.Lchild,Paramlist); ret2:=ComputerTree(Tree^.Rchild,ParamList); case Tree.NodeType of opk : begin if tree.operator='+' then result:=ret1+ret2 else if tree.operator='-' then result:=ret1-ret2 else if tree.operator='*' then result:=ret2*ret1 else if tree.operator='/' then if ret2<>0 then result:=ret1/ret2 ........
思路2: 类似思路1: 1)词法分析 2)语法分析,构造语法树(实际为二叉树) 3)后续遍历语法树,得到表达式的逆波兰表达式 4)通过一遍扫描,计算后续表达式的值 付:计算后续表达式的算法: function read(Expression:string;var idx:integer):string; var ret:string; begin ret:=''; if idx<=length(Expression) then begin while (Expression[idx]<>' ' )and (idx<=length(Expression))do begin ret:=ret+Expression[idx]; inc(idx); end; end; inc(idx);//使Idx指向非空元素; if Expression[idx]=' 'then inc(idx); //两个空格表示当前字符是参数之一; result:=ret; end; function sum(a,b:double):double;//自定义函数 begin result:=a+b; end;function square(x:double):double;//自定义函数 begin result:=x*x; end;function Multy(a,b,c:double):double; begin result:=a-c+b; end;procedure Computer_Expression(Expression:string); var idx:integer; Op:string;//从字符串中读取的元素; op1,op2,op3,ret:Double; stk:TStackCls; cRet:string; begin idx:=1; stk:=TStackCls.Create; while idx<=length(Expression)do begin op:=read(trim(Expression),idx); if trim(op)='+' then begin op1:=strtofloat(stk.pop); op2:=strtofloat(stk.pop); ret:=op1+op2; stk.push(floattostr(ret)); end else if trim(op)='-' then begin op1:=strtofloat(stk.pop); // Pop(S)弹出减数 op2:=strtofloat(stk.pop); //Pop(S)弹出的是被减数 ret:=op2-op1; stk.push(floattostr(ret)); end else if trim(op)='*' then begin op1:=strtofloat(stk.pop); op2:=strtofloat(stk.pop); ret:=op1*op2; stk.push(floattostr(ret)); end else if trim(op)='/' then begin op1:=strtofloat(stk.pop); // Pop(S)弹出除数 if(op1<>0.0)then ret:=strtofloat(stk.pop)/op1 //Pop(S)弹出的是被除数 else //除数为0时终止运行 begin showmessage('div by zero'); exit; end; stk.push(floattostr(ret)); end else if trim(op)='sum'then begin op1:=strtofloat(stk.pop); op2:=strtofloat(stk.pop); ret:=sum(op1,op2); stk.push(floattostr(ret)); end else if trim(op)='square'then begin op1:=strtofloat(stk.pop); ret:=square(op1); stk.push(floattostr(ret)); end else if trim(op)='multy'then begin op1:=strtofloat(stk.pop); op2:=strtofloat(stk.pop); op3:=strtofloat(stk.pop); ret:=multy(op3,op2,op1); stk.push(floattostr(ret)); end else begin stk.push(op); end; end; if not stk.IsEmpty then cRet:=stk.pop; if not stk.IsEmpty then begin showmessage('参数数目不匹配,请重新输入!!!'); end else showmessage('计算结果='+cRet); stk.Free; end;procedure TForm1.Button2Click(Sender: TObject); var pp:TparserTree; str:string; begin pp:=tparserTree.create; str:='sum(9,sum(3,4))+(8*9+888)+(9-(4))*3/8+((5-(8)))'; pp.Atoken.Origin:=pchar(str); form2.Memo1.Clear; form2.Memo2.Clear; form2.Memo3.Clear; form2.Memo1.Lines.Add(str); pp.SyntaxTreeShow; form2.ShowModal; Computer_Expression(pp.postExpression); pp.Free; end;两种思想对比: 思路一较思路二 效率高,在后续遍历的过程中就进行计算, 支持不定数目参数的自定义函数, 出错处理比较容易 支持表达式嵌套 思路二,计算方法比较容易,只能支持固定数目的自定义函数,支持表达式嵌套 这方面的计算还要一种比较经典的思路:算法优先算法,比较简单就不多说了。
shellexec('cal.exe')
呵呵
ms scripting
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Math;type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Edit2: TEdit;
procedure Button1Click(Sender: TObject); private
{ Private declarations }
s: string;
function GetNumber(): real;
function comp(a, b: char): char;
function cal(a, b: real; p: char): real;
function expr(): real;
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
var r: real;
begin
s := edit1.Text; //edit1中为要求值的表达式
r := expr(); // 调用求值函数
edit2.Text := floattostr(r); //将求值结果写到eidt2中
end;function TForm1.cal(a, b: real; p: char): real;
begin
case p of
'+': result := a + b;
'-': result := a - b;
'*': result := a * b;
'/':
begin
if b = 0 then
begin
showmessage('除数为0');
result := 0;
end
else
result := a / b;
end;
end;
end;function TForm1.comp(a, b: char): char;
begin
if not (a in ['+', '-', '*', '/', '(', ')', '#']) or not (b in ['+', '-', '*', '/', '(', ')', '#']) then result := 'e'
else
case a of
'+', '-': case b of
'*', '/', '(': result := '<';
else result := '>';
end;
'*', '/': if b = '(' then result := '<' else result := '>';
'(': if b = ')' then result := '=' else if b = '#' then result := 'e' else result := '<';
')': if b = '(' then result := 'e' else result := '>';
'#': if b = ')' then result := 'e' else if b = '#' then result := 'R' else result := '<';
end;
end;
function TForm1.expr(): real;
var
res, ch: char;
oprTop, numTop: integer;
opr: array[1..100] of char;
num: array[1..100] of real;begin opr[1] := '#';
s := s + '#';
oprTop := 1;
numTop := 0;
res := ' ';
repeat
if s[1] in ['0'..'9'] then
begin
inc(numTop);
num[numTop] := GetNumber();
end
else
begin
ch := s[1];
delete(s, 1, 1);
repeat
res := comp(opr[oprTop], ch);
case res of
'>': begin
num[numTop - 1] := cal(num[numTop - 1], num[numtop], opr[oprTop]);
dec(numTop);
dec(oprTop);
end;
'<': begin
inc(oprTop);
opr[oprTop] := ch;
end;
'=': begin
dec(oprTop);
end;
'e': begin
showmessage('表达式出错!');
result := 0;
exit;
end;
'R': begin
result := num[numTop];
end;
end;
until res <> '>';
end;
until res = 'R';
end;
function TForm1.GetNumber(): real;
var
i, code: integer;
begin
i := 1;
while (i <= length(s)) and (s[i] in ['0'..'9', '.']) do inc(i);
val(copy(s, 1, i - 1), result, code);
delete(s, 1, i - 1);
end;
end.
语法规则:
SimpleStatement ->Designator ':=' Expression
Expression -> SimpleExpression [RelOp SimpleExpression]...
SimpleExpression -> ['+' | '-'] Term [AddOp Term]...
Term -> Factor [MulOp Factor]...
Factor -> Designator ['(' ExprList ')']
-> '@' Designator
-> Number
-> String
-> NIL
分析子程序:
function ExprList:pTreeNode;
function Exp:pTreeNode;
function Simple_exp:pTreeNode;
function Term:pTreeNode;
function Factor:pTreeNode;
....
function TParserTree.Term:pTreeNode;//term分析子程序
var t,p:pTreeNode;
begin
t:=factor;
while (AToken.Token.TokenKind=tkmult) or(AToken.Token.TokenKind=tkdiv) do
begin
p:=newExpNode(opk);
if p<>nil then
begin
p.LChild:=t;
p.operator:=AToken.Token.Data;
p.IdName:=Atoken.Token.Data;
t:=p;
match(AToken.Token.TokenKind);
t.RChild:=factor;
end;
end;
result:=t;
end;
思路(1):
1。词法分析
2、语法分析可以采用底归下降底分析方法,在语法分析过程中构造出一颗二叉树
其节点数据结构定义:
type
pTreeNode=^TTreeNode;
TTreeNode=record
Val : Double; // 节点的值
operator:string[20]; // 操作符
IdName:string[20]; // 标识符的值
NodeType:ExpKind; // 结点类型
Lchild:pTreeNode; // 左孩子节点
Rchild:pTreeNode; // 右孩子节点
end;
3:进行计算,通过后续遍历这颗二叉树进行计算
我现在做的这个表达式计算,可以支持自定义函数,并且支持不定参数的计算,如sum(a,b...任意多个),而且表达式里面也可以嵌套表达式,如sum(a,sum(a,b,c))+4/5
这种思路最关键的是要在内存中构造出一颗二叉树,通过递归调用,计算出表达式的值。
function TParserTree.ComputerTree(Tree:pTreeNode;var ParamList:string):Double; //后续计算表达式的值;
var
ret1,ret2:double;
arr:mytype;
i:integer;
ret:double;
begin
if Tree<>nil then
begin
ret1:=ComputerTree(Tree^.Lchild,Paramlist);
ret2:=ComputerTree(Tree^.Rchild,ParamList);
case Tree.NodeType of
opk : begin
if tree.operator='+' then result:=ret1+ret2
else if tree.operator='-' then result:=ret1-ret2
else if tree.operator='*' then result:=ret2*ret1
else if tree.operator='/' then
if ret2<>0 then
result:=ret1/ret2
........
类似思路1:
1)词法分析
2)语法分析,构造语法树(实际为二叉树)
3)后续遍历语法树,得到表达式的逆波兰表达式
4)通过一遍扫描,计算后续表达式的值
付:计算后续表达式的算法:
function read(Expression:string;var idx:integer):string;
var
ret:string;
begin
ret:='';
if idx<=length(Expression) then
begin
while (Expression[idx]<>' ' )and (idx<=length(Expression))do
begin
ret:=ret+Expression[idx];
inc(idx);
end;
end;
inc(idx);//使Idx指向非空元素;
if Expression[idx]=' 'then
inc(idx); //两个空格表示当前字符是参数之一;
result:=ret;
end;
function sum(a,b:double):double;//自定义函数
begin
result:=a+b;
end;function square(x:double):double;//自定义函数
begin
result:=x*x;
end;function Multy(a,b,c:double):double;
begin
result:=a-c+b;
end;procedure Computer_Expression(Expression:string);
var
idx:integer;
Op:string;//从字符串中读取的元素;
op1,op2,op3,ret:Double;
stk:TStackCls;
cRet:string;
begin
idx:=1;
stk:=TStackCls.Create;
while idx<=length(Expression)do
begin
op:=read(trim(Expression),idx);
if trim(op)='+' then
begin
op1:=strtofloat(stk.pop);
op2:=strtofloat(stk.pop);
ret:=op1+op2;
stk.push(floattostr(ret));
end
else if trim(op)='-' then
begin
op1:=strtofloat(stk.pop); // Pop(S)弹出减数
op2:=strtofloat(stk.pop); //Pop(S)弹出的是被减数
ret:=op2-op1;
stk.push(floattostr(ret));
end
else if trim(op)='*' then
begin
op1:=strtofloat(stk.pop);
op2:=strtofloat(stk.pop);
ret:=op1*op2;
stk.push(floattostr(ret));
end
else if trim(op)='/' then
begin
op1:=strtofloat(stk.pop); // Pop(S)弹出除数
if(op1<>0.0)then
ret:=strtofloat(stk.pop)/op1 //Pop(S)弹出的是被除数
else //除数为0时终止运行
begin
showmessage('div by zero');
exit;
end;
stk.push(floattostr(ret));
end
else if trim(op)='sum'then
begin
op1:=strtofloat(stk.pop);
op2:=strtofloat(stk.pop);
ret:=sum(op1,op2);
stk.push(floattostr(ret));
end
else if trim(op)='square'then
begin
op1:=strtofloat(stk.pop);
ret:=square(op1);
stk.push(floattostr(ret));
end
else if trim(op)='multy'then
begin
op1:=strtofloat(stk.pop);
op2:=strtofloat(stk.pop);
op3:=strtofloat(stk.pop);
ret:=multy(op3,op2,op1);
stk.push(floattostr(ret));
end
else
begin
stk.push(op);
end;
end;
if not stk.IsEmpty then
cRet:=stk.pop;
if not stk.IsEmpty then
begin
showmessage('参数数目不匹配,请重新输入!!!');
end
else
showmessage('计算结果='+cRet);
stk.Free;
end;procedure TForm1.Button2Click(Sender: TObject);
var pp:TparserTree;
str:string;
begin
pp:=tparserTree.create;
str:='sum(9,sum(3,4))+(8*9+888)+(9-(4))*3/8+((5-(8)))';
pp.Atoken.Origin:=pchar(str);
form2.Memo1.Clear;
form2.Memo2.Clear;
form2.Memo3.Clear;
form2.Memo1.Lines.Add(str);
pp.SyntaxTreeShow;
form2.ShowModal;
Computer_Expression(pp.postExpression);
pp.Free;
end;两种思想对比:
思路一较思路二
效率高,在后续遍历的过程中就进行计算,
支持不定数目参数的自定义函数,
出错处理比较容易
支持表达式嵌套
思路二,计算方法比较容易,只能支持固定数目的自定义函数,支持表达式嵌套
这方面的计算还要一种比较经典的思路:算法优先算法,比较简单就不多说了。