4040 lines
110 KiB
ObjectPascal
4040 lines
110 KiB
ObjectPascal
{**************************************************************************************************}
|
||
{ }
|
||
{ Project JEDI Code Library (JCL) }
|
||
{ }
|
||
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
|
||
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
|
||
{ License at http://www.mozilla.org/MPL/ }
|
||
{ }
|
||
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
|
||
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
|
||
{ and limitations under the License. }
|
||
{ }
|
||
{ The Original Code is JclExprEval.pas. }
|
||
{ }
|
||
{ The Initial Developer of the Original Code is Barry Kelly. }
|
||
{ Portions created by Barry Kelly are Copyright (C) Barry Kelly. All rights reserved. }
|
||
{ }
|
||
{ Contributor(s): }
|
||
{ Barry Kelly }
|
||
{ Matthias Thoma (mthoma) }
|
||
{ Petr Vones (pvones) }
|
||
{ Robert Marquardt (marquardt) }
|
||
{ Robert Rossmair (rrossmair) }
|
||
{ }
|
||
{**************************************************************************************************}
|
||
{ }
|
||
{ This unit contains three expression evaluators, each tailored for different usage patterns. It }
|
||
{ also contains the component objects, so that a customized expression evaluator can be assembled }
|
||
{ relatively easily. }
|
||
{ }
|
||
{**************************************************************************************************}
|
||
|
||
// Last modified: $Date: 2005/04/12 17:04:30 $
|
||
// For history see end of file
|
||
|
||
unit JclExprEval;
|
||
|
||
{$I jcl.inc}
|
||
|
||
interface
|
||
|
||
uses
|
||
SysUtils, Classes,
|
||
JclBase, JclSysUtils, JclStrHashMap, JclResources;
|
||
|
||
const
|
||
cExprEvalHashSize = 127;
|
||
|
||
type
|
||
EJclExprEvalError = class(EJclError);
|
||
|
||
const
|
||
ExprWhiteSpace = [#1..#32];
|
||
|
||
type
|
||
TFloat = Double;
|
||
PFloat = ^TFloat;
|
||
|
||
TFloat32 = Single;
|
||
PFloat32 = ^TFloat32;
|
||
|
||
TFloat64 = Double;
|
||
PFloat64 = ^TFloat64;
|
||
|
||
TFloat80 = Extended;
|
||
PFloat80 = ^TFloat80;
|
||
|
||
TFloatFunc = function: TFloat;
|
||
TFloat32Func = function: TFloat32;
|
||
TFloat64Func = function: TFloat64;
|
||
TFloat80Func = function: TFloat80;
|
||
|
||
TUnaryFunc = function(X: TFloat): TFloat;
|
||
TUnary32Func = function(X: TFloat32): TFloat32;
|
||
TUnary64Func = function(X: TFloat64): TFloat64;
|
||
TUnary80Func = function(X: TFloat80): TFloat80;
|
||
|
||
TBinaryFunc = function(X, Y: TFloat): TFloat;
|
||
TBinary32Func = function(X, Y: TFloat32): TFloat32;
|
||
TBinary64Func = function(X, Y: TFloat64): TFloat64;
|
||
TBinary80Func = function(X, Y: TFloat80): TFloat80;
|
||
|
||
TTernaryFunc = function(X, Y, Z: TFloat): TFloat;
|
||
TTernary32Func = function(X, Y, Z: TFloat32): TFloat32;
|
||
TTernary64Func = function(X, Y, Z: TFloat64): TFloat64;
|
||
TTernary80Func = function(X, Y, Z: TFloat80): TFloat80;
|
||
|
||
type
|
||
{ Forward Declarations }
|
||
TExprLexer = class;
|
||
TExprCompileParser = class;
|
||
TExprEvalParser = class;
|
||
TExprSym = class;
|
||
TExprNode = class;
|
||
TExprNodeFactory = class;
|
||
|
||
TExprContext = class(TObject)
|
||
public
|
||
function Find(const AName: string): TExprSym; virtual; abstract;
|
||
end;
|
||
|
||
TExprHashContext = class(TExprContext)
|
||
private
|
||
FHashMap: TStringHashMap;
|
||
public
|
||
constructor Create(ACaseSensitive: Boolean = False; AHashSize: Integer = 127);
|
||
destructor Destroy; override;
|
||
procedure Add(ASymbol: TExprSym);
|
||
procedure Remove(const AName: string);
|
||
function Find(const AName: string): TExprSym; override;
|
||
end;
|
||
|
||
TExprSetContext = class(TExprContext)
|
||
private
|
||
FList: TList;
|
||
FOwnsContexts: Boolean;
|
||
function GetContexts(AIndex: Integer): TExprContext;
|
||
function GetCount: Integer;
|
||
public
|
||
constructor Create(AOwnsContexts: Boolean);
|
||
destructor Destroy; override;
|
||
procedure Add(AContext: TExprContext);
|
||
procedure Remove(AContext: TExprContext);
|
||
procedure Delete(AIndex: Integer);
|
||
function Extract(AContext: TExprContext): TExprContext;
|
||
property Count: Integer read GetCount;
|
||
property Contexts[AIndex: Integer]: TExprContext read GetContexts;
|
||
property InternalList: TList read FList;
|
||
function Find(const AName: string): TExprSym; override;
|
||
end;
|
||
|
||
TExprSym = class(TObject)
|
||
private
|
||
FIdent: string;
|
||
FLexer: TExprLexer;
|
||
FEvalParser: TExprEvalParser;
|
||
FCompileParser: TExprCompileParser;
|
||
FNodeFactory: TExprNodeFactory;
|
||
public
|
||
constructor Create(const AIdent: string);
|
||
function Evaluate: TFloat; virtual; abstract;
|
||
function Compile: TExprNode; virtual; abstract;
|
||
property Ident: string read FIdent;
|
||
property Lexer: TExprLexer read FLexer write FLexer;
|
||
property CompileParser: TExprCompileParser read FCompileParser
|
||
write FCompileParser;
|
||
property EvalParser: TExprEvalParser read FEvalParser write FEvalParser;
|
||
property NodeFactory: TExprNodeFactory read FNodeFactory write FNodeFactory;
|
||
end;
|
||
|
||
TExprToken = (
|
||
// specials
|
||
etEof,
|
||
etNumber,
|
||
etIdentifier,
|
||
|
||
// user extension tokens
|
||
etUser0, etUser1, etUser2, etUser3, etUser4, etUser5, etUser6, etUser7,
|
||
etUser8, etUser9, etUser10, etUser11, etUser12, etUser13, etUser14, etUser15,
|
||
etUser16, etUser17, etUser18, etUser19, etUser20, etUser21, etUser22, etUser23,
|
||
etUser24, etUser25, etUser26, etUser27, etUser28, etUser29, etUser30, etUser31,
|
||
|
||
// compound tokens
|
||
etNotEqual, // <>
|
||
etLessEqual, // <=
|
||
etGreaterEqual, // >=
|
||
|
||
// ASCII normal & ordinals
|
||
|
||
etBang, // '!' #$21 33
|
||
etDoubleQuote, // '"' #$22 34
|
||
etHash, // '#' #$23 35
|
||
etDollar, // '$' #$24 36
|
||
etPercent, // '%' #$25 37
|
||
etAmpersand, // '&' #$26 38
|
||
etSingleQuote, // '''' #$27 39
|
||
etLParen, // '(' #$28 40
|
||
etRParen, // ')' #$29 41
|
||
etAsterisk, // '*' #$2A 42
|
||
etPlus, // '+' #$2B 43
|
||
etComma, // ',' #$2C 44
|
||
etMinus, // '-' #$2D 45
|
||
etDot, // '.' #$2E 46
|
||
etForwardSlash, // '/' #$2F 47
|
||
|
||
// 48..57 - numbers...
|
||
|
||
etColon, // ':' #$3A 58
|
||
etSemiColon, // ';' #$3B 59
|
||
etLessThan, // '<' #$3C 60
|
||
etEqualTo, // '=' #$3D 61
|
||
etGreaterThan, // '>' #$3E 62
|
||
etQuestion, // '?' #$3F 63
|
||
etAt, // '@' #$40 64
|
||
|
||
// 65..90 - capital letters...
|
||
|
||
etLBracket, // '[' #$5B 91
|
||
etBackSlash, // '\' #$5C 92
|
||
etRBracket, // ']' #$5D 93
|
||
etArrow, // '^' #$5E 94
|
||
// 95 - underscore
|
||
etBackTick, // '`' #$60 96
|
||
|
||
// 97..122 - small letters...
|
||
|
||
etLBrace, // '{' #$7B 123
|
||
etPipe, // '|' #$7C 124
|
||
etRBrace, // '}' #$7D 125
|
||
etTilde, // '~' #$7E 126
|
||
et127, // '' #$7F 127
|
||
etEuro, // '<27>' #$80 128
|
||
et129, // '<27>' #$81 129
|
||
et130, // '<27>' #$82 130
|
||
et131, // '<27>' #$83 131
|
||
et132, // '<27>' #$84 132
|
||
et133, // '<27>' #$85 133
|
||
et134, // '<27>' #$86 134
|
||
et135, // '<27>' #$87 135
|
||
et136, // '<27>' #$88 136
|
||
et137, // '<27>' #$89 137
|
||
et138, // '<27>' #$8A 138
|
||
et139, // '<27>' #$8B 139
|
||
et140, // '<27>' #$8C 140
|
||
et141, // '<27>' #$8D 141
|
||
et142, // '<27>' #$8E 142
|
||
et143, // '<27>' #$8F 143
|
||
et144, // '<27>' #$90 144
|
||
et145, // '<27>' #$91 145
|
||
et146, // '<27>' #$92 146
|
||
et147, // '<27>' #$93 147
|
||
et148, // '<27>' #$94 148
|
||
et149, // '<27>' #$95 149
|
||
et150, // '<27>' #$96 150
|
||
et151, // '<27>' #$97 151
|
||
et152, // '<27>' #$98 152
|
||
et153, // '<27>' #$99 153
|
||
et154, // '<27>' #$9A 154
|
||
et155, // '<27>' #$9B 155
|
||
et156, // '<27>' #$9C 156
|
||
et157, // '<27>' #$9D 157
|
||
et158, // '<27>' #$9E 158
|
||
et159, // '<27>' #$9F 159
|
||
et160, // '<27>' #$A0 160
|
||
et161, // '<27>' #$A1 161
|
||
et162, // '<27>' #$A2 162
|
||
et163, // '<27>' #$A3 163
|
||
et164, // '<27>' #$A4 164
|
||
et165, // '<27>' #$A5 165
|
||
et166, // '<27>' #$A6 166
|
||
et167, // '<27>' #$A7 167
|
||
et168, // '<27>' #$A8 168
|
||
et169, // '<27>' #$A9 169
|
||
et170, // '<27>' #$AA 170
|
||
et171, // '<27>' #$AB 171
|
||
et172, // '<27>' #$AC 172
|
||
et173, // '<27>' #$AD 173
|
||
et174, // '<27>' #$AE 174
|
||
et175, // '<27>' #$AF 175
|
||
et176, // '<27>' #$B0 176
|
||
et177, // '<27>' #$B1 177
|
||
et178, // '<27>' #$B2 178
|
||
et179, // '<27>' #$B3 179
|
||
et180, // '<27>' #$B4 180
|
||
et181, // '<27>' #$B5 181
|
||
et182, // '<27>' #$B6 182
|
||
et183, // '<27>' #$B7 183
|
||
et184, // '<27>' #$B8 184
|
||
et185, // '<27>' #$B9 185
|
||
et186, // '<27>' #$BA 186
|
||
et187, // '<27>' #$BB 187
|
||
et188, // '<27>' #$BC 188
|
||
et189, // '<27>' #$BD 189
|
||
et190, // '<27>' #$BE 190
|
||
et191, // '<27>' #$BF 191
|
||
et192, // '<27>' #$C0 192
|
||
et193, // '<27>' #$C1 193
|
||
et194, // '<27>' #$C2 194
|
||
et195, // '<27>' #$C3 195
|
||
et196, // '<27>' #$C4 196
|
||
et197, // '<27>' #$C5 197
|
||
et198, // '<27>' #$C6 198
|
||
et199, // '<27>' #$C7 199
|
||
et200, // '<27>' #$C8 200
|
||
et201, // '<27>' #$C9 201
|
||
et202, // '<27>' #$CA 202
|
||
et203, // '<27>' #$CB 203
|
||
et204, // '<27>' #$CC 204
|
||
et205, // '<27>' #$CD 205
|
||
et206, // '<27>' #$CE 206
|
||
et207, // '<27>' #$CF 207
|
||
et208, // '<27>' #$D0 208
|
||
et209, // '<27>' #$D1 209
|
||
et210, // '<27>' #$D2 210
|
||
et211, // '<27>' #$D3 211
|
||
et212, // '<27>' #$D4 212
|
||
et213, // '<27>' #$D5 213
|
||
et214, // '<27>' #$D6 214
|
||
et215, // '<27>' #$D7 215
|
||
et216, // '<27>' #$D8 216
|
||
et217, // '<27>' #$D9 217
|
||
et218, // '<27>' #$DA 218
|
||
et219, // '<27>' #$DB 219
|
||
et220, // '<27>' #$DC 220
|
||
et221, // '<27>' #$DD 221
|
||
et222, // '<27>' #$DE 222
|
||
et223, // '<27>' #$DF 223
|
||
et224, // '<27>' #$E0 224
|
||
et225, // '<27>' #$E1 225
|
||
et226, // '<27>' #$E2 226
|
||
et227, // '<27>' #$E3 227
|
||
et228, // '<27>' #$E4 228
|
||
et229, // '<27>' #$E5 229
|
||
et230, // '<27>' #$E6 230
|
||
et231, // '<27>' #$E7 231
|
||
et232, // '<27>' #$E8 232
|
||
et233, // '<27>' #$E9 233
|
||
et234, // '<27>' #$EA 234
|
||
et235, // '<27>' #$EB 235
|
||
et236, // '<27>' #$EC 236
|
||
et237, // '<27>' #$ED 237
|
||
et238, // '<27>' #$EE 238
|
||
et239, // '<27>' #$EF 239
|
||
et240, // '<27>' #$F0 240
|
||
et241, // '<27>' #$F1 241
|
||
et242, // '<27>' #$F2 242
|
||
et243, // '<27>' #$F3 243
|
||
et244, // '<27>' #$F4 244
|
||
et245, // '<27>' #$F5 245
|
||
et246, // '<27>' #$F6 246
|
||
et247, // '<27>' #$F7 247
|
||
et248, // '<27>' #$F8 248
|
||
et249, // '<27>' #$F9 249
|
||
et250, // '<27>' #$FA 250
|
||
et251, // '<27>' #$FB 251
|
||
et252, // '<27>' #$FC 252
|
||
et253, // '<27>' #$FD 253
|
||
et254, // '<27>' #$FE 254
|
||
et255, // '<27>' #$FF 255
|
||
etInvalid // invalid token type
|
||
);
|
||
|
||
TExprLexer = class(TObject)
|
||
protected
|
||
FCurrTok: TExprToken;
|
||
FTokenAsNumber: TFloat;
|
||
FTokenAsString: string;
|
||
public
|
||
constructor Create;
|
||
procedure NextTok; virtual; abstract;
|
||
procedure Reset; virtual;
|
||
property TokenAsString: string read FTokenAsString;
|
||
property TokenAsNumber: TFloat read FTokenAsNumber;
|
||
property CurrTok: TExprToken read FCurrTok;
|
||
end;
|
||
|
||
TExprNode = class(TObject)
|
||
private
|
||
FDepList: TList;
|
||
function GetDepCount: Integer;
|
||
function GetDeps(AIndex: Integer): TExprNode;
|
||
public
|
||
constructor Create(const ADepList: array of TExprNode);
|
||
destructor Destroy; override;
|
||
procedure AddDep(ADep: TExprNode);
|
||
property DepCount: Integer read GetDepCount;
|
||
property Deps[AIndex: Integer]: TExprNode read GetDeps; default;
|
||
property DepList: TList read FDepList;
|
||
end;
|
||
|
||
TExprNodeFactory = class(TObject)
|
||
public
|
||
function LoadVar32(ALoc: PFloat32): TExprNode; virtual; abstract;
|
||
function LoadVar64(ALoc: PFloat64): TExprNode; virtual; abstract;
|
||
function LoadVar80(ALoc: PFloat80): TExprNode; virtual; abstract;
|
||
|
||
function LoadConst32(AValue: TFloat32): TExprNode; virtual; abstract;
|
||
function LoadConst64(AValue: TFloat64): TExprNode; virtual; abstract;
|
||
function LoadConst80(AValue: TFloat80): TExprNode; virtual; abstract;
|
||
|
||
function CallFloatFunc(AFunc: TFloatFunc): TExprNode; virtual; abstract;
|
||
function CallFloat32Func(AFunc: TFloat32Func): TExprNode; virtual; abstract;
|
||
function CallFloat64Func(AFunc: TFloat64Func): TExprNode; virtual; abstract;
|
||
function CallFloat80Func(AFunc: TFloat80Func): TExprNode; virtual; abstract;
|
||
function CallUnaryFunc(AFunc: TUnaryFunc; X: TExprNode): TExprNode; virtual; abstract;
|
||
function CallUnary32Func(AFunc: TUnary32Func; X: TExprNode): TExprNode; virtual; abstract;
|
||
function CallUnary64Func(AFunc: TUnary64Func; X: TExprNode): TExprNode; virtual; abstract;
|
||
function CallUnary80Func(AFunc: TUnary80Func; X: TExprNode): TExprNode; virtual; abstract;
|
||
function CallBinaryFunc(AFunc: TBinaryFunc; X, Y: TExprNode): TExprNode; virtual; abstract;
|
||
function CallBinary32Func(AFunc: TBinary32Func; X, Y: TExprNode): TExprNode; virtual; abstract;
|
||
function CallBinary64Func(AFunc: TBinary64Func; X, Y: TExprNode): TExprNode; virtual; abstract;
|
||
function CallBinary80Func(AFunc: TBinary80Func; X, Y: TExprNode): TExprNode; virtual; abstract;
|
||
function CallTernaryFunc(AFunc: TTernaryFunc; X, Y, Z: TExprNode): TExprNode; virtual; abstract;
|
||
function CallTernary32Func(AFunc: TTernary32Func; X, Y, Z: TExprNode): TExprNode; virtual; abstract;
|
||
function CallTernary64Func(AFunc: TTernary64Func; X, Y, Z: TExprNode): TExprNode; virtual; abstract;
|
||
function CallTernary80Func(AFunc: TTernary80Func; X, Y, Z: TExprNode): TExprNode; virtual; abstract;
|
||
|
||
function Add(ALeft, ARight: TExprNode): TExprNode; virtual; abstract;
|
||
function Subtract(ALeft, ARight: TExprNode): TExprNode; virtual; abstract;
|
||
function Multiply(ALeft, ARight: TExprNode): TExprNode; virtual; abstract;
|
||
function Divide(ALeft, ARight: TExprNode): TExprNode; virtual; abstract;
|
||
function Negate(AValue: TExprNode): TExprNode; virtual; abstract;
|
||
|
||
function Compare(ALeft, ARight: TExprNode): TExprNode; virtual; abstract;
|
||
|
||
function LoadVar(ALoc: PFloat32): TExprNode; overload;
|
||
function LoadVar(ALoc: PFloat64): TExprNode; overload;
|
||
function LoadVar(ALoc: PFloat80): TExprNode; overload;
|
||
function LoadConst(AValue: TFloat32): TExprNode; overload;
|
||
function LoadConst(AValue: TFloat64): TExprNode; overload;
|
||
function LoadConst(AValue: TFloat80): TExprNode; overload;
|
||
end;
|
||
|
||
TExprCompileParser = class(TObject)
|
||
private
|
||
FContext: TExprContext;
|
||
FLexer: TExprLexer;
|
||
FNodeFactory: TExprNodeFactory;
|
||
public
|
||
constructor Create(ALexer: TExprLexer; ANodeFactory: TExprNodeFactory);
|
||
function Compile: TExprNode; virtual;
|
||
property Lexer: TExprLexer read FLexer;
|
||
property NodeFactory: TExprNodeFactory read FNodeFactory;
|
||
property Context: TExprContext read FContext write FContext;
|
||
|
||
// grammar starts here
|
||
|
||
function CompileExpr(ASkip: Boolean): TExprNode; virtual;
|
||
function CompileSimpleExpr(ASkip: Boolean): TExprNode;
|
||
function CompileTerm(ASkip: Boolean): TExprNode;
|
||
function CompileSignedFactor(ASkip: Boolean): TExprNode;
|
||
function CompileFactor: TExprNode;
|
||
function CompileIdentFactor: TExprNode;
|
||
end;
|
||
|
||
TExprEvalParser = class(TObject)
|
||
private
|
||
FContext: TExprContext;
|
||
FLexer: TExprLexer;
|
||
public
|
||
constructor Create(ALexer: TExprLexer);
|
||
function Evaluate: TFloat; virtual;
|
||
|
||
property Lexer: TExprLexer read FLexer;
|
||
property Context: TExprContext read FContext write FContext;
|
||
|
||
// grammar starts here
|
||
|
||
function EvalExpr(ASkip: Boolean): TFloat; virtual;
|
||
function EvalSimpleExpr(ASkip: Boolean): TFloat;
|
||
function EvalTerm(ASkip: Boolean): TFloat;
|
||
function EvalSignedFactor(ASkip: Boolean): TFloat;
|
||
function EvalFactor: TFloat;
|
||
function EvalIdentFactor: TFloat;
|
||
end;
|
||
|
||
{ some concrete class descendants follow... }
|
||
|
||
TExprSimpleLexer = class(TExprLexer)
|
||
protected
|
||
FCurrPos: PChar;
|
||
FBuf: string;
|
||
procedure SetBuf(const ABuf: string);
|
||
public
|
||
constructor Create(const ABuf: string);
|
||
|
||
procedure NextTok; override;
|
||
procedure Reset; override;
|
||
|
||
property Buf: string read FBuf write SetBuf;
|
||
end;
|
||
|
||
TExprVirtMachOp = class(TObject)
|
||
private
|
||
function GetOutputLoc: PFloat;
|
||
protected
|
||
FOutput: TFloat;
|
||
public
|
||
procedure Execute; virtual; abstract;
|
||
property OutputLoc: PFloat read GetOutputLoc;
|
||
end;
|
||
|
||
TExprVirtMach = class(TObject)
|
||
private
|
||
FCodeList: TList;
|
||
FConstList: TList;
|
||
public
|
||
constructor Create;
|
||
destructor Destroy; override;
|
||
procedure Add(AOp: TExprVirtMachOp);
|
||
procedure AddConst(AOp: TExprVirtMachOp);
|
||
procedure Clear;
|
||
function Execute: TFloat;
|
||
end;
|
||
|
||
TExprVirtMachNodeFactory = class(TExprNodeFactory)
|
||
private
|
||
FNodeList: TList;
|
||
function AddNode(ANode: TExprNode): TExprNode;
|
||
procedure DoClean(AVirtMach: TExprVirtMach);
|
||
procedure DoConsts(AVirtMach: TExprVirtMach);
|
||
procedure DoCode(AVirtMach: TExprVirtMach);
|
||
public
|
||
constructor Create;
|
||
destructor Destroy; override;
|
||
|
||
procedure GenCode(AVirtMach: TExprVirtMach);
|
||
|
||
function LoadVar32(ALoc: PFloat32): TExprNode; override;
|
||
function LoadVar64(ALoc: PFloat64): TExprNode; override;
|
||
function LoadVar80(ALoc: PFloat80): TExprNode; override;
|
||
function LoadConst32(AValue: TFloat32): TExprNode; override;
|
||
function LoadConst64(AValue: TFloat64): TExprNode; override;
|
||
function LoadConst80(AValue: TFloat80): TExprNode; override;
|
||
|
||
function CallFloatFunc(AFunc: TFloatFunc): TExprNode; override;
|
||
function CallFloat32Func(AFunc: TFloat32Func): TExprNode; override;
|
||
function CallFloat64Func(AFunc: TFloat64Func): TExprNode; override;
|
||
function CallFloat80Func(AFunc: TFloat80Func): TExprNode; override;
|
||
function CallUnaryFunc(AFunc: TUnaryFunc; X: TExprNode): TExprNode; override;
|
||
function CallUnary32Func(AFunc: TUnary32Func; X: TExprNode): TExprNode; override;
|
||
function CallUnary64Func(AFunc: TUnary64Func; X: TExprNode): TExprNode; override;
|
||
function CallUnary80Func(AFunc: TUnary80Func; X: TExprNode): TExprNode; override;
|
||
function CallBinaryFunc(AFunc: TBinaryFunc; X, Y: TExprNode): TExprNode; override;
|
||
function CallBinary32Func(AFunc: TBinary32Func; X, Y: TExprNode): TExprNode; override;
|
||
function CallBinary64Func(AFunc: TBinary64Func; X, Y: TExprNode): TExprNode; override;
|
||
function CallBinary80Func(AFunc: TBinary80Func; X, Y: TExprNode): TExprNode; override;
|
||
function CallTernaryFunc(AFunc: TTernaryFunc; X, Y, Z: TExprNode): TExprNode; override;
|
||
function CallTernary32Func(AFunc: TTernary32Func; X, Y, Z: TExprNode): TExprNode; override;
|
||
function CallTernary64Func(AFunc: TTernary64Func; X, Y, Z: TExprNode): TExprNode; override;
|
||
function CallTernary80Func(AFunc: TTernary80Func; X, Y, Z: TExprNode): TExprNode; override;
|
||
|
||
function Add(ALeft, ARight: TExprNode): TExprNode; override;
|
||
function Subtract(ALeft, ARight: TExprNode): TExprNode; override;
|
||
function Multiply(ALeft, ARight: TExprNode): TExprNode; override;
|
||
function Divide(ALeft, ARight: TExprNode): TExprNode; override;
|
||
function Negate(AValue: TExprNode): TExprNode; override;
|
||
function Compare(ALeft, ARight: TExprNode): TExprNode; override;
|
||
end;
|
||
|
||
{ some concrete symbols }
|
||
|
||
TExprConstSym = class(TExprSym)
|
||
private
|
||
FValue: TFloat;
|
||
public
|
||
constructor Create(const AIdent: string; AValue: TFloat);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprConst32Sym = class(TExprSym)
|
||
private
|
||
FValue: TFloat32;
|
||
public
|
||
constructor Create(const AIdent: string; AValue: TFloat32);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprConst64Sym = class(TExprSym)
|
||
private
|
||
FValue: TFloat64;
|
||
public
|
||
constructor Create(const AIdent: string; AValue: TFloat64);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprConst80Sym = class(TExprSym)
|
||
private
|
||
FValue: TFloat80;
|
||
public
|
||
constructor Create(const AIdent: string; AValue: TFloat80);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprVar32Sym = class(TExprSym)
|
||
private
|
||
FLoc: PFloat32;
|
||
public
|
||
constructor Create(const AIdent: string; ALoc: PFloat32);
|
||
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprVar64Sym = class(TExprSym)
|
||
private
|
||
FLoc: PFloat64;
|
||
public
|
||
constructor Create(const AIdent: string; ALoc: PFloat64);
|
||
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprVar80Sym = class(TExprSym)
|
||
private
|
||
FLoc: PFloat80;
|
||
public
|
||
constructor Create(const AIdent: string; ALoc: PFloat80);
|
||
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprAbstractFuncSym = class(TExprSym)
|
||
protected
|
||
function EvalFirstArg: TFloat;
|
||
function EvalNextArg: TFloat;
|
||
function CompileFirstArg: TExprNode;
|
||
function CompileNextArg: TExprNode;
|
||
procedure EndArgs;
|
||
end;
|
||
|
||
TExprFuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TFloatFunc;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TFloatFunc);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprFloat32FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TFloat32Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TFloat32Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprFloat64FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TFloat64Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TFloat64Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprFloat80FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TFloat80Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TFloat80Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprUnaryFuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TUnaryFunc;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TUnaryFunc);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprUnary32FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TUnary32Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TUnary32Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprUnary64FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TUnary64Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TUnary64Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprUnary80FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TUnary80Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TUnary80Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprBinaryFuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TBinaryFunc;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TBinaryFunc);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprBinary32FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TBinary32Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TBinary32Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprBinary64FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TBinary64Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TBinary64Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprBinary80FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TBinary80Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TBinary80Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprTernaryFuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TTernaryFunc;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TTernaryFunc);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprTernary32FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TTernary32Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TTernary32Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprTernary64FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TTernary64Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TTernary64Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TExprTernary80FuncSym = class(TExprAbstractFuncSym)
|
||
private
|
||
FFunc: TTernary80Func;
|
||
public
|
||
constructor Create(const AIdent: string; AFunc: TTernary80Func);
|
||
function Evaluate: TFloat; override;
|
||
function Compile: TExprNode; override;
|
||
end;
|
||
|
||
TEasyEvaluator = class(TObject)
|
||
private
|
||
FOwnContext: TExprHashContext;
|
||
FExtContextSet: TExprSetContext;
|
||
FInternalContextSet: TExprSetContext;
|
||
protected
|
||
property InternalContextSet: TExprSetContext read FInternalContextSet;
|
||
public
|
||
constructor Create;
|
||
destructor Destroy; override;
|
||
|
||
procedure AddVar(const AName: string; var AVar: TFloat32); overload;
|
||
procedure AddVar(const AName: string; var AVar: TFloat64); overload;
|
||
procedure AddVar(const AName: string; var AVar: TFloat80); overload;
|
||
|
||
procedure AddConst(const AName: string; AConst: TFloat32); overload;
|
||
procedure AddConst(const AName: string; AConst: TFloat64); overload;
|
||
procedure AddConst(const AName: string; AConst: TFloat80); overload;
|
||
|
||
procedure AddFunc(const AName: string; AFunc: TFloat32Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TFloat64Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TFloat80Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TUnary32Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TUnary64Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TUnary80Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TBinary32Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TBinary64Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TBinary80Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TTernary32Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TTernary64Func); overload;
|
||
procedure AddFunc(const AName: string; AFunc: TTernary80Func); overload;
|
||
procedure Remove(const AName: string);
|
||
|
||
procedure Clear;
|
||
property ExtContextSet: TExprSetContext read FExtContextSet;
|
||
end;
|
||
|
||
TEvaluator = class(TEasyEvaluator)
|
||
private
|
||
FLexer: TExprSimpleLexer;
|
||
FParser: TExprEvalParser;
|
||
public
|
||
constructor Create;
|
||
destructor Destroy; override;
|
||
function Evaluate(const AExpr: string): TFloat;
|
||
end;
|
||
|
||
TCompiledEvaluator = class(TEasyEvaluator)
|
||
private
|
||
FExpr: string;
|
||
FVirtMach: TExprVirtMach;
|
||
public
|
||
constructor Create;
|
||
destructor Destroy; override;
|
||
procedure Compile(const AExpr: string);
|
||
function Evaluate: TFloat;
|
||
end;
|
||
|
||
{ TODO : change this definition to be just a normal function pointer, not
|
||
a closure; will require a small executable memory allocater, and a
|
||
couple of injected instructions. Similar concept to
|
||
Forms.MakeObjectInstance.
|
||
|
||
This will allow compiled expressions to be used as functions in
|
||
contexts. Parameters won't be supported, though; I'll think about
|
||
this. }
|
||
|
||
TCompiledExpression = function: TFloat of object;
|
||
|
||
TExpressionCompiler = class(TEasyEvaluator)
|
||
private
|
||
FExprHash: TStringHashMap;
|
||
public
|
||
constructor Create;
|
||
destructor Destroy; override;
|
||
function Compile(const AExpr: string): TCompiledExpression;
|
||
procedure Remove(const AExpr: string);
|
||
procedure Delete(ACompiledExpression: TCompiledExpression);
|
||
procedure Clear;
|
||
end;
|
||
|
||
implementation
|
||
|
||
//=== { TExprHashContext } ===================================================
|
||
|
||
constructor TExprHashContext.Create(ACaseSensitive: Boolean; AHashSize: Integer);
|
||
begin
|
||
inherited Create;
|
||
if ACaseSensitive then
|
||
FHashMap := TStringHashMap.Create(CaseSensitiveTraits, AHashSize)
|
||
else
|
||
FHashMap := TStringHashMap.Create(CaseInsensitiveTraits, AHashSize);
|
||
end;
|
||
|
||
destructor TExprHashContext.Destroy;
|
||
begin
|
||
FHashMap.Iterate(nil, Iterate_FreeObjects);
|
||
FHashMap.Free;
|
||
inherited Destroy;
|
||
end;
|
||
|
||
procedure TExprHashContext.Add(ASymbol: TExprSym);
|
||
begin
|
||
FHashMap.Add(ASymbol.Ident, ASymbol);
|
||
end;
|
||
|
||
procedure TExprHashContext.Remove(const AName: string);
|
||
begin
|
||
TObject(FHashMap.Remove(AName)).Free;
|
||
end;
|
||
|
||
function TExprHashContext.Find(const AName: string): TExprSym;
|
||
begin
|
||
if not FHashMap.Find(AName, Result) then
|
||
Result := nil;
|
||
end;
|
||
|
||
//=== { TExprSetContext } ====================================================
|
||
|
||
constructor TExprSetContext.Create(AOwnsContexts: Boolean);
|
||
begin
|
||
inherited Create;
|
||
FOwnsContexts := AOwnsContexts;
|
||
FList := TList.Create;
|
||
end;
|
||
|
||
destructor TExprSetContext.Destroy;
|
||
begin
|
||
if FOwnsContexts then
|
||
ClearObjectList(FList);
|
||
FList.Free;
|
||
inherited Destroy;
|
||
end;
|
||
|
||
procedure TExprSetContext.Add(AContext: TExprContext);
|
||
begin
|
||
FList.Add(AContext);
|
||
end;
|
||
|
||
procedure TExprSetContext.Delete(AIndex: Integer);
|
||
begin
|
||
if FOwnsContexts then
|
||
TObject(FList[AIndex]).Free;
|
||
FList.Delete(AIndex);
|
||
end;
|
||
|
||
function TExprSetContext.Extract(AContext: TExprContext): TExprContext;
|
||
begin
|
||
Result := AContext;
|
||
FList.Remove(AContext);
|
||
end;
|
||
|
||
function TExprSetContext.Find(const AName: string): TExprSym;
|
||
var
|
||
I: Integer;
|
||
begin
|
||
Result := nil;
|
||
for I := Count - 1 downto 0 do
|
||
begin
|
||
Result := Contexts[I].Find(AName);
|
||
if Result <> nil then
|
||
Break;
|
||
end;
|
||
end;
|
||
|
||
function TExprSetContext.GetContexts(AIndex: Integer): TExprContext;
|
||
begin
|
||
Result := TExprContext(FList[AIndex]);
|
||
end;
|
||
|
||
function TExprSetContext.GetCount: Integer;
|
||
begin
|
||
Result := FList.Count;
|
||
end;
|
||
|
||
procedure TExprSetContext.Remove(AContext: TExprContext);
|
||
begin
|
||
FList.Remove(AContext);
|
||
if FOwnsContexts then
|
||
AContext.Free;
|
||
end;
|
||
|
||
//=== { TExprSym } ===========================================================
|
||
|
||
constructor TExprSym.Create(const AIdent: string);
|
||
begin
|
||
inherited Create;
|
||
FIdent := AIdent;
|
||
end;
|
||
|
||
//=== { TExprLexer } =========================================================
|
||
|
||
constructor TExprLexer.Create;
|
||
begin
|
||
inherited Create;
|
||
Reset;
|
||
end;
|
||
|
||
procedure TExprLexer.Reset;
|
||
begin
|
||
NextTok;
|
||
end;
|
||
|
||
//=== { TExprCompileParser } =================================================
|
||
|
||
constructor TExprCompileParser.Create(ALexer: TExprLexer; ANodeFactory: TExprNodeFactory);
|
||
begin
|
||
inherited Create;
|
||
FLexer := ALexer;
|
||
FNodeFactory := ANodeFactory;
|
||
end;
|
||
|
||
function TExprCompileParser.Compile: TExprNode;
|
||
begin
|
||
Result := CompileExpr(False);
|
||
end;
|
||
|
||
function TExprCompileParser.CompileExpr(ASkip: Boolean): TExprNode;
|
||
begin
|
||
Result := CompileSimpleExpr(ASkip);
|
||
|
||
{ Utilize some of these compound instructions to test DAG optimization
|
||
techniques later on.
|
||
|
||
Playing a few games after much hard work, too.
|
||
Functional programming is fun! :-> BJK }
|
||
while True do
|
||
case Lexer.CurrTok of
|
||
etEqualTo: // =
|
||
begin
|
||
// need to return 1 if true, 0 if false
|
||
// compare will return 0 if true, -1 / +1 if false
|
||
// squaring will force a positive or zero value
|
||
// subtract value from 1 to get answer
|
||
// IOW: 1 - Sqr(Compare(X, Y))
|
||
|
||
// first, get comparison
|
||
Result := NodeFactory.Compare(Result, CompileSimpleExpr(True));
|
||
|
||
// next, square comparison - note that this
|
||
// forces a common sub-expression; parse tree will no longer
|
||
// be a tree, but a DAG
|
||
Result := NodeFactory.Multiply(Result, Result);
|
||
|
||
// finally, subtract from one
|
||
Result := NodeFactory.Subtract(
|
||
NodeFactory.LoadConst32(1),
|
||
Result
|
||
);
|
||
end;
|
||
|
||
etNotEqual: // <>
|
||
begin
|
||
// same as above, but without the subtract
|
||
Result := NodeFactory.Compare(Result, CompileSimpleExpr(True));
|
||
Result := NodeFactory.Multiply(Result, Result);
|
||
end;
|
||
|
||
etLessThan: // <
|
||
begin
|
||
// have 1 for less than, 0 for equal, 0 for greater than too
|
||
// c = compare(X, Y)
|
||
// d = c * c
|
||
// if less than, d = 1, c = -1; d - c = 2
|
||
// if greater than, d = c = 1; d - c = 0
|
||
// if equal, d = c = 0; d - c = 0
|
||
// IOW: (Sqr(compare(X, Y)) - compare(X, Y)) / 2
|
||
|
||
// get comparison
|
||
Result := NodeFactory.Compare(Result, CompileSimpleExpr(True));
|
||
// subtract from square
|
||
Result := NodeFactory.Subtract(
|
||
NodeFactory.Multiply(
|
||
Result,
|
||
Result
|
||
),
|
||
Result
|
||
);
|
||
// divide by two
|
||
Result := NodeFactory.Divide(Result, NodeFactory.LoadConst32(2));
|
||
end;
|
||
|
||
etLessEqual: // <=
|
||
begin
|
||
// less than or equal to return 1, greater than returns 0
|
||
// c = compare(X, Y)
|
||
// d = c * c
|
||
// < c = -1, d = 1, c + d = 0
|
||
// = c = 0, d = 0, c + d = 0
|
||
// > c = +1, d = 1, c + d = 2
|
||
// then divide by two, take away from 1
|
||
// IOW: 1 - (compare(X, Y) + Sqr(compare(X, Y))) / 2
|
||
Result := NodeFactory.Compare(Result, CompileSimpleExpr(True));
|
||
// now, for some fun!
|
||
Result := NodeFactory.Subtract(
|
||
NodeFactory.LoadConst32(1),
|
||
NodeFactory.Divide(
|
||
NodeFactory.Add(
|
||
Result,
|
||
NodeFactory.Multiply(
|
||
Result,
|
||
Result
|
||
)
|
||
),
|
||
NodeFactory.LoadConst32(2)
|
||
)
|
||
);
|
||
end;
|
||
|
||
etGreaterThan: // >
|
||
begin
|
||
// same as <=, without the taking away from 1 bit
|
||
Result := NodeFactory.Compare(Result, CompileSimpleExpr(True));
|
||
Result := NodeFactory.Divide(
|
||
NodeFactory.Add(
|
||
Result,
|
||
NodeFactory.Multiply(
|
||
Result,
|
||
Result
|
||
)
|
||
),
|
||
NodeFactory.LoadConst32(2)
|
||
);
|
||
end;
|
||
|
||
etGreaterEqual: // >=
|
||
begin
|
||
// same as less than, but subtract from one
|
||
Result := NodeFactory.Compare(Result, CompileSimpleExpr(True));
|
||
Result := NodeFactory.Subtract(
|
||
NodeFactory.Multiply(
|
||
Result,
|
||
Result
|
||
),
|
||
Result
|
||
);
|
||
Result := NodeFactory.Divide(Result, NodeFactory.LoadConst32(2));
|
||
Result := NodeFactory.Subtract(NodeFactory.LoadConst32(1), Result);
|
||
end;
|
||
else
|
||
Break;
|
||
end;
|
||
end;
|
||
|
||
function TExprCompileParser.CompileSimpleExpr(ASkip: Boolean): TExprNode;
|
||
begin
|
||
Result := CompileTerm(ASkip);
|
||
|
||
while True do
|
||
case Lexer.CurrTok of
|
||
etPlus:
|
||
Result := NodeFactory.Add(Result, CompileTerm(True));
|
||
etMinus:
|
||
Result := NodeFactory.Subtract(Result, CompileTerm(True));
|
||
else
|
||
Break;
|
||
end;
|
||
end;
|
||
|
||
function TExprCompileParser.CompileTerm(ASkip: Boolean): TExprNode;
|
||
begin
|
||
Result := CompileSignedFactor(ASkip);
|
||
|
||
while True do
|
||
case Lexer.CurrTok of
|
||
etAsterisk:
|
||
Result := NodeFactory.Multiply(Result, CompileSignedFactor(True));
|
||
etForwardSlash:
|
||
Result := NodeFactory.Divide(Result, CompileSignedFactor(True));
|
||
else
|
||
Break;
|
||
end;
|
||
end;
|
||
|
||
function TExprCompileParser.CompileSignedFactor(ASkip: Boolean): TExprNode;
|
||
var
|
||
Neg: Boolean;
|
||
begin
|
||
if ASkip then
|
||
Lexer.NextTok;
|
||
|
||
Neg := False;
|
||
while True do
|
||
begin
|
||
case Lexer.CurrTok of
|
||
etPlus:
|
||
{ do nothing };
|
||
etMinus:
|
||
Neg := not Neg;
|
||
else
|
||
Break;
|
||
end;
|
||
Lexer.NextTok;
|
||
end;
|
||
|
||
Result := CompileFactor;
|
||
if Neg then
|
||
Result := NodeFactory.Negate(Result);
|
||
end;
|
||
|
||
function TExprCompileParser.CompileFactor: TExprNode;
|
||
begin
|
||
case Lexer.CurrTok of
|
||
etNumber:
|
||
begin
|
||
Result := NodeFactory.LoadConst64(Lexer.TokenAsNumber);
|
||
Lexer.NextTok;
|
||
end;
|
||
etIdentifier:
|
||
Result := CompileIdentFactor;
|
||
etLParen:
|
||
begin
|
||
Result := CompileExpr(True);
|
||
if Lexer.CurrTok <> etRParen then
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalRParenExpected);
|
||
Lexer.NextTok;
|
||
end;
|
||
else
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalFactorExpected);
|
||
end;
|
||
end;
|
||
|
||
function TExprCompileParser.CompileIdentFactor: TExprNode;
|
||
var
|
||
Sym: TExprSym;
|
||
oldCompileParser: TExprCompileParser;
|
||
oldLexer: TExprLexer;
|
||
oldNodeFactory: TExprNodeFactory;
|
||
begin
|
||
{ find symbol }
|
||
if FContext = nil then
|
||
raise EJclExprEvalError.CreateResFmt(@RsExprEvalUnknownSymbol,
|
||
[Lexer.TokenAsString]);
|
||
Sym := FContext.Find(Lexer.TokenAsString);
|
||
if Sym = nil then
|
||
raise EJclExprEvalError.CreateResFmt(@RsExprEvalUnknownSymbol,
|
||
[Lexer.TokenAsString]);
|
||
|
||
Lexer.NextTok;
|
||
|
||
{ set symbol properties }
|
||
oldCompileParser := Sym.CompileParser;
|
||
oldLexer := Sym.Lexer;
|
||
oldNodeFactory := Sym.NodeFactory;
|
||
Sym.FLexer := Lexer;
|
||
Sym.FCompileParser := Self;
|
||
Sym.FNodeFactory := NodeFactory;
|
||
try
|
||
{ compile symbol }
|
||
Result := Sym.Compile;
|
||
finally
|
||
Sym.FLexer := oldLexer;
|
||
Sym.FCompileParser := oldCompileParser;
|
||
Sym.FNodeFactory := oldNodeFactory;
|
||
end;
|
||
end;
|
||
|
||
//=== { TExprEvalParser } ====================================================
|
||
|
||
constructor TExprEvalParser.Create(ALexer: TExprLexer);
|
||
begin
|
||
inherited Create;
|
||
FLexer := ALexer;
|
||
end;
|
||
|
||
function TExprEvalParser.Evaluate: TFloat;
|
||
begin
|
||
Result := EvalExpr(False);
|
||
|
||
if (Lexer.CurrTok <> etEof) then
|
||
begin
|
||
raise EJclExprEvalError.CreateResFmt(@RsExprEvalUnknownSymbol,
|
||
[Lexer.TokenAsString]);
|
||
end;
|
||
end;
|
||
|
||
function TExprEvalParser.EvalExpr(ASkip: Boolean): TFloat;
|
||
begin
|
||
Result := EvalSimpleExpr(ASkip);
|
||
|
||
while True do
|
||
case Lexer.CurrTok of
|
||
etEqualTo: // =
|
||
if Result = EvalSimpleExpr(True) then
|
||
Result := 1.0
|
||
else
|
||
Result := 0.0;
|
||
etNotEqual: // <>
|
||
if Result <> EvalSimpleExpr(True) then
|
||
Result := 1.0
|
||
else
|
||
Result := 0.0;
|
||
etLessThan: // <
|
||
if Result < EvalSimpleExpr(True) then
|
||
Result := 1.0
|
||
else
|
||
Result := 0.0;
|
||
etLessEqual: // <=
|
||
if Result <= EvalSimpleExpr(True) then
|
||
Result := 1.0
|
||
else
|
||
Result := 0.0;
|
||
etGreaterThan: // >
|
||
if Result > EvalSimpleExpr(True) then
|
||
Result := 1.0
|
||
else
|
||
Result := 0.0;
|
||
etGreaterEqual: // >=
|
||
if Result >= EvalSimpleExpr(True) then
|
||
Result := 1.0
|
||
else
|
||
Result := 0.0;
|
||
else
|
||
Break;
|
||
end;
|
||
end;
|
||
|
||
function TExprEvalParser.EvalSimpleExpr(ASkip: Boolean): TFloat;
|
||
begin
|
||
Result := EvalTerm(ASkip);
|
||
|
||
while True do
|
||
case Lexer.CurrTok of
|
||
etPlus:
|
||
Result := Result + EvalTerm(True);
|
||
etMinus:
|
||
Result := Result - EvalTerm(True);
|
||
else
|
||
Break;
|
||
end;
|
||
end;
|
||
|
||
function TExprEvalParser.EvalTerm(ASkip: Boolean): TFloat;
|
||
begin
|
||
Result := EvalSignedFactor(ASkip);
|
||
|
||
while True do
|
||
case Lexer.CurrTok of
|
||
etAsterisk:
|
||
Result := Result * EvalSignedFactor(True);
|
||
etForwardSlash:
|
||
Result := Result / EvalSignedFactor(True);
|
||
else
|
||
Break;
|
||
end;
|
||
end;
|
||
|
||
function TExprEvalParser.EvalSignedFactor(ASkip: Boolean): TFloat;
|
||
var
|
||
Neg: Boolean;
|
||
begin
|
||
if ASkip then
|
||
Lexer.NextTok;
|
||
|
||
Neg := False;
|
||
while True do
|
||
begin
|
||
case Lexer.CurrTok of
|
||
etPlus:
|
||
{ do nothing };
|
||
etMinus:
|
||
Neg := not Neg;
|
||
else
|
||
Break;
|
||
end;
|
||
Lexer.NextTok;
|
||
end;
|
||
|
||
Result := EvalFactor;
|
||
if Neg then
|
||
Result := -Result;
|
||
end;
|
||
|
||
function TExprEvalParser.EvalFactor: TFloat;
|
||
begin
|
||
case Lexer.CurrTok of
|
||
etIdentifier:
|
||
begin
|
||
Result := EvalIdentFactor;
|
||
end;
|
||
|
||
etLParen:
|
||
begin
|
||
Result := EvalExpr(True);
|
||
if Lexer.CurrTok <> etRParen then
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalRParenExpected);
|
||
Lexer.NextTok;
|
||
end;
|
||
etNumber:
|
||
begin
|
||
Result := Lexer.TokenAsNumber;
|
||
Lexer.NextTok;
|
||
end;
|
||
else
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalFactorExpected);
|
||
end;
|
||
end;
|
||
|
||
function TExprEvalParser.EvalIdentFactor: TFloat;
|
||
var
|
||
Sym: TExprSym;
|
||
oldEvalParser: TExprEvalParser;
|
||
oldLexer: TExprLexer;
|
||
begin
|
||
{ find symbol }
|
||
if Context = nil then
|
||
raise EJclExprEvalError.CreateResFmt(@RsExprEvalUnknownSymbol,
|
||
[Lexer.TokenAsString]);
|
||
Sym := FContext.Find(Lexer.TokenAsString);
|
||
if Sym = nil then
|
||
raise EJclExprEvalError.CreateResFmt(@RsExprEvalUnknownSymbol,
|
||
[Lexer.TokenAsString]);
|
||
|
||
Lexer.NextTok;
|
||
|
||
{ set symbol properties }
|
||
oldEvalParser := Sym.FEvalParser;
|
||
oldLexer := Sym.Lexer;
|
||
Sym.FLexer := Lexer;
|
||
Sym.FEvalParser := Self;
|
||
try
|
||
{ evaluate symbol }
|
||
Result := Sym.Evaluate;
|
||
finally
|
||
Sym.FLexer := oldLexer;
|
||
Sym.FEvalParser := oldEvalParser;
|
||
end;
|
||
end;
|
||
|
||
//=== { TExprSimpleLexer } ===================================================
|
||
|
||
constructor TExprSimpleLexer.Create(const ABuf: string);
|
||
begin
|
||
FBuf := ABuf;
|
||
inherited Create;
|
||
end;
|
||
|
||
procedure TExprSimpleLexer.NextTok;
|
||
const
|
||
CharToTokenMap: array [Char] of TExprToken =
|
||
(
|
||
{#0..#31}
|
||
etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid, etInvalid,
|
||
{#32} etInvalid,
|
||
{#33} etBang, {#34} etDoubleQuote, {#35} etHash, {#36} etDollar,
|
||
{#37} etPercent, {#38} etAmpersand, {#39} etSingleQuote, {#40} etLParen,
|
||
{#41} etRParen, {#42} etAsterisk, {#43} etPlus, {#44} etComma,
|
||
{#45} etMinus, {#46} etDot, {#47} etForwardSlash,
|
||
// 48..57 - numbers...
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid,
|
||
{#58} etColon, {#59} etSemiColon, {#60} etLessThan, {#61} etEqualTo,
|
||
{#62} etGreaterThan, {#63} etQuestion, {#64} etAt,
|
||
// 65..90 - capital letters...
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid,
|
||
{#91} etLBracket, {#92} etBackSlash, {#93} etRBracket, {#94} etArrow,
|
||
etInvalid, // 95 - underscore
|
||
{#96} etBackTick,
|
||
// 97..122 - small letters...
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid, etInvalid, etInvalid,
|
||
etInvalid, etInvalid,
|
||
{#123} etLBrace,
|
||
{#124} etPipe, {#125} etRBrace, {#126} etTilde, {#127} et127,
|
||
{#128} etEuro, {#129} et129, {#130} et130, {#131} et131,
|
||
{#132} et132, {#133} et133, {#134} et134, {#135} et135,
|
||
{#136} et136, {#137} et137, {#138} et138, {#139} et139,
|
||
{#140} et140, {#141} et141, {#142} et142, {#143} et143,
|
||
{#144} et144, {#145} et145, {#146} et146, {#147} et147,
|
||
{#148} et148, {#149} et149, {#150} et150, {#151} et151,
|
||
{#152} et152, {#153} et153, {#154} et154, {#155} et155,
|
||
{#156} et156, {#157} et157, {#158} et158, {#159} et159,
|
||
{#160} et160, {#161} et161, {#162} et162, {#163} et163,
|
||
{#164} et164, {#165} et165, {#166} et166, {#167} et167,
|
||
{#168} et168, {#169} et169, {#170} et170, {#171} et171,
|
||
{#172} et172, {#173} et173, {#174} et174, {#175} et175,
|
||
{#176} et176, {#177} et177, {#178} et178, {#179} et179,
|
||
{#180} et180, {#181} et181, {#182} et182, {#183} et183,
|
||
{#184} et184, {#185} et185, {#186} et186, {#187} et187,
|
||
{#188} et188, {#189} et189, {#190} et190, {#191} et191,
|
||
{#192} et192, {#193} et193, {#194} et194, {#195} et195,
|
||
{#196} et196, {#197} et197, {#198} et198, {#199} et199,
|
||
{#200} et200, {#201} et201, {#202} et202, {#203} et203,
|
||
{#204} et204, {#205} et205, {#206} et206, {#207} et207,
|
||
{#208} et208, {#209} et209, {#210} et210, {#211} et211,
|
||
{#212} et212, {#213} et213, {#214} et214, {#215} et215,
|
||
{#216} et216, {#217} et217, {#218} et218, {#219} et219,
|
||
{#220} et220, {#221} et221, {#222} et222, {#223} et223,
|
||
{#224} et224, {#225} et225, {#226} et226, {#227} et227,
|
||
{#228} et228, {#229} et229, {#230} et230, {#231} et231,
|
||
{#232} et232, {#233} et233, {#234} et234, {#235} et235,
|
||
{#236} et236, {#237} et237, {#238} et238, {#239} et239,
|
||
{#240} et240, {#241} et241, {#242} et242, {#243} et243,
|
||
{#244} et244, {#245} et245, {#246} et246, {#247} et247,
|
||
{#248} et248, {#249} et249, {#250} et250, {#251} et251,
|
||
{#252} et252, {#253} et253, {#254} et254, {#255} et255
|
||
);
|
||
var
|
||
{ register variable optimization }
|
||
cp: PChar;
|
||
start: PChar;
|
||
begin
|
||
cp := FCurrPos;
|
||
|
||
{ skip whitespace }
|
||
while cp^ in ExprWhiteSpace do
|
||
Inc(cp);
|
||
|
||
{ determine token type }
|
||
case cp^ of
|
||
#0:
|
||
FCurrTok := etEof;
|
||
'a'..'z', 'A'..'Z', '_':
|
||
begin
|
||
start := cp;
|
||
Inc(cp);
|
||
while cp^ in ['0'..'9', 'a'..'z', 'A'..'Z', '_'] do
|
||
Inc(cp);
|
||
SetString(FTokenAsString, start, cp - start);
|
||
FCurrTok := etIdentifier;
|
||
end;
|
||
'0'..'9':
|
||
begin
|
||
start := cp;
|
||
|
||
{ read in integer part of mantissa }
|
||
while cp^ in ['0'..'9'] do
|
||
Inc(cp);
|
||
|
||
{ check for and read in fraction part of mantissa }
|
||
if (cp^ = '.') or (cp^ = DecimalSeparator) then
|
||
begin
|
||
Inc(cp);
|
||
while cp^ in ['0'..'9'] do
|
||
Inc(cp);
|
||
end;
|
||
|
||
{ check for and read in exponent }
|
||
if cp^ in ['e', 'E'] then
|
||
begin
|
||
Inc(cp);
|
||
if cp^ in ['+', '-'] then
|
||
Inc(cp);
|
||
while cp^ in ['0'..'9'] do
|
||
Inc(cp);
|
||
end;
|
||
|
||
{ evaluate number }
|
||
SetString(FTokenAsString, start, cp - start);
|
||
FTokenAsNumber := StrToFloat(FTokenAsString);
|
||
|
||
FCurrTok := etNumber;
|
||
end;
|
||
'<':
|
||
begin
|
||
Inc(cp);
|
||
case cp^ of
|
||
'=':
|
||
begin
|
||
FCurrTok := etLessEqual;
|
||
Inc(cp);
|
||
end;
|
||
'>':
|
||
begin
|
||
FCurrTok := etNotEqual;
|
||
Inc(cp);
|
||
end;
|
||
else
|
||
FCurrTok := etLessThan;
|
||
end;
|
||
end;
|
||
'>':
|
||
begin
|
||
Inc(cp);
|
||
if cp^ = '=' then
|
||
begin
|
||
FCurrTok := etGreaterEqual;
|
||
Inc(cp);
|
||
end
|
||
else
|
||
FCurrTok := etGreaterThan;
|
||
end;
|
||
else
|
||
{ map character to token }
|
||
FCurrTok := CharToTokenMap[cp^];
|
||
Inc(cp);
|
||
end;
|
||
|
||
FCurrPos := cp;
|
||
end;
|
||
|
||
procedure TExprSimpleLexer.Reset;
|
||
begin
|
||
FCurrPos := PChar(FBuf);
|
||
inherited Reset;
|
||
end;
|
||
|
||
procedure TExprSimpleLexer.SetBuf(const ABuf: string);
|
||
begin
|
||
FBuf := ABuf;
|
||
Reset;
|
||
end;
|
||
|
||
//=== { TExprNode } ==========================================================
|
||
|
||
constructor TExprNode.Create(const ADepList: array of TExprNode);
|
||
var
|
||
I: Integer;
|
||
begin
|
||
inherited Create;
|
||
FDepList := TList.Create;
|
||
for I := Low(ADepList) to High(ADepList) do
|
||
AddDep(ADepList[I]);
|
||
end;
|
||
|
||
destructor TExprNode.Destroy;
|
||
begin
|
||
FDepList.Free;
|
||
inherited Destroy;
|
||
end;
|
||
|
||
procedure TExprNode.AddDep(ADep: TExprNode);
|
||
begin
|
||
FDepList.Add(ADep);
|
||
end;
|
||
|
||
function TExprNode.GetDepCount: Integer;
|
||
begin
|
||
Result := FDepList.Count;
|
||
end;
|
||
|
||
function TExprNode.GetDeps(AIndex: Integer): TExprNode;
|
||
begin
|
||
Result := TExprNode(FDepList[AIndex]);
|
||
end;
|
||
|
||
//=== { TExprNodeFactory } ===================================================
|
||
|
||
function TExprNodeFactory.LoadVar(ALoc: PFloat32): TExprNode;
|
||
begin
|
||
Result := LoadVar32(ALoc);
|
||
end;
|
||
|
||
function TExprNodeFactory.LoadVar(ALoc: PFloat64): TExprNode;
|
||
begin
|
||
Result := LoadVar64(ALoc);
|
||
end;
|
||
|
||
function TExprNodeFactory.LoadVar(ALoc: PFloat80): TExprNode;
|
||
begin
|
||
Result := LoadVar80(ALoc);
|
||
end;
|
||
|
||
function TExprNodeFactory.LoadConst(AValue: TFloat32): TExprNode;
|
||
begin
|
||
Result := LoadConst32(AValue);
|
||
end;
|
||
|
||
function TExprNodeFactory.LoadConst(AValue: TFloat64): TExprNode;
|
||
begin
|
||
Result := LoadConst64(AValue);
|
||
end;
|
||
|
||
function TExprNodeFactory.LoadConst(AValue: TFloat80): TExprNode;
|
||
begin
|
||
Result := LoadConst80(AValue);
|
||
end;
|
||
|
||
//=== { TEvaluator } =========================================================
|
||
|
||
constructor TEvaluator.Create;
|
||
begin
|
||
inherited Create;
|
||
|
||
FLexer := TExprSimpleLexer.Create('');
|
||
FParser := TExprEvalParser.Create(FLexer);
|
||
|
||
FParser.Context := InternalContextSet;
|
||
end;
|
||
|
||
destructor TEvaluator.Destroy;
|
||
begin
|
||
FParser.Free;
|
||
FLexer.Free;
|
||
inherited Destroy;
|
||
end;
|
||
|
||
function TEvaluator.Evaluate(const AExpr: string): TFloat;
|
||
begin
|
||
FLexer.Buf := AExpr;
|
||
Result := FParser.Evaluate;
|
||
end;
|
||
|
||
//=== { TExprVirtMachOp } ====================================================
|
||
|
||
function TExprVirtMachOp.GetOutputLoc: PFloat;
|
||
begin
|
||
Result := @FOutput;
|
||
end;
|
||
|
||
//=== Virtual machine operators follow =======================================
|
||
|
||
type
|
||
{ abstract base for var readers }
|
||
TExprVarVmOp = class(TExprVirtMachOp)
|
||
private
|
||
FVarLoc: Pointer;
|
||
public
|
||
constructor Create(AVarLoc: Pointer);
|
||
end;
|
||
|
||
TExprVarVmOpClass = class of TExprVarVmOp;
|
||
|
||
{ the var readers }
|
||
|
||
TExprVar32VmOp = class(TExprVarVmOp)
|
||
public
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprVar64VmOp = class(TExprVarVmOp)
|
||
public
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprVar80VmOp = class(TExprVarVmOp)
|
||
public
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
{ the const holder }
|
||
TExprConstVmOp = class(TExprVirtMachOp)
|
||
public
|
||
constructor Create(AValue: TFloat);
|
||
{ null function }
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
{ abstract unary operator }
|
||
TExprUnaryVmOp = class(TExprVirtMachOp)
|
||
protected
|
||
FInput: PFloat;
|
||
public
|
||
constructor Create(AInput: PFloat);
|
||
property Input: PFloat read FInput write FInput;
|
||
end;
|
||
|
||
TExprUnaryVmOpClass = class of TExprUnaryVmOp;
|
||
|
||
{ abstract binary operator }
|
||
TExprBinaryVmOp = class(TExprVirtMachOp)
|
||
protected
|
||
FLeft: PFloat;
|
||
FRight: PFloat;
|
||
public
|
||
constructor Create(ALeft, ARight: PFloat);
|
||
property Left: PFloat read FLeft write FLeft;
|
||
property Right: PFloat read FRight write FRight;
|
||
end;
|
||
|
||
TExprBinaryVmOpClass = class of TExprBinaryVmOp;
|
||
|
||
{ the 4 basic binary operators }
|
||
|
||
TExprAddVmOp = class(TExprBinaryVmOp)
|
||
public
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprSubtractVmOp = class(TExprBinaryVmOp)
|
||
public
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprMultiplyVmOp = class(TExprBinaryVmOp)
|
||
public
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprDivideVmOp = class(TExprBinaryVmOp)
|
||
public
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCompareVmOp = class(TExprBinaryVmOp)
|
||
public
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
{ the unary operators }
|
||
|
||
TExprNegateVmOp = class(TExprUnaryVmOp)
|
||
public
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
{ function calls }
|
||
|
||
TExprCallFloatVmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TFloatFunc;
|
||
public
|
||
constructor Create(AFunc: TFloatFunc);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallFloat32VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TFloat32Func;
|
||
public
|
||
constructor Create(AFunc: TFloat32Func);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallFloat64VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TFloat64Func;
|
||
public
|
||
constructor Create(AFunc: TFloat64Func);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallFloat80VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TFloat80Func;
|
||
public
|
||
constructor Create(AFunc: TFloat80Func);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallUnaryVmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TUnaryFunc;
|
||
FX: PFloat;
|
||
public
|
||
constructor Create(AFunc: TUnaryFunc; X: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallUnary32VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TUnary32Func;
|
||
FX: PFloat;
|
||
public
|
||
constructor Create(AFunc: TUnary32Func; X: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallUnary64VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TUnary64Func;
|
||
FX: PFloat;
|
||
public
|
||
constructor Create(AFunc: TUnary64Func; X: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallUnary80VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TUnary80Func;
|
||
FX: PFloat;
|
||
public
|
||
constructor Create(AFunc: TUnary80Func; X: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallBinaryVmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TBinaryFunc;
|
||
FX, FY: PFloat;
|
||
public
|
||
constructor Create(AFunc: TBinaryFunc; X, Y: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallBinary32VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TBinary32Func;
|
||
FX, FY: PFloat;
|
||
public
|
||
constructor Create(AFunc: TBinary32Func; X, Y: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallBinary64VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TBinary64Func;
|
||
FX, FY: PFloat;
|
||
public
|
||
constructor Create(AFunc: TBinary64Func; X, Y: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallBinary80VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TBinary80Func;
|
||
FX, FY: PFloat;
|
||
public
|
||
constructor Create(AFunc: TBinary80Func; X, Y: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallTernaryVmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TTernaryFunc;
|
||
FX, FY, FZ: PFloat;
|
||
public
|
||
constructor Create(AFunc: TTernaryFunc; X, Y, Z: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallTernary32VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TTernary32Func;
|
||
FX, FY, FZ: PFloat;
|
||
public
|
||
constructor Create(AFunc: TTernary32Func; X, Y, Z: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallTernary64VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TTernary64Func;
|
||
FX, FY, FZ: PFloat;
|
||
public
|
||
constructor Create(AFunc: TTernary64Func; X, Y, Z: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
TExprCallTernary80VmOp = class(TExprVirtMachOp)
|
||
private
|
||
FFunc: TTernary80Func;
|
||
FX, FY, FZ: PFloat;
|
||
public
|
||
constructor Create(AFunc: TTernary80Func; X, Y, Z: PFloat);
|
||
procedure Execute; override;
|
||
end;
|
||
|
||
//=== { TExprVar32VmOp } =====================================================
|
||
|
||
procedure TExprVar32VmOp.Execute;
|
||
begin
|
||
FOutput := PFloat32(FVarLoc)^;
|
||
end;
|
||
|
||
//=== { TExprVar64VmOp } =====================================================
|
||
|
||
procedure TExprVar64VmOp.Execute;
|
||
begin
|
||
FOutput := PFloat64(FVarLoc)^;
|
||
end;
|
||
|
||
//=== { TExprVar80VmOp } =====================================================
|
||
|
||
procedure TExprVar80VmOp.Execute;
|
||
begin
|
||
FOutput := PFloat80(FVarLoc)^;
|
||
end;
|
||
|
||
//=== { TExprConstVmOp } =====================================================
|
||
|
||
constructor TExprConstVmOp.Create(AValue: TFloat);
|
||
begin
|
||
inherited Create;
|
||
FOutput := AValue;
|
||
end;
|
||
|
||
procedure TExprConstVmOp.Execute;
|
||
begin
|
||
end;
|
||
|
||
//=== { TExprUnaryVmOp } =====================================================
|
||
|
||
constructor TExprUnaryVmOp.Create(AInput: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FInput := AInput;
|
||
end;
|
||
|
||
//=== { TExprBinaryVmOp } ====================================================
|
||
|
||
constructor TExprBinaryVmOp.Create(ALeft, ARight: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FLeft := ALeft;
|
||
FRight := ARight;
|
||
end;
|
||
|
||
//=== { TExprAddVmOp } =======================================================
|
||
procedure TExprAddVmOp.Execute;
|
||
begin
|
||
FOutput := FLeft^ + FRight^;
|
||
end;
|
||
|
||
//=== { TExprSubtractVmOp } ==================================================
|
||
|
||
procedure TExprSubtractVmOp.Execute;
|
||
begin
|
||
FOutput := FLeft^ - FRight^;
|
||
end;
|
||
|
||
//=== { TExprMultiplyVmOp } ==================================================
|
||
|
||
procedure TExprMultiplyVmOp.Execute;
|
||
begin
|
||
FOutput := FLeft^ * FRight^;
|
||
end;
|
||
|
||
//=== { TExprDivideVmOp } ====================================================
|
||
|
||
procedure TExprDivideVmOp.Execute;
|
||
begin
|
||
FOutput := FLeft^ / FRight^;
|
||
end;
|
||
|
||
//=== { TExprCompareVmOp } ===================================================
|
||
|
||
procedure TExprCompareVmOp.Execute;
|
||
begin
|
||
if FLeft^ < FRight^ then
|
||
FOutput := -1.0
|
||
else
|
||
if FLeft^ > FRight^ then
|
||
FOutput := 1.0
|
||
else
|
||
FOutput := 0.0;
|
||
end;
|
||
|
||
//=== { TExprNegateVmOp } ====================================================
|
||
|
||
procedure TExprNegateVmOp.Execute;
|
||
begin
|
||
FOutput := - FInput^;
|
||
end;
|
||
|
||
//=== { TExprVarVmOp } =======================================================
|
||
|
||
constructor TExprVarVmOp.Create(AVarLoc: Pointer);
|
||
begin
|
||
inherited Create;
|
||
FVarLoc := AVarLoc;
|
||
end;
|
||
|
||
//=== { TExprCallFloatVmOp } =================================================
|
||
|
||
constructor TExprCallFloatVmOp.Create(AFunc: TFloatFunc);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
procedure TExprCallFloatVmOp.Execute;
|
||
begin
|
||
FOutput := FFunc;
|
||
end;
|
||
|
||
//=== { TExprCallFloat32VmOp } ===============================================
|
||
|
||
constructor TExprCallFloat32VmOp.Create(AFunc: TFloat32Func);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
procedure TExprCallFloat32VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc;
|
||
end;
|
||
|
||
//=== { TExprCallFloat64VmOp } ===============================================
|
||
|
||
constructor TExprCallFloat64VmOp.Create(AFunc: TFloat64Func);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
procedure TExprCallFloat64VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc;
|
||
end;
|
||
|
||
//=== { TExprCallFloat80VmOp } ===============================================
|
||
|
||
constructor TExprCallFloat80VmOp.Create(AFunc: TFloat80Func);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
procedure TExprCallFloat80VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc;
|
||
end;
|
||
|
||
//=== { TExprCallUnaryVmOp } =================================================
|
||
|
||
constructor TExprCallUnaryVmOp.Create(AFunc: TUnaryFunc; X: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
end;
|
||
|
||
procedure TExprCallUnaryVmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^);
|
||
end;
|
||
|
||
//=== { TExprCallUnary32VmOp } ===============================================
|
||
|
||
constructor TExprCallUnary32VmOp.Create(AFunc: TUnary32Func; X: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
end;
|
||
|
||
procedure TExprCallUnary32VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^);
|
||
end;
|
||
|
||
//=== { TExprCallUnary64VmOp } ===============================================
|
||
|
||
constructor TExprCallUnary64VmOp.Create(AFunc: TUnary64Func; X: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
end;
|
||
|
||
procedure TExprCallUnary64VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^);
|
||
end;
|
||
|
||
//=== { TExprCallUnary80VmOp } ===============================================
|
||
|
||
constructor TExprCallUnary80VmOp.Create(AFunc: TUnary80Func; X: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
end;
|
||
|
||
procedure TExprCallUnary80VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^);
|
||
end;
|
||
|
||
//=== { TExprCallBinaryVmOp } ================================================
|
||
|
||
constructor TExprCallBinaryVmOp.Create(AFunc: TBinaryFunc; X, Y: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
FY := Y;
|
||
end;
|
||
|
||
procedure TExprCallBinaryVmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^, FY^);
|
||
end;
|
||
|
||
//=== { TExprCallBinary32VmOp } ==============================================
|
||
|
||
constructor TExprCallBinary32VmOp.Create(AFunc: TBinary32Func; X, Y: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
FY := Y;
|
||
end;
|
||
|
||
procedure TExprCallBinary32VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^, FY^);
|
||
end;
|
||
|
||
//=== { TExprCallBinary64VmOp } ==============================================
|
||
|
||
constructor TExprCallBinary64VmOp.Create(AFunc: TBinary64Func; X, Y: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
FY := Y;
|
||
end;
|
||
|
||
procedure TExprCallBinary64VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^, FY^);
|
||
end;
|
||
|
||
//=== { TExprCallBinary80VmOp } ==============================================
|
||
|
||
constructor TExprCallBinary80VmOp.Create(AFunc: TBinary80Func; X, Y: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
FY := Y;
|
||
end;
|
||
|
||
procedure TExprCallBinary80VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^, FY^);
|
||
end;
|
||
|
||
//=== { TExprCallTernaryVmOp } ===============================================
|
||
|
||
constructor TExprCallTernaryVmOp.Create(AFunc: TTernaryFunc; X, Y, Z: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
FY := Y;
|
||
FZ := Z;
|
||
end;
|
||
|
||
procedure TExprCallTernaryVmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^, FY^, FZ^);
|
||
end;
|
||
|
||
//=== { TExprCallTernary32VmOp } =============================================
|
||
|
||
constructor TExprCallTernary32VmOp.Create(AFunc: TTernary32Func; X, Y, Z: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
FY := Y;
|
||
FZ := Z;
|
||
end;
|
||
|
||
procedure TExprCallTernary32VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^, FY^, FZ^);
|
||
end;
|
||
|
||
//=== { TExprCallTernary64VmOp } =============================================
|
||
|
||
constructor TExprCallTernary64VmOp.Create(AFunc: TTernary64Func; X, Y, Z: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
FY := Y;
|
||
FZ := Z;
|
||
end;
|
||
|
||
procedure TExprCallTernary64VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^, FY^, FZ^);
|
||
end;
|
||
|
||
//=== { TExprCallTernary80VmOp } =============================================
|
||
|
||
constructor TExprCallTernary80VmOp.Create(AFunc: TTernary80Func; X, Y, Z: PFloat);
|
||
begin
|
||
inherited Create;
|
||
FFunc := AFunc;
|
||
FX := X;
|
||
FY := Y;
|
||
FZ := Z;
|
||
end;
|
||
|
||
procedure TExprCallTernary80VmOp.Execute;
|
||
begin
|
||
FOutput := FFunc(FX^, FY^, FZ^);
|
||
end;
|
||
|
||
{ End of virtual machine operators }
|
||
|
||
//=== { TExprVirtMach } ======================================================
|
||
|
||
constructor TExprVirtMach.Create;
|
||
begin
|
||
inherited Create;
|
||
FCodeList := TList.Create;
|
||
FConstList := TList.Create;
|
||
end;
|
||
|
||
destructor TExprVirtMach.Destroy;
|
||
begin
|
||
FreeObjectList(FCodeList);
|
||
FreeObjectList(FConstList);
|
||
inherited Destroy;
|
||
end;
|
||
|
||
function TExprVirtMach.Execute: TFloat;
|
||
type
|
||
PExprVirtMachOp = ^TExprVirtMachOp;
|
||
var
|
||
I: Integer;
|
||
pop: PExprVirtMachOp;
|
||
begin
|
||
if FCodeList.Count <> 0 then
|
||
begin
|
||
{ The code that follows is the same as this, but a lot faster
|
||
for I := 0 to FCodeList.Count - 1 do
|
||
TExprVirtMachOp(FCodeList[I]).Execute; }
|
||
I := FCodeList.Count;
|
||
pop := @FCodeList.List^[0];
|
||
while I > 0 do
|
||
begin
|
||
pop^.Execute;
|
||
Inc(pop);
|
||
Dec(I);
|
||
end;
|
||
Result := TExprVirtMachOp(FCodeList[FCodeList.Count - 1]).FOutput;
|
||
end
|
||
else
|
||
begin
|
||
if (FConstList.Count = 1) then
|
||
Result := TExprVirtMachOp(FConstList[0]).FOutput
|
||
else
|
||
Result := 0;
|
||
end;
|
||
end;
|
||
|
||
procedure TExprVirtMach.Add(AOp: TExprVirtMachOp);
|
||
begin
|
||
FCodeList.Add(AOp);
|
||
end;
|
||
|
||
procedure TExprVirtMach.AddConst(AOp: TExprVirtMachOp);
|
||
begin
|
||
FConstList.Add(AOp);
|
||
end;
|
||
|
||
procedure TExprVirtMach.Clear;
|
||
begin
|
||
ClearObjectList(FCodeList);
|
||
ClearObjectList(FConstList);
|
||
end;
|
||
|
||
//=== { TExprVirtMachNode } ==================================================
|
||
|
||
type
|
||
TExprVirtMachNode = class(TExprNode)
|
||
private
|
||
FExprVmCode: TExprVirtMachOp;
|
||
function GetVmDeps(AIndex: Integer): TExprVirtMachNode;
|
||
public
|
||
procedure GenCode(AVirtMach: TExprVirtMach); virtual; abstract;
|
||
|
||
property ExprVmCode: TExprVirtMachOp read FExprVmCode;
|
||
|
||
{ this property saves typecasting to access ExprVmCode }
|
||
property VmDeps[AIndex: Integer]: TExprVirtMachNode read GetVmDeps; default;
|
||
end;
|
||
|
||
function TExprVirtMachNode.GetVmDeps(AIndex: Integer): TExprVirtMachNode;
|
||
begin
|
||
Result := TExprVirtMachNode(FDepList[AIndex]);
|
||
end;
|
||
|
||
//=== Concrete expression nodes for virtual machine ==========================
|
||
|
||
type
|
||
TExprUnaryVmNode = class(TExprVirtMachNode)
|
||
private
|
||
FUnaryClass: TExprUnaryVmOpClass;
|
||
public
|
||
constructor Create(AUnaryClass: TExprUnaryVmOpClass;
|
||
const ADeps: array of TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprBinaryVmNode = class(TExprVirtMachNode)
|
||
private
|
||
FBinaryClass: TExprBinaryVmOpClass;
|
||
public
|
||
constructor Create(ABinaryClass: TExprBinaryVmOpClass;
|
||
const ADeps: array of TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprConstVmNode = class(TExprVirtMachNode)
|
||
private
|
||
FValue: TFloat;
|
||
public
|
||
constructor Create(AValue: TFloat);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprVar32VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FValue: PFloat32;
|
||
public
|
||
constructor Create(AValue: PFloat32);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprVar64VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FValue: PFloat64;
|
||
public
|
||
constructor Create(AValue: PFloat64);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprVar80VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FValue: PFloat80;
|
||
public
|
||
constructor Create(AValue: PFloat80);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallFloatVmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TFloatFunc;
|
||
public
|
||
constructor Create(AFunc: TFloatFunc);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallFloat32VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TFloat32Func;
|
||
public
|
||
constructor Create(AFunc: TFloat32Func);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallFloat64VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TFloat64Func;
|
||
public
|
||
constructor Create(AFunc: TFloat64Func);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallFloat80VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TFloat80Func;
|
||
public
|
||
constructor Create(AFunc: TFloat80Func);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallUnaryVmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TUnaryFunc;
|
||
public
|
||
constructor Create(AFunc: TUnaryFunc; X: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallUnary32VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TUnary32Func;
|
||
public
|
||
constructor Create(AFunc: TUnary32Func; X: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallUnary64VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TUnary64Func;
|
||
public
|
||
constructor Create(AFunc: TUnary64Func; X: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallUnary80VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TUnary80Func;
|
||
public
|
||
constructor Create(AFunc: TUnary80Func; X: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallBinaryVmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TBinaryFunc;
|
||
public
|
||
constructor Create(AFunc: TBinaryFunc; X, Y: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallBinary32VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TBinary32Func;
|
||
public
|
||
constructor Create(AFunc: TBinary32Func; X, Y: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallBinary64VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TBinary64Func;
|
||
public
|
||
constructor Create(AFunc: TBinary64Func; X, Y: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallBinary80VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TBinary80Func;
|
||
public
|
||
constructor Create(AFunc: TBinary80Func; X, Y: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallTernaryVmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TTernaryFunc;
|
||
public
|
||
constructor Create(AFunc: TTernaryFunc; X, Y, Z: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallTernary32VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TTernary32Func;
|
||
public
|
||
constructor Create(AFunc: TTernary32Func; X, Y, Z: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallTernary64VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TTernary64Func;
|
||
public
|
||
constructor Create(AFunc: TTernary64Func; X, Y, Z: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCallTernary80VmNode = class(TExprVirtMachNode)
|
||
private
|
||
FFunc: TTernary80Func;
|
||
public
|
||
constructor Create(AFunc: TTernary80Func; X, Y, Z: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
TExprCompareVmNode = class(TExprVirtMachNode)
|
||
public
|
||
constructor Create(ALeft, ARight: TExprNode);
|
||
procedure GenCode(AVirtMach: TExprVirtMach); override;
|
||
end;
|
||
|
||
//== { TExprUnaryVmNode } ====================================================
|
||
|
||
constructor TExprUnaryVmNode.Create(AUnaryClass: TExprUnaryVmOpClass; const ADeps: array of TExprNode);
|
||
begin
|
||
FUnaryClass := AUnaryClass;
|
||
inherited Create(ADeps);
|
||
Assert(FDepList.Count = 1);
|
||
end;
|
||
|
||
procedure TExprUnaryVmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := FUnaryClass.Create(VmDeps[0].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprBinaryVmNode } ==================================================
|
||
|
||
constructor TExprBinaryVmNode.Create(ABinaryClass: TExprBinaryVmOpClass; const ADeps: array of TExprNode);
|
||
begin
|
||
FBinaryClass := ABinaryClass;
|
||
inherited Create(ADeps);
|
||
Assert(FDepList.Count = 2);
|
||
end;
|
||
|
||
procedure TExprBinaryVmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := FBinaryClass.Create(
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprConstVmNode } ==================================================
|
||
|
||
constructor TExprConstVmNode.Create(AValue: TFloat);
|
||
begin
|
||
FValue := AValue;
|
||
inherited Create([]);
|
||
end;
|
||
|
||
procedure TExprConstVmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprConstVmOp.Create(FValue);
|
||
AVirtMach.AddConst(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprVar32VmNode } ===================================================
|
||
|
||
constructor TExprVar32VmNode.Create(AValue: PFloat32);
|
||
begin
|
||
FValue := AValue;
|
||
inherited Create([]);
|
||
end;
|
||
|
||
procedure TExprVar32VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprVar32VmOp.Create(FValue);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprVar64VmNode } ===================================================
|
||
|
||
constructor TExprVar64VmNode.Create(AValue: PFloat64);
|
||
begin
|
||
FValue := AValue;
|
||
inherited Create([]);
|
||
end;
|
||
|
||
procedure TExprVar64VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprVar64VmOp.Create(FValue);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprVar80VmNode } ===================================================
|
||
|
||
constructor TExprVar80VmNode.Create(AValue: PFloat80);
|
||
begin
|
||
FValue := AValue;
|
||
inherited Create([]);
|
||
end;
|
||
|
||
procedure TExprVar80VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprVar80VmOp.Create(FValue);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
{ End of expression nodes for virtual machine }
|
||
|
||
//=== { TExprVirtMachNodeFactory } ===========================================
|
||
|
||
constructor TExprVirtMachNodeFactory.Create;
|
||
begin
|
||
inherited Create;
|
||
FNodeList := TList.Create;
|
||
end;
|
||
|
||
destructor TExprVirtMachNodeFactory.Destroy;
|
||
begin
|
||
FreeObjectList(FNodeList);
|
||
inherited Destroy;
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.AddNode(ANode: TExprNode): TExprNode;
|
||
begin
|
||
Result := ANode;
|
||
FNodeList.Add(ANode);
|
||
end;
|
||
|
||
procedure TExprVirtMachNodeFactory.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
{ TODO : optimize the expression tree into a DAG (i.e. find CSEs) and
|
||
evaluate constant subexpressions, implement strength reduction, etc. }
|
||
|
||
{ TODO : move optimization logic (as far as possible) into ancestor classes
|
||
once tested and interfaces are solid, so that other evaluation strategies
|
||
can take advantage of these optimizations. }
|
||
|
||
DoClean(AVirtMach);
|
||
DoConsts(AVirtMach);
|
||
DoCode(AVirtMach);
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.LoadVar32(ALoc: PFloat32): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprVar32VmNode.Create(ALoc));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.LoadVar64(ALoc: PFloat64): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprVar64VmNode.Create(ALoc));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.LoadVar80(ALoc: PFloat80): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprVar80VmNode.Create(ALoc));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.LoadConst32(AValue: TFloat32): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprConstVmNode.Create(AValue));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.LoadConst64(AValue: TFloat64): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprConstVmNode.Create(AValue));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.LoadConst80(AValue: TFloat80): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprConstVmNode.Create(AValue));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.Add(ALeft, ARight: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprBinaryVmNode.Create(TExprAddVmOp, [ALeft, ARight]));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.Subtract(ALeft, ARight: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprBinaryVmNode.Create(TExprSubtractVmOp, [ALeft, ARight]));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.Multiply(ALeft, ARight: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprBinaryVmNode.Create(TExprMultiplyVmOp, [ALeft, ARight]));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.Divide(ALeft, ARight: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprBinaryVmNode.Create(TExprDivideVmOp, [ALeft, ARight]));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.Negate(AValue: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprUnaryVmNode.Create(TExprNegateVmOp, [AValue]));
|
||
end;
|
||
|
||
procedure TExprVirtMachNodeFactory.DoClean(AVirtMach: TExprVirtMach);
|
||
var
|
||
I: Integer;
|
||
begin
|
||
{ clean up in preparation for code generation }
|
||
AVirtMach.Clear;
|
||
for I := 0 to FNodeList.Count - 1 do
|
||
TExprVirtMachNode(FNodeList[I]).FExprVmCode := nil;
|
||
end;
|
||
|
||
procedure TExprVirtMachNodeFactory.DoConsts(AVirtMach: TExprVirtMach);
|
||
var
|
||
I: Integer;
|
||
Node: TExprVirtMachNode;
|
||
begin
|
||
{ process consts }
|
||
for I := 0 to FNodeList.Count - 1 do
|
||
begin
|
||
Node := TExprVirtMachNode(FNodeList[I]);
|
||
if (Node is TExprConstVmNode) and (Node.ExprVmCode = nil) then
|
||
Node.GenCode(AVirtMach);
|
||
end;
|
||
end;
|
||
|
||
procedure TExprVirtMachNodeFactory.DoCode(AVirtMach: TExprVirtMach);
|
||
var
|
||
I: Integer;
|
||
Node: TExprVirtMachNode;
|
||
begin
|
||
{ process code }
|
||
for I := 0 to FNodeList.Count - 1 do
|
||
begin
|
||
Node := TExprVirtMachNode(FNodeList[I]);
|
||
if Node.ExprVmCode = nil then
|
||
Node.GenCode(AVirtMach);
|
||
end;
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallFloatFunc(AFunc: TFloatFunc): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallFloatVmNode.Create(AFunc));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallFloat32Func(AFunc: TFloat32Func): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallFloat32VmNode.Create(AFunc));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallFloat64Func(AFunc: TFloat64Func): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallFloat64VmNode.Create(AFunc));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallFloat80Func(AFunc: TFloat80Func): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallFloat80VmNode.Create(AFunc));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallUnaryFunc(AFunc: TUnaryFunc; X: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallUnaryVmNode.Create(AFunc, X));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallUnary32Func(AFunc: TUnary32Func; X: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallUnary32VmNode.Create(AFunc, X));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallUnary64Func(AFunc: TUnary64Func; X: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallUnary64VmNode.Create(AFunc, X));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallUnary80Func(AFunc: TUnary80Func; X: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallUnary80VmNode.Create(AFunc, X));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallBinaryFunc(AFunc: TBinaryFunc; X, Y: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallBinaryVmNode.Create(AFunc, X, Y));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallBinary32Func(AFunc: TBinary32Func; X, Y: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallBinary32VmNode.Create(AFunc, X, Y));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallBinary64Func(AFunc: TBinary64Func; X, Y: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallBinary64VmNode.Create(AFunc, X, Y));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallBinary80Func(AFunc: TBinary80Func; X, Y: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallBinary80VmNode.Create(AFunc, X, Y));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallTernaryFunc(AFunc: TTernaryFunc; X, Y, Z: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallTernaryVmNode.Create(AFunc, X, Y, Z));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallTernary32Func(AFunc: TTernary32Func; X, Y, Z: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallTernary32VmNode.Create(AFunc, X, Y, Z));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallTernary64Func(AFunc: TTernary64Func; X, Y, Z: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallTernary64VmNode.Create(AFunc, X, Y, Z));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.CallTernary80Func(AFunc: TTernary80Func; X, Y, Z: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCallTernary80VmNode.Create(AFunc, X, Y, Z));
|
||
end;
|
||
|
||
function TExprVirtMachNodeFactory.Compare(ALeft, ARight: TExprNode): TExprNode;
|
||
begin
|
||
Result := AddNode(TExprCompareVmNode.Create(ALeft, ARight));
|
||
end;
|
||
|
||
//=== { TCompiledEvaluator } =================================================
|
||
|
||
constructor TCompiledEvaluator.Create;
|
||
begin
|
||
inherited Create;
|
||
FVirtMach := TExprVirtMach.Create;
|
||
end;
|
||
|
||
destructor TCompiledEvaluator.Destroy;
|
||
begin
|
||
FVirtMach.Free;
|
||
inherited Destroy;
|
||
end;
|
||
|
||
procedure TCompiledEvaluator.Compile(const AExpr: string);
|
||
var
|
||
Lex: TExprSimpleLexer;
|
||
Parse: TExprCompileParser;
|
||
NodeFactory: TExprVirtMachNodeFactory;
|
||
begin
|
||
if AExpr <> FExpr then
|
||
begin
|
||
FExpr := AExpr;
|
||
FVirtMach.Clear;
|
||
|
||
Parse := nil;
|
||
NodeFactory := nil;
|
||
Lex := TExprSimpleLexer.Create(FExpr);
|
||
try
|
||
NodeFactory := TExprVirtMachNodeFactory.Create;
|
||
Parse := TExprCompileParser.Create(Lex, NodeFactory);
|
||
Parse.Context := InternalContextSet;
|
||
Parse.Compile;
|
||
NodeFactory.GenCode(FVirtMach);
|
||
finally
|
||
Parse.Free;
|
||
NodeFactory.Free;
|
||
Lex.Free;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function TCompiledEvaluator.Evaluate: TFloat;
|
||
begin
|
||
Result := FVirtMach.Execute;
|
||
end;
|
||
|
||
//=== { TExprVar32Sym } ======================================================
|
||
|
||
constructor TExprVar32Sym.Create(const AIdent: string; ALoc: PFloat32);
|
||
begin
|
||
Assert(ALoc <> nil);
|
||
FLoc := ALoc;
|
||
inherited Create(AIdent);
|
||
end;
|
||
|
||
function TExprVar32Sym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.LoadVar32(FLoc);
|
||
end;
|
||
|
||
function TExprVar32Sym.Evaluate: TFloat;
|
||
begin
|
||
Result := FLoc^;
|
||
end;
|
||
|
||
//=== { TExprVar64Sym } ======================================================
|
||
|
||
constructor TExprVar64Sym.Create(const AIdent: string; ALoc: PFloat64);
|
||
begin
|
||
Assert(ALoc <> nil);
|
||
FLoc := ALoc;
|
||
inherited Create(AIdent);
|
||
end;
|
||
|
||
function TExprVar64Sym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.LoadVar64(FLoc);
|
||
end;
|
||
|
||
function TExprVar64Sym.Evaluate: TFloat;
|
||
begin
|
||
Result := FLoc^;
|
||
end;
|
||
|
||
//=== { TExprVar80Sym } ======================================================
|
||
|
||
constructor TExprVar80Sym.Create(const AIdent: string; ALoc: PFloat80);
|
||
begin
|
||
Assert(ALoc <> nil);
|
||
FLoc := ALoc;
|
||
inherited Create(AIdent);
|
||
end;
|
||
|
||
function TExprVar80Sym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.LoadVar80(FLoc);
|
||
end;
|
||
|
||
function TExprVar80Sym.Evaluate: TFloat;
|
||
begin
|
||
Result := FLoc^;
|
||
end;
|
||
|
||
//=== { TExprCallFloatVmNode } ===============================================
|
||
|
||
constructor TExprCallFloatVmNode.Create(AFunc: TFloatFunc);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([]);
|
||
end;
|
||
|
||
procedure TExprCallFloatVmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallFloatVmOp.Create(FFunc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallFloat32VmNode } =============================================
|
||
|
||
constructor TExprCallFloat32VmNode.Create(AFunc: TFloat32Func);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([]);
|
||
end;
|
||
|
||
procedure TExprCallFloat32VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallFloat32VmOp.Create(FFunc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallFloat64VmNode } =============================================
|
||
|
||
constructor TExprCallFloat64VmNode.Create(AFunc: TFloat64Func);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([]);
|
||
end;
|
||
|
||
procedure TExprCallFloat64VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallFloat64VmOp.Create(FFunc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallFloat80VmNode } =============================================
|
||
|
||
constructor TExprCallFloat80VmNode.Create(AFunc: TFloat80Func);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([]);
|
||
end;
|
||
|
||
procedure TExprCallFloat80VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallFloat80VmOp.Create(FFunc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallUnaryVmNode } ===============================================
|
||
|
||
constructor TExprCallUnaryVmNode.Create(AFunc: TUnaryFunc; X: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X]);
|
||
end;
|
||
|
||
procedure TExprCallUnaryVmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallUnaryVmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallUnary32VmNode } =============================================
|
||
|
||
constructor TExprCallUnary32VmNode.Create(AFunc: TUnary32Func; X: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X]);
|
||
end;
|
||
|
||
procedure TExprCallUnary32VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallUnary32VmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallUnary64VmNode } =============================================
|
||
|
||
constructor TExprCallUnary64VmNode.Create(AFunc: TUnary64Func; X: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X]);
|
||
end;
|
||
|
||
procedure TExprCallUnary64VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallUnary64VmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallUnary80VmNode } =============================================
|
||
|
||
constructor TExprCallUnary80VmNode.Create(AFunc: TUnary80Func; X: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X]);
|
||
end;
|
||
|
||
procedure TExprCallUnary80VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallUnary80VmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallBinaryVmNode } ==============================================
|
||
|
||
constructor TExprCallBinaryVmNode.Create(AFunc: TBinaryFunc; X, Y: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X, Y]);
|
||
end;
|
||
|
||
procedure TExprCallBinaryVmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallBinaryVmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallBinary32VmNode } ============================================
|
||
|
||
constructor TExprCallBinary32VmNode.Create(AFunc: TBinary32Func; X, Y: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X, Y]);
|
||
end;
|
||
|
||
procedure TExprCallBinary32VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallBinary32VmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallBinary64VmNode } ============================================
|
||
|
||
constructor TExprCallBinary64VmNode.Create(AFunc: TBinary64Func; X, Y: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X, Y]);
|
||
end;
|
||
|
||
procedure TExprCallBinary64VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallBinary64VmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallBinary80VmNode } ============================================
|
||
|
||
constructor TExprCallBinary80VmNode.Create(AFunc: TBinary80Func; X, Y: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X, Y]);
|
||
end;
|
||
|
||
procedure TExprCallBinary80VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallBinary80VmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallTernaryVmNode } =============================================
|
||
|
||
constructor TExprCallTernaryVmNode.Create(AFunc: TTernaryFunc; X, Y, Z: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X, Y, Z]);
|
||
end;
|
||
|
||
procedure TExprCallTernaryVmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallTernaryVmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc,
|
||
VmDeps[2].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallTernary32VmNode } ===========================================
|
||
|
||
constructor TExprCallTernary32VmNode.Create(AFunc: TTernary32Func; X, Y, Z: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X, Y, Z]);
|
||
end;
|
||
|
||
procedure TExprCallTernary32VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallTernary32VmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc,
|
||
VmDeps[2].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallTernary64VmNode } ===========================================
|
||
|
||
constructor TExprCallTernary64VmNode.Create(AFunc: TTernary64Func; X, Y, Z: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X, Y, Z]);
|
||
end;
|
||
|
||
procedure TExprCallTernary64VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallTernary64VmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc,
|
||
VmDeps[2].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCallTernary80VmNode } ===========================================
|
||
|
||
constructor TExprCallTernary80VmNode.Create(AFunc: TTernary80Func; X, Y, Z: TExprNode);
|
||
begin
|
||
FFunc := AFunc;
|
||
inherited Create([X, Y, Z]);
|
||
end;
|
||
|
||
procedure TExprCallTernary80VmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCallTernary80VmOp.Create(
|
||
FFunc,
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc,
|
||
VmDeps[2].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprCompareVmNode } =================================================
|
||
|
||
constructor TExprCompareVmNode.Create(ALeft, ARight: TExprNode);
|
||
begin
|
||
inherited Create([ALeft, ARight]);
|
||
end;
|
||
|
||
procedure TExprCompareVmNode.GenCode(AVirtMach: TExprVirtMach);
|
||
begin
|
||
FExprVmCode := TExprCompareVmOp.Create(
|
||
VmDeps[0].ExprVmCode.OutputLoc,
|
||
VmDeps[1].ExprVmCode.OutputLoc);
|
||
AVirtMach.Add(FExprVmCode);
|
||
end;
|
||
|
||
//=== { TExprAbstractFuncSym } ===============================================
|
||
|
||
function TExprAbstractFuncSym.CompileFirstArg: TExprNode;
|
||
begin
|
||
if Lexer.CurrTok <> etLParen then
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalFirstArg);
|
||
Result := CompileParser.CompileExpr(True);
|
||
end;
|
||
|
||
function TExprAbstractFuncSym.CompileNextArg: TExprNode;
|
||
begin
|
||
if Lexer.CurrTok <> etComma then
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalNextArg);
|
||
Result := CompileParser.CompileExpr(True);
|
||
end;
|
||
|
||
function TExprAbstractFuncSym.EvalFirstArg: TFloat;
|
||
begin
|
||
if Lexer.CurrTok <> etLParen then
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalFirstArg);
|
||
Result := EvalParser.EvalExpr(True);
|
||
end;
|
||
|
||
function TExprAbstractFuncSym.EvalNextArg: TFloat;
|
||
begin
|
||
if Lexer.CurrTok <> etComma then
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalNextArg);
|
||
Result := EvalParser.EvalExpr(True);
|
||
end;
|
||
|
||
procedure TExprAbstractFuncSym.EndArgs;
|
||
begin
|
||
if Lexer.CurrTok <> etRParen then
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalEndArgs);
|
||
Lexer.NextTok;
|
||
end;
|
||
|
||
//=== { TExprFuncSym } =======================================================
|
||
|
||
constructor TExprFuncSym.Create(const AIdent: string; AFunc: TFloatFunc);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprFuncSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.CallFloatFunc(FFunc);
|
||
end;
|
||
|
||
function TExprFuncSym.Evaluate: TFloat;
|
||
begin
|
||
Result := FFunc;
|
||
end;
|
||
|
||
//=== { TExprFloat32FuncSym } ================================================
|
||
|
||
constructor TExprFloat32FuncSym.Create(const AIdent: string; AFunc: TFloat32Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprFloat32FuncSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.CallFloat32Func(FFunc);
|
||
end;
|
||
|
||
function TExprFloat32FuncSym.Evaluate: TFloat;
|
||
begin
|
||
Result := FFunc;
|
||
end;
|
||
|
||
//=== { TExprFloat64FuncSym } ================================================
|
||
|
||
constructor TExprFloat64FuncSym.Create(const AIdent: string; AFunc: TFloat64Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprFloat64FuncSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.CallFloat64Func(FFunc);
|
||
end;
|
||
|
||
function TExprFloat64FuncSym.Evaluate: TFloat;
|
||
begin
|
||
Result := FFunc;
|
||
end;
|
||
|
||
//=== { TExprFloat80FuncSym } ================================================
|
||
|
||
constructor TExprFloat80FuncSym.Create(const AIdent: string; AFunc: TFloat80Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprFloat80FuncSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.CallFloat80Func(FFunc);
|
||
end;
|
||
|
||
function TExprFloat80FuncSym.Evaluate: TFloat;
|
||
begin
|
||
Result := FFunc;
|
||
end;
|
||
|
||
//=== { TExprUnaryFuncSym } ==================================================
|
||
|
||
constructor TExprUnaryFuncSym.Create(const AIdent: string; AFunc: TUnaryFunc);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprUnaryFuncSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.CallUnaryFunc(FFunc, CompileFirstArg);
|
||
EndArgs;
|
||
end;
|
||
|
||
function TExprUnaryFuncSym.Evaluate: TFloat;
|
||
begin
|
||
Result := FFunc(EvalFirstArg);
|
||
EndArgs;
|
||
end;
|
||
|
||
//=== { TExprUnary32FuncSym } ================================================
|
||
|
||
constructor TExprUnary32FuncSym.Create(const AIdent: string; AFunc: TUnary32Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprUnary32FuncSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.CallUnary32Func(FFunc, CompileFirstArg);
|
||
EndArgs;
|
||
end;
|
||
|
||
function TExprUnary32FuncSym.Evaluate: TFloat;
|
||
begin
|
||
Result := FFunc(EvalFirstArg);
|
||
EndArgs;
|
||
end;
|
||
|
||
//=== { TExprUnary64FuncSym } ================================================
|
||
|
||
constructor TExprUnary64FuncSym.Create(const AIdent: string; AFunc: TUnary64Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprUnary64FuncSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.CallUnary64Func(FFunc, CompileFirstArg);
|
||
EndArgs;
|
||
end;
|
||
|
||
function TExprUnary64FuncSym.Evaluate: TFloat;
|
||
begin
|
||
Result := FFunc(EvalFirstArg);
|
||
EndArgs;
|
||
end;
|
||
|
||
//=== { TExprUnary80FuncSym } ================================================
|
||
|
||
constructor TExprUnary80FuncSym.Create(const AIdent: string; AFunc: TUnary80Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprUnary80FuncSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.CallUnary80Func(FFunc, CompileFirstArg);
|
||
EndArgs;
|
||
end;
|
||
|
||
function TExprUnary80FuncSym.Evaluate: TFloat;
|
||
begin
|
||
Result := FFunc(EvalFirstArg);
|
||
EndArgs;
|
||
end;
|
||
|
||
//=== { TExprBinaryFuncSym } =================================================
|
||
|
||
constructor TExprBinaryFuncSym.Create(const AIdent: string; AFunc: TBinaryFunc);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprBinaryFuncSym.Compile: TExprNode;
|
||
var
|
||
X, Y: TExprNode;
|
||
begin
|
||
// must be called this way, because evaluation order of function
|
||
// parameters is not defined; we need CompileFirstArg to be called
|
||
// first.
|
||
X := CompileFirstArg;
|
||
Y := CompileNextArg;
|
||
EndArgs;
|
||
Result := NodeFactory.CallBinaryFunc(FFunc, X, Y);
|
||
end;
|
||
|
||
function TExprBinaryFuncSym.Evaluate: TFloat;
|
||
var
|
||
X, Y: TFloat;
|
||
begin
|
||
X := EvalFirstArg;
|
||
Y := EvalNextArg;
|
||
Result := FFunc(X, Y);
|
||
EndArgs;
|
||
end;
|
||
|
||
//=== { TExprBinary32FuncSym } ===============================================
|
||
|
||
constructor TExprBinary32FuncSym.Create(const AIdent: string; AFunc: TBinary32Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprBinary32FuncSym.Compile: TExprNode;
|
||
var
|
||
X, Y: TExprNode;
|
||
begin
|
||
X := CompileFirstArg;
|
||
Y := CompileNextArg;
|
||
EndArgs;
|
||
Result := NodeFactory.CallBinary32Func(FFunc, X, Y);
|
||
end;
|
||
|
||
function TExprBinary32FuncSym.Evaluate: TFloat;
|
||
var
|
||
X, Y: TFloat;
|
||
begin
|
||
X := EvalFirstArg;
|
||
Y := EvalNextArg;
|
||
EndArgs;
|
||
Result := FFunc(X, Y);
|
||
end;
|
||
|
||
//=== { TExprBinary64FuncSym } ===============================================
|
||
|
||
constructor TExprBinary64FuncSym.Create(const AIdent: string; AFunc: TBinary64Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprBinary64FuncSym.Compile: TExprNode;
|
||
var
|
||
X, Y: TExprNode;
|
||
begin
|
||
X := CompileFirstArg;
|
||
Y := CompileNextArg;
|
||
EndArgs;
|
||
Result := NodeFactory.CallBinary64Func(FFunc, X, Y);
|
||
end;
|
||
|
||
function TExprBinary64FuncSym.Evaluate: TFloat;
|
||
var
|
||
X, Y: TFloat;
|
||
begin
|
||
X := EvalFirstArg;
|
||
Y := EvalNextArg;
|
||
EndArgs;
|
||
Result := FFunc(X, Y);
|
||
end;
|
||
|
||
//=== { TExprBinary80FuncSym } ===============================================
|
||
|
||
constructor TExprBinary80FuncSym.Create(const AIdent: string; AFunc: TBinary80Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprBinary80FuncSym.Compile: TExprNode;
|
||
var
|
||
X, Y: TExprNode;
|
||
begin
|
||
X := CompileFirstArg;
|
||
Y := CompileNextArg;
|
||
EndArgs;
|
||
Result := NodeFactory.CallBinary80Func(FFunc, X, Y);
|
||
end;
|
||
|
||
function TExprBinary80FuncSym.Evaluate: TFloat;
|
||
var
|
||
X, Y: TFloat;
|
||
begin
|
||
X := EvalFirstArg;
|
||
Y := EvalNextArg;
|
||
EndArgs;
|
||
Result := FFunc(X, Y);
|
||
end;
|
||
|
||
//=== { TExprTernaryFuncSym } ================================================
|
||
|
||
constructor TExprTernaryFuncSym.Create(const AIdent: string; AFunc: TTernaryFunc);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprTernaryFuncSym.Compile: TExprNode;
|
||
var
|
||
X, Y, Z: TExprNode;
|
||
begin
|
||
X := CompileFirstArg;
|
||
Y := CompileNextArg;
|
||
Z := CompileNextArg;
|
||
EndArgs;
|
||
Result := NodeFactory.CallTernaryFunc(FFunc, X, Y, Z);
|
||
end;
|
||
|
||
function TExprTernaryFuncSym.Evaluate: TFloat;
|
||
var
|
||
X, Y, Z: TFloat;
|
||
begin
|
||
X := EvalFirstArg;
|
||
Y := EvalNextArg;
|
||
Z := EvalNextArg;
|
||
EndArgs;
|
||
Result := FFunc(X, Y, Z);
|
||
end;
|
||
|
||
//=== { TExprTernary32FuncSym } ==============================================
|
||
|
||
constructor TExprTernary32FuncSym.Create(const AIdent: string; AFunc: TTernary32Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprTernary32FuncSym.Compile: TExprNode;
|
||
var
|
||
X, Y, Z: TExprNode;
|
||
begin
|
||
X := CompileFirstArg;
|
||
Y := CompileNextArg;
|
||
Z := CompileNextArg;
|
||
EndArgs;
|
||
Result := NodeFactory.CallTernary32Func(FFunc, X, Y, Z);
|
||
end;
|
||
|
||
function TExprTernary32FuncSym.Evaluate: TFloat;
|
||
var
|
||
X, Y, Z: TFloat;
|
||
begin
|
||
X := EvalFirstArg;
|
||
Y := EvalNextArg;
|
||
Z := EvalNextArg;
|
||
EndArgs;
|
||
Result := FFunc(X, Y, Z);
|
||
end;
|
||
|
||
//=== { TExprTernary64FuncSym } ==============================================
|
||
|
||
constructor TExprTernary64FuncSym.Create(const AIdent: string; AFunc: TTernary64Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprTernary64FuncSym.Compile: TExprNode;
|
||
var
|
||
X, Y, Z: TExprNode;
|
||
begin
|
||
X := CompileFirstArg;
|
||
Y := CompileNextArg;
|
||
Z := CompileNextArg;
|
||
EndArgs;
|
||
Result := NodeFactory.CallTernary64Func(FFunc, X, Y, Z);
|
||
end;
|
||
|
||
function TExprTernary64FuncSym.Evaluate: TFloat;
|
||
var
|
||
X, Y, Z: TFloat;
|
||
begin
|
||
X := EvalFirstArg;
|
||
Y := EvalNextArg;
|
||
Z := EvalNextArg;
|
||
EndArgs;
|
||
Result := FFunc(X, Y, Z);
|
||
end;
|
||
|
||
//=== { TExprTernary80FuncSym } ==============================================
|
||
|
||
constructor TExprTernary80FuncSym.Create(const AIdent: string; AFunc: TTernary80Func);
|
||
begin
|
||
Assert(Assigned(AFunc));
|
||
inherited Create(AIdent);
|
||
FFunc := AFunc;
|
||
end;
|
||
|
||
function TExprTernary80FuncSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.CallTernary80Func(FFunc, CompileFirstArg,
|
||
CompileNextArg, CompileNextArg);
|
||
EndArgs;
|
||
end;
|
||
|
||
function TExprTernary80FuncSym.Evaluate: TFloat;
|
||
var
|
||
X, Y, Z: TFloat;
|
||
begin
|
||
X := EvalFirstArg;
|
||
Y := EvalNextArg;
|
||
Z := EvalNextArg;
|
||
EndArgs;
|
||
Result := FFunc(X, Y, Z);
|
||
end;
|
||
|
||
//=== { TExprConstSym } ======================================================
|
||
|
||
constructor TExprConstSym.Create(const AIdent: string; AValue: TFloat);
|
||
begin
|
||
inherited Create(AIdent);
|
||
FValue := AValue;
|
||
end;
|
||
|
||
function TExprConstSym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.LoadConst(FValue);
|
||
end;
|
||
|
||
function TExprConstSym.Evaluate: TFloat;
|
||
begin
|
||
Result := FValue;
|
||
end;
|
||
|
||
//=== { TExprConst32Sym } ====================================================
|
||
|
||
constructor TExprConst32Sym.Create(const AIdent: string; AValue: TFloat32);
|
||
begin
|
||
inherited Create(AIdent);
|
||
FValue := AValue;
|
||
end;
|
||
|
||
function TExprConst32Sym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.LoadConst(FValue);
|
||
end;
|
||
|
||
function TExprConst32Sym.Evaluate: TFloat;
|
||
begin
|
||
Result := FValue;
|
||
end;
|
||
|
||
//=== { TExprConst64Sym } ====================================================
|
||
|
||
constructor TExprConst64Sym.Create(const AIdent: string; AValue: TFloat64);
|
||
begin
|
||
inherited Create(AIdent);
|
||
FValue := AValue;
|
||
end;
|
||
|
||
function TExprConst64Sym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.LoadConst(FValue);
|
||
end;
|
||
|
||
function TExprConst64Sym.Evaluate: TFloat;
|
||
begin
|
||
Result := FValue;
|
||
end;
|
||
|
||
//=== { TExprConst80Sym } ====================================================
|
||
|
||
constructor TExprConst80Sym.Create(const AIdent: string; AValue: TFloat80);
|
||
begin
|
||
inherited Create(AIdent);
|
||
FValue := AValue;
|
||
end;
|
||
|
||
function TExprConst80Sym.Compile: TExprNode;
|
||
begin
|
||
Result := NodeFactory.LoadConst(FValue);
|
||
end;
|
||
|
||
function TExprConst80Sym.Evaluate: TFloat;
|
||
begin
|
||
Result := FValue;
|
||
end;
|
||
|
||
//=== { TEasyEvaluator } =====================================================
|
||
|
||
constructor TEasyEvaluator.Create;
|
||
begin
|
||
inherited Create;
|
||
FOwnContext := TExprHashContext.Create(False, cExprEvalHashSize);
|
||
FExtContextSet := TExprSetContext.Create(False);
|
||
FInternalContextSet := TExprSetContext.Create(False);
|
||
|
||
// user added names get precedence over external context's names
|
||
FInternalContextSet.Add(FExtContextSet);
|
||
FInternalContextSet.Add(FOwnContext);
|
||
end;
|
||
|
||
destructor TEasyEvaluator.Destroy;
|
||
begin
|
||
FInternalContextSet.Free;
|
||
FOwnContext.Free;
|
||
FExtContextSet.Free;
|
||
inherited Destroy;
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddConst(const AName: string; AConst: TFloat80);
|
||
begin
|
||
FOwnContext.Add(TExprConst80Sym.Create(AName, AConst));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddConst(const AName: string; AConst: TFloat64);
|
||
begin
|
||
FOwnContext.Add(TExprConst64Sym.Create(AName, AConst));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddConst(const AName: string; AConst: TFloat32);
|
||
begin
|
||
FOwnContext.Add(TExprConst32Sym.Create(AName, AConst));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddVar(const AName: string; var AVar: TFloat32);
|
||
begin
|
||
FOwnContext.Add(TExprVar32Sym.Create(AName, @AVar));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddVar(const AName: string; var AVar: TFloat64);
|
||
begin
|
||
FOwnContext.Add(TExprVar64Sym.Create(AName, @AVar));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddVar(const AName: string; var AVar: TFloat80);
|
||
begin
|
||
FOwnContext.Add(TExprVar80Sym.Create(AName, @AVar));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TFloat32Func);
|
||
begin
|
||
FOwnContext.Add(TExprFloat32FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TFloat64Func);
|
||
begin
|
||
FOwnContext.Add(TExprFloat64FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TFloat80Func);
|
||
begin
|
||
FOwnContext.Add(TExprFloat80FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TUnary32Func);
|
||
begin
|
||
FOwnContext.Add(TExprUnary32FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TUnary64Func);
|
||
begin
|
||
FOwnContext.Add(TExprUnary64FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TUnary80Func);
|
||
begin
|
||
FOwnContext.Add(TExprUnary80FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TBinary32Func);
|
||
begin
|
||
FOwnContext.Add(TExprBinary32FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TBinary64Func);
|
||
begin
|
||
FOwnContext.Add(TExprBinary64FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TBinary80Func);
|
||
begin
|
||
FOwnContext.Add(TExprBinary80FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TTernary32Func);
|
||
begin
|
||
FOwnContext.Add(TExprTernary32FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TTernary64Func);
|
||
begin
|
||
FOwnContext.Add(TExprTernary64FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.AddFunc(const AName: string; AFunc: TTernary80Func);
|
||
begin
|
||
FOwnContext.Add(TExprTernary80FuncSym.Create(AName, AFunc));
|
||
end;
|
||
|
||
procedure TEasyEvaluator.Clear;
|
||
begin
|
||
FOwnContext.FHashMap.Iterate(nil, Iterate_FreeObjects);
|
||
FOwnContext.FHashMap.Clear;
|
||
end;
|
||
|
||
procedure TEasyEvaluator.Remove(const AName: string);
|
||
begin
|
||
FOwnContext.Remove(AName);
|
||
end;
|
||
|
||
//=== { TInternalCompiledExpression } ========================================
|
||
|
||
type
|
||
TInternalCompiledExpression = class(TObject)
|
||
private
|
||
FVirtMach: TExprVirtMach;
|
||
FRefCount: Integer;
|
||
public
|
||
constructor Create(AVirtMach: TExprVirtMach);
|
||
destructor Destroy; override;
|
||
property VirtMach: TExprVirtMach read FVirtMach;
|
||
property RefCount: Integer read FRefCount write FRefCount;
|
||
end;
|
||
|
||
constructor TInternalCompiledExpression.Create(AVirtMach: TExprVirtMach);
|
||
begin
|
||
inherited Create;
|
||
FVirtMach := AVirtMach;
|
||
end;
|
||
|
||
destructor TInternalCompiledExpression.Destroy;
|
||
begin
|
||
FVirtMach.Free;
|
||
inherited Destroy;
|
||
end;
|
||
|
||
//=== { TExpressionCompiler } ================================================
|
||
|
||
constructor TExpressionCompiler.Create;
|
||
begin
|
||
FExprHash := TStringHashMap.Create(CaseInsensitiveTraits,
|
||
cExprEvalHashSize);
|
||
inherited Create;
|
||
end;
|
||
|
||
destructor TExpressionCompiler.Destroy;
|
||
begin
|
||
FExprHash.Iterate(nil, Iterate_FreeObjects);
|
||
FExprHash.Free;
|
||
inherited Destroy;
|
||
end;
|
||
|
||
function TExpressionCompiler.Compile(const AExpr: string): TCompiledExpression;
|
||
var
|
||
Ice: TInternalCompiledExpression;
|
||
Vm: TExprVirtMach;
|
||
Parser: TExprCompileParser;
|
||
Lexer: TExprSimpleLexer;
|
||
NodeFactory: TExprVirtMachNodeFactory;
|
||
begin
|
||
if FExprHash.Find(AExpr, Ice) then
|
||
begin
|
||
// expression already exists, add reference
|
||
Result := Ice.VirtMach.Execute;
|
||
Ice.RefCount := Ice.RefCount + 1;
|
||
end
|
||
else
|
||
begin
|
||
// compile fresh expression
|
||
Parser := nil;
|
||
NodeFactory := nil;
|
||
Lexer := TExprSimpleLexer.Create(AExpr);
|
||
try
|
||
NodeFactory := TExprVirtMachNodeFactory.Create;
|
||
Parser := TExprCompileParser.Create(Lexer, NodeFactory);
|
||
Parser.Context := InternalContextSet;
|
||
Parser.Compile;
|
||
|
||
Ice := nil;
|
||
Vm := TExprVirtMach.Create;
|
||
try
|
||
NodeFactory.GenCode(Vm);
|
||
Ice := TInternalCompiledExpression.Create(Vm);
|
||
Ice.RefCount := 1;
|
||
FExprHash.Add(AExpr, Ice);
|
||
except
|
||
Ice.Free;
|
||
Vm.Free;
|
||
raise;
|
||
end;
|
||
finally
|
||
NodeFactory.Free;
|
||
Parser.Free;
|
||
Lexer.Free;
|
||
end;
|
||
|
||
Result := Ice.VirtMach.Execute;
|
||
end;
|
||
end;
|
||
|
||
type
|
||
PIceFindResult = ^TIceFindResult;
|
||
TIceFindResult = record
|
||
Found: Boolean;
|
||
Ce: TCompiledExpression;
|
||
Ice: TInternalCompiledExpression;
|
||
Expr: string;
|
||
end;
|
||
|
||
function IterateFindIce(AUserData: Pointer; const AStr: string; var APtr: Pointer): Boolean;
|
||
var
|
||
PIfr: PIceFindResult;
|
||
Ice: TInternalCompiledExpression;
|
||
Ce: TCompiledExpression;
|
||
begin
|
||
PIfr := AUserData;
|
||
Ice := APtr;
|
||
Ce := Ice.VirtMach.Execute;
|
||
|
||
if (TMethod(PIfr^.Ce).Code = TMethod(Ce).Code) and
|
||
(TMethod(PIfr^.Ce).Data = TMethod(Ce).Data) then
|
||
begin
|
||
PIfr^.Found := True;
|
||
PIfr^.Ice := Ice;
|
||
PIfr^.Expr := AStr;
|
||
Result := False;
|
||
end else
|
||
Result := True;
|
||
end;
|
||
|
||
procedure TExpressionCompiler.Delete(ACompiledExpression: TCompiledExpression);
|
||
var
|
||
Ifr: TIceFindResult;
|
||
begin
|
||
with Ifr do
|
||
begin
|
||
Found := False;
|
||
Ce := ACompiledExpression;
|
||
Ice := nil;
|
||
Expr := '';
|
||
FExprHash.Iterate(@Ifr, IterateFindIce);
|
||
if not Found then
|
||
raise EJclExprEvalError.CreateRes(@RsExprEvalExprPtrNotFound);
|
||
Remove(Expr);
|
||
end;
|
||
end;
|
||
|
||
procedure TExpressionCompiler.Remove(const AExpr: string);
|
||
var
|
||
Ice: TInternalCompiledExpression;
|
||
begin
|
||
if not FExprHash.Find(AExpr, Ice) then
|
||
raise EJclExprEvalError.CreateResFmt(@RsExprEvalExprNotFound, [AExpr]);
|
||
|
||
Ice.RefCount := Ice.RefCount - 1;
|
||
Assert(Ice.RefCount >= 0, LoadResString(@RsExprEvalExprRefCountAssertion));
|
||
if Ice.RefCount = 0 then
|
||
begin
|
||
Ice.Free;
|
||
FExprHash.Remove(AExpr);
|
||
end;
|
||
end;
|
||
|
||
procedure TExpressionCompiler.Clear;
|
||
begin
|
||
FExprHash.Iterate(nil, Iterate_FreeObjects);
|
||
end;
|
||
|
||
// History:
|
||
|
||
// $Log: JclExprEval.pas,v $
|
||
// Revision 1.17 2005/04/12 17:04:30 outchy
|
||
// a semicolon at the wrong place (just before an else)
|
||
//
|
||
// Revision 1.16 2005/04/11 21:46:20 mthoma
|
||
// Fixed 0002743.
|
||
//
|
||
// Revision 1.15 2005/03/08 08:33:16 marquardt
|
||
// overhaul of exceptions and resourcestrings, minor style cleaning
|
||
//
|
||
// Revision 1.14 2005/02/26 23:27:25 mthoma
|
||
// Fixed #150 - a valid expression followed by Rubbish doesn't throw an exception => Now it does.
|
||
//
|
||
// Revision 1.13 2005/02/26 23:18:46 mthoma
|
||
// *** empty log message ***
|
||
//
|
||
// Revision 1.12 2005/02/24 16:34:40 marquardt
|
||
// remove divider lines, add section lines (unfinished)
|
||
//
|
||
// Revision 1.11 2005/02/02 04:43:01 rrossmair
|
||
// - issue #2522 fixed
|
||
//
|
||
// Revision 1.10 2004/10/12 17:20:50 rrossmair
|
||
// cleanup
|
||
//
|
||
// Revision 1.9 2004/08/02 15:30:16 marquardt
|
||
// hunting down (rom) comments
|
||
//
|
||
// Revision 1.8 2004/08/01 05:52:11 marquardt
|
||
// move constructors/destructors
|
||
//
|
||
// Revision 1.7 2004/07/03 03:27:48 rrossmair
|
||
// documentation extracted to ExprEval.dtx (Doc-O-Matic topic file)
|
||
//
|
||
// Revision 1.6 2004/06/02 03:23:44 rrossmair
|
||
// cosmetic changes in several units (code formatting, help TODOs processed etc.)
|
||
//
|
||
// Revision 1.5 2004/05/13 07:43:26 rrossmair
|
||
// reworked comments for DOM2 inclusion
|
||
//
|
||
// Revision 1.4 2004/05/05 00:04:11 mthoma
|
||
// Updated headers: Added donors as contributors, adjusted the initial authors, added cvs names when they were not obvious. Changed $data to $date where necessary,
|
||
|
||
end.
|