示例:对布尔表达式进行操作和求值
说明:
(1)、文法
在这个语言中终结符是布尔变量,即常量true和false。"非终结符表示"包含运算符and,or和not的布尔表达式。
BooleanExp ::= VariableExp | Constant | OrExp | AndExp | NotExp | '(' BooleanExp ')'
AndExp ::= BooleanExp 'and' BooleanExp
OrExp ::= BooleanExp 'or' BooleanExp
NotExp ::= 'not' BooleanExp
Constant ::= 'true' | 'false'
VariableExp ::= 'A' | 'B' | 'C' | …… | 'X' | 'Y' | 'Z'
(2)、表示
BooleanExp类为所有定义一个布尔表达式的类定义了一个接口。
VariableExp表示一个有名变量。
Constant类表示布尔常量。
AndExp表示由两个布尔表达式"与"操作得到的表达式。
OrExp表示由两个布尔表达式"或"操作得到的表达式。
NotExp表示由一个布尔表达式"求反"操作得到的表达式。
(3)、解释器
这里我们定义布尔表达式上的两个操作。第一个操作是求值(evaluate),即在一个上下文中求一个布尔表达式的值,当然,该上下文必须为每个变量都赋以一个"真"或"假"的布尔值。第二个操作是替换(replace),即用一个表达式来替换一个变量以产生一个新的布尔表达式。替换操作说明了解释器模式不仅可以用于求表达式的值,而且还可用作其它用途。在这个例子中,它就被用来对表达式本身进行操作。
(4)、句子
(true and x) or (y and (not x))
代码:
unit uBooleanExpression;
interface
type
TBoolArray = array[0..25] of Boolean;
TContext = class;
{布尔表达式}
TBooleanExp = class
public
constructor Create;
destructor Destroy; override;
//---
{求值}
function Evaluate(AContext: TContext): Boolean; virtual; abstract;
{替换}
function Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp; virtual; abstract;
function Copy(): TBooleanExp; virtual; abstract;
end;
{变量表达式}
TVariableExp = class(TBooleanExp)
private
FName: Char;
public
constructor Create(const AName: Char);
//--
function Evaluate(AContext: TContext): Boolean; override;
function Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp; override;
function Copy: TBooleanExp; override;
//---
property Name: Char read FName;
end;
{与运算}
TAndExp = class(TBooleanExp)
private
FOperand1: TBooleanExp;
FOperand2: TBooleanExp;
public
constructor Create(op1,op2: TBooleanExp);
//---
function Evaluate(AContext: TContext): Boolean; override;
function Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp; override;
function Copy(): TBooleanExp; override;
end;
{求反运算}
TNotExp = class(TBooleanExp)
private
FOperand: TBooleanExp;
public
constructor Create(op: TBooleanExp);
//---
function Evaluate(AContext: TContext): Boolean; override;
function Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp; override;
function Copy(): TBooleanExp; override;
end;
{或运算}
TOrExp = class(TBooleanExp)
private
FOperand1: TBooleanExp;
FOperand2: TBooleanExp;
public
constructor Create(op1,op2: TBooleanExp);
function Evaluate(AContext: TContext): Boolean; override;
function Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp; override;
function Copy(): TBooleanExp; override;
end;
{常量}
TConstantExp = class(TBooleanExp)
private
FValue: Boolean;
public
constructor Create(const AValue: Boolean);
//---
function Evaluate(AContext: TContext): Boolean; override;
function Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp; override;
function Copy(): TBooleanExp; override;
end;
TContext = class
private
FVariables: TBoolArray;
public
function Lookup(const AName: Char): Boolean;
procedure Assign(const AVariable: TVariableExp; const Value: Boolean);
end;
implementation
uses
Contnrs;
var
FTempExps: TObjectList;
function TContext.Lookup(const AName: Char): Boolean;
begin
Result := FVariables[ord(AName) - ord('A')];
end;
procedure TContext.Assign(const AVariable: TVariableExp; const Value: Boolean);
begin
FVariables[Ord(AVariable.Name) - ord('A')] := Value;
end;
constructor TVariableExp.Create(const AName: Char);
begin
inherited Create;
//---
FName := AName;
end;
function TVariableExp.Evaluate(AContext: TContext): Boolean;
begin
Result := AContext.Lookup(FName);
end;
function TVariableExp.Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp;
begin
if AName = FName then
Result := AExpression.Copy()
else
Result := TVariableExp.Create(FName);
end;
function TVariableExp.Copy: TBooleanExp;
begin
Result := TVariableExp.Create(FName);
end;
constructor TAndExp.Create(op1,op2: TBooleanExp);
begin
inherited Create;
//---
FOperand1 := op1;
FOperand2 := op2;
end;
function TAndExp.Evaluate(AContext: TContext): Boolean;
begin
Result := (FOperand1.Evaluate(AContext) and (FOperand2.Evaluate(AContext)));
end;
function TAndExp.Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp;
begin
result := TAndExp.Create(FOperand1.Replace(AName,AExpression),FOperand2.Replace(AName,AExpression));
end;
function TAndExp.Copy(): TBooleanExp;
begin
Result := TAndExp.Create(FOperand1.Copy(),FOperand2.Copy());
end;
constructor TNotExp.Create(op: TBooleanExp);
begin
inherited Create;
//---
FOperand := op;
end;
function TNotExp.Evaluate(AContext: TContext): Boolean;
begin
result := not FOperand.Evaluate(AContext);
end;
function TNotExp.Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp;
begin
result := TNotExp.Create(FOperand.Replace(AName,AExpression));
end;
function TNotExp.Copy(): TBooleanExp;
begin
result := TNotExp.Create(FOperand.Copy());
end;
constructor TOrExp.Create(op1,op2: TBooleanExp);
begin
inherited Create;
//---
FOperand1 := op1;
FOperand2 := op2;
end;
function TOrExp.Evaluate(AContext: TContext): Boolean;
begin
result := FOperand1.Evaluate(AContext) or FOperand2.Evaluate(AContext);
end;
function TOrExp.Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp;
begin
result := TOrExp.Create(FOperand1.Replace(AName,AExpression),FOperand2.Replace(AName,AExpression));
end;
function TOrExp.Copy(): TBooleanExp;
begin
result := TOrExp.Create(FOperand1.Copy(),FOperand2.Copy());
end;
constructor TConstantExp.Create(const AValue: Boolean);
begin
inherited Create;
//---
FValue := AValue;
end;
function TConstantExp.Evaluate(AContext: TContext): Boolean;
begin
Result := FValue;
end;
function TConstantExp.Replace(const AName: Char; AExpression: TBooleanExp): TBooleanExp;
begin
Result := TConstantExp.Create(FValue);
end;
function TConstantExp.Copy(): TBooleanExp;
begin
Result := TConstantExp.Create(FValue);
end;
constructor TBooleanExp.Create;
begin
FTempExps.Add(self);
end;
destructor TBooleanExp.Destroy;
begin
if not FTempExps.OwnsObjects then
FTempExps.Remove(self);
//---
inherited;
end;
initialization
FTempExps := TObjectList.Create;
FTempExps.OwnsObjects := false;
finalization
FTempExps.OwnsObjects := true;
FTempExps.Free;
end.
procedure TForm1.Button3Click(Sender: TObject);
{
布尔表达式"(true and x) or (y and (not x))"
,并对给定的以true或false赋值的x和y求这个表达式值。
}
var
AExpression: TBooleanExp;
AContext: TContext;
x,y: TVariableExp;
AResult: Boolean;
begin
AContext := TContext.Create;
//---
x := TVariableExp.Create('X');
y := TVariableExp.Create('Y');
//---
AExpression := TOrExp.Create(
TAndExp.Create(TConstantExp.Create(true),x),
TAndExp.Create(y,TNotExp.Create(x)));
//---
AContext.Assign(x,false);
AContext.Assign(y,true);
//---
AResult := AExpression.Evaluate(AContext);
if AResult then
ShowMessage('true')
else
ShowMessage('false');
//---
AExpression.Free;
AContext.Free;
end;
procedure TForm1.Button4Click(Sender: TObject);
{
计算布尔表达式"(true and x) or (y and (not x))"}
var
AExpression: TBooleanExp;
AContext: TContext;
//---
procedure Test1;
{对给定的以true或false赋值的x和y求这个表达式值。}
var
x,y: TVariableExp;
AResult: Boolean;
begin
x := TVariableExp.Create('X');
y := TVariableExp.Create('Y');
//---
AExpression := TOrExp.Create(
TAndExp.Create(TConstantExp.Create(true),x),
TAndExp.Create(y,TNotExp.Create(x)));
//---
AContext.Assign(x,false);
AContext.Assign(y,true);
//---
AResult := AExpression.Evaluate(AContext);
if AResult then
ShowMessage('true')
else
ShowMessage('false');
end;
//---
procedure Test2;
{用一个新的表达式替换变量y,并重新求值。}
var
AReplacement: TBooleanExp;
z: TVariableExp;
not_z: TNotExp;
AResult: Boolean;
begin
z := TVariableExp.Create('Z');
not_z := TNotExp.Create(z);
//---
AReplacement := AExpression.Replace('Y',not_z);
//---
AContext.Assign(z,true);
//---
AResult := AReplacement.Evaluate(AContext);
if AResult then
ShowMessage('true')
else
ShowMessage('false');
end;
begin
AContext := TContext.Create;
//---
Test1;
Test2;
//---
AExpression.Free;
AContext.Free;
end;