Strings Delphi

Title: Evaluating an expression in a string
Question: I need to resolve expressions like "a + 10 * (25 / b)" for a numeric result, or "(a = b) & (a 0)"
Answer:
Ever needed to add some scripting functionallity to your delphi application?
For example, you could add a condition attribute to an xml tag and interpret if the data the tag represents should be used in some way.
Here is a complete unit that takes an infix notation, translates it into a postfix notation and calculates and returns the result.
This can be used to write your own little calculator as well.
The code even supports the use of variables and parenthesis in the infix notation. Example: "(MYVAR * 2) / 5" or "(MYVAR = 10)|((MYVAR = 50) & (MYVAR = 100))"
Just use the following function in your code:
function EvaluateExpression(AInfix : string; out ResultType : TEvalResultType; out AResult : integer; AVars : IEvalVariableList = nil) : boolean;
IEvalVariableList is an interface that you can implement in your own variable classes. There is however a ready class to handle variables "TEvalVariables".
Enjoy!
Let me know if you make the code better in any way.

------------------
unit EvalExpressions;
//
// Condition evaluator v1.0
// Written by Magnus Flysj 2008
// magnus@flysjo.com
//
interface
uses Classes, SysUtils, Windows;
type
TEvalTokenType = (ttNone,ttOperator,ttOperand);
TEvalOperator = (oNONE,oLP,oRP,oOR,oXOR,oAND,oEQ,oNEQ,
oGT,oLT,oGET,oLET,oADD,oSUB,oDIV,oMUL);
TEvalOperandType = (otUnknown,otConst,otVar);
TEvalResultType = (rtBool,rtOrdinal);
IEvalVariableList = interface
['{A7244BC1-BEB9-4CAB-8F98-C287ECCE71F5}']
function HasVariable(AVarName : string) : boolean;
function GetValue(AVarName : string) : integer;
procedure SetValue(AVarName : string; AValue : integer);
end;
TEvalVarItem = class(TCollectionItem)
private
FVarName : string;
FVarValue : integer;
public
property VarName : string read FVarName write FVarName;
property VarValue : integer read FVarValue write FVarValue;
end;
TEvalVariables = class(TCollection,IEvalVariableList)
constructor Create;
private
function GetVarItem(AIdx : integer) : TEvalVarItem;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
function FindVarItemByName(AVarName : string) : TEvalVarItem;
function HasVariable(AVarName : string) : boolean;
function GetValue(AVarName : string) : integer;
procedure SetValue(AVarName : string; AValue : integer);
property VarItem[AIdx : integer] : TEvalVarItem read GetVarItem;
property Variable[AVarName : string] : integer read GetValue write SetValue; default;
end;
// Base class for tokens
TEvalToken = class(TCollectionItem)
private
function GetTokenType : TEvalTokenType; virtual; abstract;
public
function ToString : string; virtual; abstract;
property TokenType : TEvalTokenType read GetTokenType;
end;
// Used by operators
TEvalTokenOperator = class(TEvalToken)
private
FOperator : TEvalOperator;
function GetTokenType : TEvalTokenType; override;
public
function ToString : string; override;
property Operator : TEvalOperator read FOperator write FOperator;
end;
// Operand base class
TEvalTokenOperand = class(TEvalToken)
private
function GetTokenType : TEvalTokenType; override;
function GetOperandType : TEvalOperandType; virtual; abstract;
public
function IsConst : boolean;
function IsVar : boolean;
end;
// Used by constant operands
TEvalTokenConstOperand = class(TEvalTokenOperand)
private
FConstVal : integer;
function GetOperandType : TEvalOperandType; override;
public
function ToString : string; override;
property ConstVal : integer read FConstVal write FConstVal;
end;
// Used by variable operands
TEvalTokenVarOperand = class(TEvalTokenOperand)
private
FVarName : string;
function GetOperandType : TEvalOperandType; override;
public
function ToString : string; override;
property VarName : string read FVarName write FVarName;
end;
TEvalExpression = class(TCollection)
constructor Create;
private
function GetToken(AIdx : integer) : TEvalToken;
function AddOperator(AOperator : TEvalOperator) : TEvalTokenOperator;
function AddOperand(AOperand : string) : TEvalTokenOperand;
public
function ToString : string;
function ParseInfix(AIn : string) : boolean;
function Evaluate(out ResultType : TEvalResultType; out AResult : integer; AVars : IEvalVariableList = nil) : boolean;
property Token[AIdx : integer] : TEvalToken read GetToken; default;
end;
function InfixToPostfixNotation(AInfix : string) : string;
function EvaluateExpression(AInfix : string; out ResultType : TEvalResultType; out AResult : integer; AVars : IEvalVariableList = nil) : boolean;
implementation
const
// List of valid operators, if changed, update enum TEvalOperator as well
cOperators = '()&|=+-*/^';
type
TEvalResultCalcItem = record
Value : integer;
ValueType : TEvalResultType;
end;
TEvalOrdinalStack = class(TObject)
constructor Create;
destructor Destroy; override;
private
FData : array of TEvalResultCalcItem;
public
function IsEmpty : boolean;
function Count : integer;
function Top : TEvalResultCalcItem;
procedure Push(AItem : TEvalResultCalcItem); overload;
procedure Push(AValue : integer; AType : TEvalResultType); overload;
function Pop : TEvalResultCalcItem;
end;
TEvalOperatorStack = class(TObject)
constructor Create;
destructor Destroy; override;
private
FData : Array of TEvalOperator;
public
function IsEmpty : boolean;
function Count : integer;
function Top : TEvalOperator;
procedure Push(AOp : TEvalOperator);
function Pop : TEvalOperator;
end;
TEvalOperandStack = class(TObject)
constructor Create;
destructor Destroy; override;
private
FData : TStringList;
public
procedure Push(AOp : string);
function Pop : string;
end;
function OperatorTokenToEnum(AToken : string) : TEvalOperator;
begin
if SameText(AToken,'(') then result := oLP
else if SameText(AToken,')') then result := oRP
else if SameText(AToken,'=') then result := oEQ
else if SameText(AToken,'') then result := oNEQ
else if SameText(AToken,'') then result := oGT
else if SameText(AToken,'') then result := oLT
else if SameText(AToken,'=') then result := oGET
else if SameText(AToken,'=') then result := oLET
else if SameText(AToken,'|') then result := oOR
else if SameText(AToken,'&') then result := oAND
else if SameText(AToken,'+') then result := oADD
else if SameText(AToken,'-') then result := oSUB
else if SameText(AToken,'*') then result := oMUL
else if SameText(AToken,'/') then result := oDIV
else if SameText(AToken,'^') then result := oXOR
else result := oNone;
end;
function EnumToOperatorToken(AEnum : TEvalOperator) : string;
begin
case AEnum of
oLP: result := '(';
oRP: result := ')';
oEQ: result := '=';
oNEQ: result := '';
oGT: result := '';
oLT: result := '';
oGET: result := '=';
oLET: result := '=';
oOR: result := '|';
oAND: result := '&';
oADD: result := '+';
oSUB: result := '-';
oMUL: result := '*';
oDIV: result := '/';
oXOR: result := '^';
else
result := '';
end;
end;
function OperatorPriority(AOp : TEvalOperator) : integer; // Higher value means higher priority
begin
case AOp of
oNone: result := 0;
oLP: result := 0;
oRP: result := 0;
oOR: result := 4;
oXOR: result := 5;
oAND: result := 6;
oEQ: result := 7;
oNEQ: result := 7;
oGT: result := 8;
oLT: result := 8;
oGET: result := 8;
oLET: result := 8;
oADD: result := 10;
oSUB: result := 10;
oDIV: result := 11;
oMUL: result := 11;
else
result := 0;
end;
end;
function OperatorGraterEqualPrio(AOpL,AOpR : TEvalOperator) : boolean;
begin
result := (OperatorPriority(AOpL) = OperatorPriority(AOpR));
end;
function IsInt(AStr : string) : boolean;
var lp0 : integer;
begin
AStr := Trim(AStr);
if (AStr '') then begin
result := true;
for lp0 := 1 to Length(AStr) do begin
if not (AStr[lp0] in [#$30..#$39]) then begin
result := false;
break;
end;
end;
end else result := false;
end;
function InfixToPostfixNotation(AInfix : string) : string;
var AEval : TEvalExpression;
begin
AEval := TEvalExpression.Create;
try
AEval.ParseInfix(AInfix);
result := AEval.ToString;
finally
AEval.Free;
end;
end;
function EvaluateExpression(AInfix : string; out ResultType : TEvalResultType; out AResult : integer; AVars : IEvalVariableList = nil) : boolean;
var AEval : TEvalExpression;
begin
AEval := TEvalExpression.Create;
try
AEval.ParseInfix(AInfix);
result := AEval.Evaluate(ResultType,AResult,AVars);
finally
AEval.Free;
end;
end;
{TEvalOrdinalStack}
function MakeResultCalcItem(AValue : integer; AType : TEvalResultType) : TEvalResultCalcItem;
begin
result.Value := AValue;
result.ValueType := AType;
end;
constructor TEvalOrdinalStack.Create;
begin
inherited Create;
SetLength(FData,0);
end;
destructor TEvalOrdinalStack.Destroy;
begin
Finalize(FData);
inherited Destroy;
end;
function TEvalOrdinalStack.IsEmpty : boolean;
begin
result := (Length(FData) = 0);
end;
function TEvalOrdinalStack.Count : integer;
begin
result := Length(FData);
end;
function TEvalOrdinalStack.Top : TEvalResultCalcItem;
var ASize : integer;
begin
ASize := Length(FData);
if (ASize 0) then begin
result := FData[ASize-1];
end else result := MakeResultCalcItem(0,rtBool);
end;
procedure TEvalOrdinalStack.Push(AItem : TEvalResultCalcItem);
var ANewSize : integer;
begin
ANewSize := Length(FData)+1;
SetLength(FData,ANewSize);
Move(AItem,FData[ANewSize-1],SizeOf(TEvalResultCalcItem));
end;
procedure TEvalOrdinalStack.Push(AValue : integer; AType : TEvalResultType);
var ANewSize : integer;
AItem : TEvalResultCalcItem;
begin
ANewSize := Length(FData)+1;
SetLength(FData,ANewSize);
AItem.Value := AValue;
AItem.ValueType := AType;
Move(AItem,FData[ANewSize-1],SizeOf(TEvalResultCalcItem));
end;
function TEvalOrdinalStack.Pop : TEvalResultCalcItem;
var ASize : integer;
begin
ASize := Length(FData);
if ASize 0 then begin
Move(FData[ASize-1],result,SizeOf(TEvalResultCalcItem));
SetLength(FData,ASize-1);
end else result := MakeResultCalcItem(0,rtBool);
end;
{TEvalOperatorStack}
constructor TEvalOperatorStack.Create;
begin
inherited Create;
SetLength(FData,0);
end;
destructor TEvalOperatorStack.Destroy;
begin
Finalize(FData);
inherited Destroy;
end;
function TEvalOperatorStack.IsEmpty : boolean;
begin
result := (Length(FData) = 0);
end;
function TEvalOperatorStack.Count : integer;
begin
result := Length(FData);
end;
function TEvalOperatorStack.Top : TEvalOperator;
var ASize : integer;
begin
ASize := Length(FData);
if (ASize 0) then begin
result := FData[ASize-1];
end else result := oNone;
end;
procedure TEvalOperatorStack.Push(AOp : TEvalOperator);
var ANewSize : integer;
begin
ANewSize := Length(FData)+1;
SetLength(FData,ANewSize);
Move(AOp,FData[ANewSize-1],SizeOf(TEvalOperator));
end;
function TEvalOperatorStack.Pop : TEvalOperator;
var ASize : integer;
begin
ASize := Length(FData);
if ASize 0 then begin
Move(FData[ASize-1],result,SizeOf(TEvalOperator));
SetLength(FData,ASize-1);
end else result := oLP;
end;
{TEvalOperandStack}
constructor TEvalOperandStack.Create;
begin
inherited Create;
FData := TStringList.Create;
end;
destructor TEvalOperandStack.Destroy;
begin
FData.Free;
inherited Destroy;
end;
procedure TEvalOperandStack.Push(AOp : string);
begin
FData.Add(AOp);
end;
function TEvalOperandStack.Pop : string;
begin
result := '';
if (FData.Count 0) then begin
result := FData[FData.Count-1];
FData.Delete(FData.Count-1);
end;
end;
{TEvalVariables}
constructor TEvalVariables.Create;
begin
inherited Create(TEvalVarItem);
end;
function TEvalVariables.GetVarItem(AIdx : integer) : TEvalVarItem;
begin
if (AIdx = 0) and (AIdx Count) then begin
result := TEvalVarItem(Items[AIdx]);
end else result := nil;
end;
function TEvalVariables.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
begin
if GetInterface(IID, Obj) then
Result := 0
else
Result := E_NOINTERFACE;
end;
function TEvalVariables._AddRef: Integer; stdcall;
begin
result := -1;
end;
function TEvalVariables._Release: Integer; stdcall;
begin
result := -1;
end;
function TEvalVariables.FindVarItemByName(AVarName : string) : TEvalVarItem;
var lp0 : integer;
begin
result := nil;
for lp0 := 0 to Count-1 do begin
if SameText(VarItem[lp0].FVarName,AVarName) then begin
result := VarItem[lp0];
break;
end;
end;
end;
function TEvalVariables.HasVariable(AVarName : string) : boolean;
begin
result := Assigned(FindVarItemByName(AVarName));
end;
function TEvalVariables.GetValue(AVarName : string) : integer;
var AItem : TEvalVarItem;
begin
result := 0;
AItem := FindVarItemByName(AVarName);
if Assigned(AItem) then begin
result := AItem.FVarValue;
end;
end;
procedure TEvalVariables.SetValue(AVarName : string; AValue : integer);
var AItem : TEvalVarItem;
begin
AItem := FindVarItemByName(AVarName);
if (AItem = nil) then begin
AItem := TEvalVarItem.Create(self);
AItem.VarName := AVarName;
end;
if Assigned(AItem) then
AItem.FVarValue := AValue;
end;
{TEvalTokenOperator}
function TEvalTokenOperator.GetTokenType : TEvalTokenType;
begin
result := ttOperator;
end;
function TEvalTokenOperator.ToString : string;
begin
result := EnumToOperatorToken(FOperator);
end;
{TEvalTokenOperand}
function TEvalTokenOperand.GetTokenType : TEvalTokenType;
begin
result := ttOperand;
end;
function TEvalTokenOperand.IsConst : boolean;
begin
result := (GetOperandType = otConst);
end;
function TEvalTokenOperand.IsVar : boolean;
begin
result := (GetOperandType = otVar);
end;
{TEvalTokenConstOperand}
function TEvalTokenConstOperand.GetOperandType : TEvalOperandType;
begin
result := otConst;
end;
function TEvalTokenConstOperand.ToString : string;
begin
result := IntToStr(FConstVal);
end;
{TEvalTokenVarOperand}
function TEvalTokenVarOperand.GetOperandType : TEvalOperandType;
begin
result := otVar;
end;
function TEvalTokenVarOperand.ToString : string;
begin
result := FVarName;
end;
{TEvalExpression}
constructor TEvalExpression.Create;
begin
inherited Create(TEvalToken);
end;
function TEvalExpression.GetToken(AIdx : integer) : TEvalToken;
begin
if (AIdx = 0) and (AIdx Count) then begin
result := TEvalToken(Items[AIdx]);
end else result := nil;
end;
function TEvalExpression.AddOperator(AOperator : TEvalOperator) : TEvalTokenOperator;
begin
result := TEvalTokenOperator.Create(self);
result.FOperator := AOperator;
end;
function TEvalExpression.AddOperand(AOperand : string) : TEvalTokenOperand;
begin
result := nil;
if (AOperand '') then begin
if IsInt(AOperand) then begin
result := TEvalTokenConstOperand.Create(self);
TEvalTokenConstOperand(result).FConstVal := StrToIntDef(AOperand,0);
end else begin
result := TEvalTokenVarOperand.Create(self);
TEvalTokenVarOperand(result).FVarName := AOperand;
end;
end;
end;
function TEvalExpression.ToString : string;
var lp0 : integer;
begin
result := '';
for lp0 := 0 to Count-1 do begin
result := result + Token[lp0].ToString + #32;
end;
result := trim(result);
end;
function TEvalExpression.ParseInfix(AIn : string) : boolean;
var AStack : TEvalOperatorStack;
AOperator,APrevOperator : TEvalOperator;
lp0,stl : integer;
AToken : string;
ATokenType : TEvalTokenType;
function ReadToken : boolean;
var AEox : boolean;
begin
result := false;
AToken := '';
ATokenType := ttNone;
AEox := (lp0 stl);
if not AEox then begin
repeat
if (Pos(AIn[lp0],cOperators) 0) then begin // Operator
if (ATokenType = ttOperand) then begin
if (AToken '') then result := true;
break;
end else begin
if (ATokenType = ttOperator) then begin
if ((AToken = '') and ((AIn[lp0] = '=') or (AIn[lp0] = ''))) or
((AToken = '') and (AIn[lp0] = '=')) then begin
// Multi char operator
ATokenType := ttOperator;
AToken := AToken + AIn[lp0];
end else begin
if (AToken '') then result := true;
break;
end;
end else begin
ATokenType := ttOperator;
AToken := AToken + AIn[lp0];
end;
end;
end else begin // Operand
case AIn[lp0] of
#9,#32: begin
if (ATokenType ttNone) then begin
if (AToken '') then result := true;
break;
end;
end;
else
if (ATokenType = ttOperator) then begin
if (AToken '') then result := true;
break;
end else begin
ATokenType := ttOperand;
AToken := AToken + AIn[lp0];
end;
end;
end;
inc(lp0);
AEox := (lp0 stl);
if AEox and (AToken '') then result := true;
until (AEox);
end;
end;
begin
result := false;
AStack := TEvalOperatorStack.Create;
try
Clear;
stl := Length(AIn);
if (stl 0) then begin
lp0 := 1;
while ReadToken do begin
case ATokenType of
ttOperator: begin
AOperator := OperatorTokenToEnum(AToken);
case AOperator of
oNone: ; // Ignore
oLP: AStack.Push(AOperator);
oRP: begin
while not AStack.IsEmpty and (AStack.Top oLP) do begin
APrevOperator := AStack.Pop;
AddOperator(APrevOperator);
end;
if not AStack.IsEmpty then AStack.Pop;
end;
else
while not AStack.IsEmpty and (AStack.Top oLP) do begin
if OperatorGraterEqualPrio(AStack.Top,AOperator) then begin
APrevOperator := AStack.Pop;
AddOperator(APrevOperator);
end else break;
end;
AStack.Push(AOperator);
end;
end;
ttOperand: begin
AddOperand(AToken);
end;
end;
end;
while not AStack.IsEmpty do begin
APrevOperator := AStack.Pop;
AddOperator(APrevOperator);
end;
result := true;
end;
finally
AStack.Free;
end;
end;
function TEvalExpression.Evaluate(out ResultType : TEvalResultType; out AResult : integer; AVars : IEvalVariableList = nil) : boolean;
var ATokenIdx : integer;
AIntStack : TEvalOrdinalStack;
ATempVal,AValLeft,AValRight : TEvalResultCalcItem;
AVarName : string;
begin
result := false;
AResult := 0;
ResultType := rtBool;
AIntStack := TEvalOrdinalStack.Create;
try
for ATokenIdx := 0 to Count-1 do begin
case Token[ATokenIdx].TokenType of
ttOperator: begin
if not (TEvalTokenOperator(Token[ATokenIdx]).FOperator in [oNONE,oLP,oRP]) then begin
if (AIntStack.Count = 2) then begin
ATempVal := MakeResultCalcItem(0,rtBool);
AValRight := AIntStack.Pop;
AValLeft := AIntStack.Pop;
case TEvalTokenOperator(Token[ATokenIdx]).FOperator of
oOR: begin
if (AValLeft.ValueType = AValRight.ValueType) then begin
ATempVal.ValueType := AValLeft.ValueType;
if ATempVal.ValueType = rtBool then begin
if (AValLeft.Value 0) or (AValRight.Value 0) then ATempVal.Value := 1;
end else begin
ATempVal.Value := (AValLeft.Value or AValRight.Value);
end;
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of same type')
end;
end;
oXOR: begin
if (AValLeft.ValueType = AValRight.ValueType) then begin
ATempVal.ValueType := AValLeft.ValueType;
if ATempVal.ValueType = rtBool then begin
if (AValLeft.Value 0) xor (AValRight.Value 0) then ATempVal.Value := 1;
end else begin
ATempVal.Value := (AValLeft.Value xor AValRight.Value);
end;
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of same type')
end;
end;
oAND: begin
if (AValLeft.ValueType = AValRight.ValueType) then begin
ATempVal.ValueType := AValLeft.ValueType;
if ATempVal.ValueType = rtBool then begin
if (AValLeft.Value 0) and (AValRight.Value 0) then ATempVal.Value := 1;
end else begin
ATempVal.Value := (AValLeft.Value and AValRight.Value);
end;
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of same type')
end;
end;
oEQ: begin
if (AValLeft.ValueType = AValRight.ValueType) then begin
ATempVal.ValueType := rtBool;
if (AValLeft.Value = AValRight.Value) then ATempVal.Value := 1;
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of same type')
end;
end;
oNEQ: begin
if (AValLeft.ValueType = AValRight.ValueType) then begin
ATempVal.ValueType := rtBool;
if (AValLeft.Value AValRight.Value) then ATempVal.Value := 1;
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of same type')
end;
end;
oGT: begin
if (AValLeft.ValueType = AValRight.ValueType) then begin
ATempVal.ValueType := rtBool;
if (AValLeft.Value AValRight.Value) then ATempVal.Value := 1;
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of same type')
end;
end;
oLT: begin
if (AValLeft.ValueType = AValRight.ValueType) then begin
ATempVal.ValueType := rtBool;
if (AValLeft.Value AValRight.Value) then ATempVal.Value := 1;
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of same type')
end;
end;
oGET: begin
if (AValLeft.ValueType = AValRight.ValueType) then begin
ATempVal.ValueType := rtBool;
if (AValLeft.Value = AValRight.Value) then ATempVal.Value := 1;
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of same type')
end;
end;
oLET: begin
if (AValLeft.ValueType = AValRight.ValueType) then begin
ATempVal.ValueType := rtBool;
if (AValLeft.Value = AValRight.Value) then ATempVal.Value := 1;
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of same type')
end;
end;
oADD: begin
if (AValLeft.ValueType = rtOrdinal) and (AValRight.ValueType = rtOrdinal) then begin
ATempVal.ValueType := rtOrdinal;
ATempVal.Value := (AValLeft.Value + AValRight.Value);
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of type ordinal')
end;
end;
oSUB: begin
if (AValLeft.ValueType = rtOrdinal) and (AValRight.ValueType = rtOrdinal) then begin
ATempVal.ValueType := rtOrdinal;
ATempVal.Value := (AValLeft.Value - AValRight.Value);
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of type ordinal')
end;
end;
oDIV: begin
if (AValLeft.ValueType = rtOrdinal) and (AValRight.ValueType = rtOrdinal) then begin
ATempVal.ValueType := rtOrdinal;
if AValRight.Value 0 then begin
ATempVal.Value := (AValLeft.Value div AValRight.Value);
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Can not divide by zero')
end;
end else begin
raise Exception.Create('Incorrect operand, must be of type ordinal')
end;
end;
oMUL: begin
if (AValLeft.ValueType = rtOrdinal) and (AValRight.ValueType = rtOrdinal) then begin
ATempVal.ValueType := rtOrdinal;
ATempVal.Value := (AValLeft.Value * AValRight.Value);
AIntStack.Push(ATempVal);
end else begin
raise Exception.Create('Incorrect operand, must be of type ordinal')
end;
end;
end;
end else raise Exception.Create('Missing operand for operator '+EnumToOperatorToken(TEvalTokenOperator(Token[ATokenIdx]).FOperator));
end;
end;
ttOperand: begin
if (Token[ATokenIdx] is TEvalTokenVarOperand) then begin
AVarName := TEvalTokenVarOperand(Token[ATokenIdx]).VarName;
if Assigned(AVars) then begin
if AVars.HasVariable(AVarName) then begin
AIntStack.Push(AVars.GetValue(AVarName),rtOrdinal);
end else raise Exception.Create('Variable '+AVarName+' is not set');
end else raise Exception.Create('Variables not allowed');
end else if (Token[ATokenIdx] is TEvalTokenConstOperand) then begin
ATempVal.Value := TEvalTokenConstOperand(Token[ATokenIdx]).FConstVal;
ATempVal.ValueType := rtOrdinal;
AIntStack.Push(ATempVal);
end else raise Exception.Create('Unknown operand');
end;
end;
end;
ATempVal := AIntStack.Pop;
AResult := ATempVal.Value;
ResultType := ATempVal.ValueType;
result := (AIntStack.IsEmpty);
finally
AIntStack.Free;
end;
end;
end.