2809 lines
61 KiB
ObjectPascal
2809 lines
61 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
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/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvForth.PAS, released on 2002-06-15.
|
|
|
|
The Initial Developer of the Original Code is Jan Verhoeven [jan1 dott verhoeven att wxs dott nl]
|
|
Portions created by Jan Verhoeven are Copyright (C) 2002 Jan Verhoeven.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s): Robert Love [rlove att slcdug dott org].
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.sourceforge.net
|
|
|
|
Known Issues:
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: JvForth.pas 11157 2007-01-18 14:06:18Z marquardt $
|
|
|
|
unit JvForth;
|
|
|
|
{$I jvcl.inc}
|
|
{$I crossplatform.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
SysUtils, Classes,
|
|
{$IFDEF MSWINDOWS}
|
|
ShellAPI,
|
|
{$ENDIF MSWINDOWS}
|
|
Windows, Messages, Forms, Dialogs, FileCtrl,
|
|
{$IFDEF HAS_UNIT_VARIANTS}
|
|
Variants,
|
|
{$ENDIF HAS_UNIT_VARIANTS}
|
|
JvXMLTree, JvComponentBase, JvStrings, JvTypes;
|
|
|
|
const
|
|
StackMax = 1000;
|
|
|
|
type
|
|
EJvJanScriptError = class(EJVCLException);
|
|
|
|
TToken = (dfoError, dfoNop,
|
|
// flow actions
|
|
dfoIf, dfoElse, dfoEndIf, dfoRepeat, dfoUntil,
|
|
// sub routines
|
|
dfoSub, dfoEndSub, dfoCall,
|
|
// stack operations
|
|
dfoDup, dfoDrop, dfoSwap,
|
|
// conversion
|
|
dfoCstr,
|
|
// data source object, symbols starting with _
|
|
dfoDSO, dfoSelDir, dfoDSOBase,
|
|
// xmldso starts with ?
|
|
dfoXML,
|
|
// system io
|
|
dfoSystem,
|
|
// internal variables
|
|
dfoIntVar,
|
|
// external variables
|
|
dfoExtVar,
|
|
// direct action
|
|
dfoInteger, dfoFloat, dfoSet, dfoString, dfoBoolean,
|
|
dfoDate,
|
|
// end direct action
|
|
dfoEq, dfoNe, dfoGt, dfoLt, dfoGe, dfoLe, dfoLike, dfoUnlike,
|
|
dfoNot, dfoAnd, dfoXor, dfoOr,
|
|
dfoIn,
|
|
dfoAdd, dfoSubtract, dfoMultiply, dfoDivide, dfoPower,
|
|
dfoAbs,
|
|
// some usefull constants
|
|
dfoCrLf,
|
|
// some gonio functions
|
|
dfoSin, dfoCos, dfoPi, dfoTan,
|
|
dfoArcSin, dfoArcCos, dfoArcTan, dfoArcTan2,
|
|
|
|
dfoNegate, dfoSqr, dfoSqrt,
|
|
dfoLeft, dfoRight,
|
|
// windows api
|
|
dfoShellExecute,
|
|
// date and time
|
|
dfoNow, dfoTime, dfoDateStr, dfoTimeStr
|
|
);
|
|
|
|
TProcVar = procedure of object;
|
|
|
|
TOnGetVariable = procedure(Sender: TObject; Symbol: string; var Value: Variant;
|
|
var Handled: Boolean; var ErrorStr: string) of object;
|
|
TOnSetVariable = procedure(Sender: TObject; Symbol: string; Value: Variant;
|
|
var Handled: Boolean; var ErrorStr: string) of object;
|
|
TOnGetSystem = procedure(Sender: TObject; Symbol, Prompt: string; var Value: Variant;
|
|
var Handled: Boolean; var ErrorStr: string) of object;
|
|
TOnSetSystem = procedure(Sender: TObject; Symbol: string; Value: Variant;
|
|
var Handled: Boolean; var ErrorStr: string) of object;
|
|
TOnInclude = procedure(Sender: TObject; IncludeFile: string; var Value: string;
|
|
var Handled: Boolean; var ErrorStr: string) of object;
|
|
|
|
TJvJanDSO = class(TStringList)
|
|
private
|
|
function InternalGetValue(Index: Integer; const AField: string): string;
|
|
procedure InternalSetValue(Index: Integer; const AField, AValue: string);
|
|
public
|
|
// when a key is not found it will be added
|
|
procedure SetValue(AKey: Variant; const AField, AValue: string);
|
|
function GetValue(AKey: Variant; const AField: string): string;
|
|
end;
|
|
|
|
TJvJanDSOList = class(TStringList)
|
|
public
|
|
destructor Destroy; override;
|
|
procedure ClearTables;
|
|
function Table(const AName: string): TJvJanDSO;
|
|
end;
|
|
|
|
TJvJanXMLList = class(TStringList)
|
|
public
|
|
destructor Destroy; override;
|
|
procedure ClearXMLS;
|
|
function Xml(const AName: string): TJvXMLTree;
|
|
end;
|
|
|
|
TVariantObject = class(TObject)
|
|
private
|
|
FValue: Variant;
|
|
procedure SetValue(const Value: Variant);
|
|
public
|
|
property Value: Variant read FValue write SetValue;
|
|
end;
|
|
|
|
TVariantList = class(TStringList)
|
|
public
|
|
destructor Destroy; override;
|
|
procedure ClearObjects;
|
|
procedure SetVariable(const Symbol: string; AValue: Variant);
|
|
function GetVariable(const Symbol: string): Variant;
|
|
function GetObject(const Symbol: string): TVariantObject; reintroduce;
|
|
end;
|
|
|
|
TAtom = class(TObject)
|
|
private
|
|
FToken: TToken;
|
|
FSymbol: string;
|
|
FValue: Variant;
|
|
FProc: TProcVar;
|
|
FIsOperand: Boolean;
|
|
procedure SetToken(const Value: TToken);
|
|
procedure SetSymbol(const Value: string);
|
|
procedure SetValue(const Value: Variant);
|
|
procedure SetProc(const Value: TProcVar);
|
|
procedure SetIsOperand(const Value: Boolean);
|
|
public
|
|
property Token: TToken read FToken write SetToken;
|
|
property Proc: TProcVar read FProc write SetProc;
|
|
property Symbol: string read FSymbol write SetSymbol;
|
|
property Value: Variant read FValue write SetValue;
|
|
property IsOperand: Boolean read FIsOperand write SetIsOperand;
|
|
end;
|
|
|
|
TAtomList = class(TList)
|
|
public
|
|
destructor Destroy; override;
|
|
procedure ClearObjects;
|
|
end;
|
|
|
|
TJvForthScript = class(TJvComponent)
|
|
private
|
|
FScript: string;
|
|
FIncludes: TStringList;
|
|
FInDevice: string;
|
|
FOutDevice: string;
|
|
FSubsList: TStringList;
|
|
FVarsList: TVariantList;
|
|
FDSOList: TJvJanDSOList;
|
|
FXMLList: TJvJanXMLList;
|
|
FXMLSelect: TList;
|
|
FXMLSelectRecord: Integer;
|
|
FDSOBase: string; // root directory for DSO tables
|
|
FAtoms: TAtomList;
|
|
// FRStack if the return stack for loop, sub etc.
|
|
FRStack: array [0..StackMax] of Integer;
|
|
FRSP: Integer;
|
|
FVStack: array [0..StackMax] of Variant;
|
|
FVSP: Integer;
|
|
// ostack: array[0..StackMax] of TToken;
|
|
// osp: Integer;
|
|
FPStack: array [0..StackMax] of TToken;
|
|
FPSP: Integer;
|
|
FPC: Integer;
|
|
FCurrentSymbol: string;
|
|
FCurrentValue: Variant;
|
|
FOnGetVariable: TOnGetVariable;
|
|
FOnSetVariable: TOnSetVariable;
|
|
FScriptTimeOut: Integer;
|
|
FOnGetSystem: TOnGetSystem;
|
|
FOnSetSystem: TOnSetSystem;
|
|
FOnInclude: TOnInclude;
|
|
// procedure ClearAtoms;
|
|
procedure SetScript(const Value: string);
|
|
procedure SetOnGetVariable(const Value: TOnGetVariable);
|
|
procedure SetOnSetVariable(const Value: TOnSetVariable);
|
|
// expresssion procedures
|
|
|
|
// constants
|
|
procedure ProcCrLf;
|
|
// date and time
|
|
procedure ProcNow;
|
|
procedure ProcDateStr;
|
|
procedure ProcTimeStr;
|
|
// shell
|
|
procedure ProcShellExecute;
|
|
// xml variables
|
|
procedure ProcXML;
|
|
// data source variables
|
|
procedure ProcDSO;
|
|
procedure ProcSelDir;
|
|
procedure ProcDSOBase;
|
|
// external variables
|
|
procedure ProcExtVar; // general dispatcher
|
|
procedure ProcAssign;
|
|
procedure ProcVariable;
|
|
|
|
// internal variables
|
|
procedure ProcIntVar; // general dispatcher
|
|
procedure ProcVarGet;
|
|
procedure ProcVarSet;
|
|
procedure ProcVarInc;
|
|
procedure ProcVarIncIndex;
|
|
procedure ProcVarDec;
|
|
procedure ProcVarDecTestZero;
|
|
procedure ProcVarAdd;
|
|
procedure ProcVarSub;
|
|
procedure ProcVarMul;
|
|
procedure ProcVarDiv;
|
|
procedure ProcVarNeg;
|
|
procedure ProcVarLoad;
|
|
procedure ProcVarSave;
|
|
// system io
|
|
procedure ProcSystem; // general dispatcher
|
|
procedure ProcSysGet;
|
|
procedure ProcSysSet;
|
|
// flow expressions
|
|
procedure ProcIf;
|
|
procedure ProcElse;
|
|
procedure ProcEndif;
|
|
procedure ProcUntil;
|
|
procedure ProcRepeat;
|
|
// end flow expressions
|
|
|
|
// sub expressions
|
|
procedure ProcSub;
|
|
procedure ProcEndsub;
|
|
procedure ProcCall;
|
|
// conversion expressions
|
|
procedure ProcCStr;
|
|
procedure ProcNop;
|
|
procedure ProcDup;
|
|
procedure ProcDrop;
|
|
procedure ProcSwap;
|
|
procedure ProcInteger;
|
|
procedure ProcFloat;
|
|
procedure ProcSet;
|
|
procedure ProcString;
|
|
procedure ProcBoolean;
|
|
procedure ProcDate;
|
|
procedure ProcEq;
|
|
procedure ProcNe;
|
|
procedure ProcGt;
|
|
procedure ProcLt;
|
|
procedure ProcGe;
|
|
procedure ProcLe;
|
|
procedure ProcLike;
|
|
procedure ProcUnlike;
|
|
procedure ProcNot;
|
|
procedure ProcAnd;
|
|
procedure ProcXor;
|
|
procedure ProcOr;
|
|
procedure ProcIn;
|
|
procedure ProcAdd;
|
|
procedure ProcSubtract;
|
|
procedure ProcMultiply;
|
|
procedure ProcDivide;
|
|
procedure ProcPower;
|
|
procedure ProcAbs;
|
|
// some gonio functions
|
|
procedure Procpi;
|
|
procedure ProcSin;
|
|
procedure ProcCos;
|
|
procedure ProcTan;
|
|
procedure ProcArcSin;
|
|
procedure ProcArcCos;
|
|
procedure ProcArcTan;
|
|
procedure ProcArcTan2;
|
|
|
|
procedure ProcNegate;
|
|
procedure ProcSqr;
|
|
procedure ProcSqrt;
|
|
procedure ProcLeft;
|
|
procedure ProcRight;
|
|
function VPop: Variant;
|
|
procedure VPush(AValue: Variant);
|
|
// function opop: TToken;
|
|
// procedure opush(AValue: TToken);
|
|
// function ppop: TToken;
|
|
// procedure ppush(AValue: TToken);
|
|
function RPop: Integer;
|
|
procedure RPush(AValue: Integer);
|
|
procedure DoProc;
|
|
procedure DoToken(AToken: TToken);
|
|
procedure SetScriptTimeOut(const Value: Integer);
|
|
procedure ParseScript;
|
|
procedure SetOnGetSystem(const Value: TOnGetSystem);
|
|
procedure SetOnSetSystem(const Value: TOnSetSystem);
|
|
procedure SetOnInclude(const Value: TOnInclude);
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function Execute: Variant;
|
|
function PopValue: Variant;
|
|
function CanPopValue: Boolean;
|
|
procedure PushValue(AValue: Variant);
|
|
function CanPushValue: Boolean;
|
|
published
|
|
property Script: string read FScript write SetScript;
|
|
property ScriptTimeOut: Integer read FScriptTimeOut write SetScriptTimeOut;
|
|
property OnGetVariable: TOnGetVariable read FOnGetVariable write SetOnGetVariable;
|
|
property OnSetVariable: TOnSetVariable read FOnSetVariable write SetOnSetVariable;
|
|
property OnSetSystem: TOnSetSystem read FOnSetSystem write SetOnSetSystem;
|
|
property OnGetSystem: TOnGetSystem read FOnGetSystem write SetOnGetSystem;
|
|
property OnInclude: TOnInclude read FOnInclude write SetOnInclude;
|
|
end;
|
|
|
|
// runs an external file or progam
|
|
procedure Launch(const AFile: string);
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvForth.pas $';
|
|
Revision: '$Revision: 11157 $';
|
|
Date: '$Date: 2007-01-18 15:06:18 +0100 (jeu., 18 janv. 2007) $';
|
|
LogPath: 'JVCL\run'
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
Math,
|
|
JvConsts, JvResources;
|
|
|
|
{ some utility functions }
|
|
|
|
procedure Launch(const AFile: string);
|
|
var
|
|
Command, Params, WorkDir: string;
|
|
begin
|
|
Command := AFile;
|
|
Params := #0;
|
|
WorkDir := #0;
|
|
{$IFDEF VCL}
|
|
ShellExecute(Application.Handle, 'open', PChar(Command),
|
|
PChar(Params), PChar(WorkDir), SW_SHOWNORMAL);
|
|
{$ENDIF VCL}
|
|
{$IFDEF VisualCLX}
|
|
ShellExecute(0, 'open', PChar(Command),
|
|
PChar(Params), PChar(WorkDir), SW_SHOWNORMAL);
|
|
{$ENDIF VisualCLX}
|
|
end;
|
|
|
|
procedure GlobalSetValue(var AText: string; const AName, AValue: string);
|
|
var
|
|
P, P2, L: Integer;
|
|
begin
|
|
L := Length(AName) + 2;
|
|
if AText = '' then
|
|
begin
|
|
AText := AName + '="' + AValue + '"';
|
|
end
|
|
else
|
|
begin
|
|
P := PosText(AName + '="', AText);
|
|
if P = 0 then
|
|
AText := AText + ' ' + AName + '="' + AValue + '"'
|
|
else
|
|
begin
|
|
P2 := PosStr('"', AText, P + L);
|
|
if P2 = 0 then
|
|
Exit;
|
|
Delete(AText, P + L, P2 - (P + L));
|
|
Insert(AValue, AText, P + L);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GlobalGetValue(const AText, AName: string): string;
|
|
var
|
|
P, P2, L: Integer;
|
|
begin
|
|
Result := '';
|
|
L := Length(AName) + 2;
|
|
P := PosText(AName + '="', AText);
|
|
if P = 0 then
|
|
Exit;
|
|
P2 := PosStr('"', AText, P + L);
|
|
if P2 = 0 then
|
|
Exit;
|
|
Result := Copy(AText, P + L, P2 - (P + L));
|
|
Result := StringReplace(Result, '~~', sLineBreak, [rfReplaceAll]);
|
|
end;
|
|
|
|
// some special expression functions
|
|
|
|
// returns the Index of Integer v in aList
|
|
|
|
function IndexOfInteger(AList: TStringList; Value: Variant): Integer;
|
|
var
|
|
C, I, Index, P: Integer;
|
|
S, S1, S2: string;
|
|
begin
|
|
Result := -1;
|
|
I := Value;
|
|
C := AList.Count;
|
|
if C = 0 then
|
|
Exit;
|
|
for Index := 0 to C - 1 do
|
|
begin
|
|
try
|
|
S := AList[Index];
|
|
P := Pos('..', S);
|
|
if P = 0 then
|
|
begin
|
|
if StrToInt(AList[Index]) = I then
|
|
begin
|
|
Result := Index;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
begin // have range
|
|
S1 := Trim(Copy(S, 1, P - 1));
|
|
S2 := Trim(Copy(S, P + 2, Length(S)));
|
|
if (I >= StrToInt(S1)) and (I <= StrToInt(S2)) then
|
|
begin
|
|
Result := Index;
|
|
Exit;
|
|
end;
|
|
end;
|
|
except
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// returns the Index of float Value (single or double) in AList
|
|
|
|
function IndexOfFloat(AList: TStringList; Value: Variant): Integer;
|
|
var
|
|
C, Index, P: Integer;
|
|
F: Extended;
|
|
S, S1, S2: string;
|
|
begin
|
|
Result := -1;
|
|
F := Value;
|
|
C := AList.Count;
|
|
if C = 0 then
|
|
Exit;
|
|
for Index := 0 to C - 1 do
|
|
begin
|
|
try
|
|
S := AList[Index];
|
|
P := Pos('..', S);
|
|
if P = 0 then
|
|
begin
|
|
if StrToFloat(S) = F then
|
|
begin
|
|
Result := Index;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
begin // have range
|
|
S1 := Trim(Copy(S, 1, P - 1));
|
|
S2 := Trim(Copy(S, P + 2, Length(S)));
|
|
if (F >= StrToFloat(S1)) and (F <= StrToFloat(S2)) then
|
|
begin
|
|
Result := Index;
|
|
Exit;
|
|
end;
|
|
end;
|
|
except
|
|
raise EJvJanScriptError.CreateResFmt(@RsEInvalidNumbers, [S]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// returns the Index of date Value in AList
|
|
|
|
function IndexOfDate(AList: TStringList; Value: Variant): Integer;
|
|
var
|
|
C, Index, P: Integer;
|
|
D: TDateTime;
|
|
S, S1, S2: string;
|
|
begin
|
|
Result := -1;
|
|
D := Value;
|
|
C := AList.Count;
|
|
if C = 0 then
|
|
Exit;
|
|
for Index := 0 to C - 1 do
|
|
begin
|
|
try
|
|
S := AList[Index];
|
|
P := Pos('..', S);
|
|
if P = 0 then
|
|
begin
|
|
if StrToDate(AList[Index]) = D then
|
|
begin
|
|
Result := Index;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
S1 := Trim(Copy(S, 1, P - 1));
|
|
S2 := Trim(Copy(S, P + 2, Length(S)));
|
|
if (D >= StrToDate(S1)) and (D <= StrToDate(S2)) then
|
|
begin
|
|
Result := Index;
|
|
Exit;
|
|
end;
|
|
end;
|
|
except
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// returns the Index of string Value in AList
|
|
|
|
function IndexOfString(AList: TStringList; Value: Variant): Integer;
|
|
var
|
|
C, Index, P: Integer;
|
|
SV: string;
|
|
S, S1, S2: string;
|
|
begin
|
|
Result := -1;
|
|
SV := Value;
|
|
C := AList.Count;
|
|
if C = 0 then
|
|
Exit;
|
|
for Index := 0 to C - 1 do
|
|
begin
|
|
try
|
|
S := AList[Index];
|
|
P := Pos('..', S);
|
|
if P = 0 then
|
|
begin
|
|
if AList[Index] = SV then
|
|
begin
|
|
Result := Index;
|
|
Exit;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
S1 := Trim(Copy(S, 1, P - 1));
|
|
S2 := Trim(Copy(S, P + 2, Length(S)));
|
|
if (SV >= S1) and (SV <= S2) then
|
|
begin
|
|
Result := Index;
|
|
Exit;
|
|
end;
|
|
end;
|
|
except
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// used by dfoIN
|
|
// tests if AValue is in ASet
|
|
|
|
function FuncIn(AValue: Variant; ASet: Variant): Boolean;
|
|
var
|
|
List: TStringList;
|
|
S: string;
|
|
P: Integer;
|
|
Token: string;
|
|
|
|
function GetToken: Boolean;
|
|
begin
|
|
Result := False;
|
|
S := TrimLeft(S);
|
|
if S = '' then
|
|
Exit;
|
|
P := 1;
|
|
if S[1] = '"' then
|
|
begin // get string
|
|
P := PosStr('"', S, 2);
|
|
if P = 0 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEUnterminatedStringNears, [S]);
|
|
Token := Copy(S, 2, P - 2);
|
|
Delete(S, 1, P);
|
|
Result := True;
|
|
end
|
|
else
|
|
begin
|
|
P := Pos(' ', S);
|
|
if P = 0 then
|
|
begin
|
|
Token := S;
|
|
Result := True;
|
|
S := '';
|
|
end
|
|
else
|
|
begin
|
|
Token := Copy(S, 1, P - 1);
|
|
Delete(S, 1, P);
|
|
Result := True;
|
|
end;
|
|
end
|
|
end;
|
|
|
|
begin
|
|
Result := False;
|
|
S := ASet;
|
|
if S = '' then
|
|
Exit;
|
|
List := TStringList.Create;
|
|
try
|
|
while GetToken do
|
|
List.Append(Token);
|
|
// c:=List.Count;
|
|
case VarType(AValue) of
|
|
varString:
|
|
Result := IndexOfString(List, AValue) > -1;
|
|
varInteger, varByte:
|
|
Result := IndexOfInteger(List, AValue) > -1;
|
|
varSingle, varDouble:
|
|
Result := IndexOfFloat(List, AValue) > -1;
|
|
varDate:
|
|
Result := IndexOfDate(List, AValue) > -1;
|
|
else
|
|
raise EJvJanScriptError.CreateRes(@RsEUnrecognizedDataTypeInSetOperation);
|
|
end;
|
|
finally
|
|
List.Free;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvForthScript } =====================================================
|
|
|
|
constructor TJvForthScript.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FAtoms := TAtomList.Create;
|
|
FIncludes := TStringList.Create;
|
|
FSubsList := TStringList.Create;
|
|
FVarsList := TVariantList.Create;
|
|
FDSOList := TJvJanDSOList.Create;
|
|
FXMLList := TJvJanXMLList.Create;
|
|
FXMLSelect := TList.Create;
|
|
FDSOBase := ExtractFilePath(ParamStr(0));
|
|
if FDSOBase[Length(FDSOBase)] = PathDelim then
|
|
Delete(FDSOBase, Length(FDSOBase), 1);
|
|
FVSP := 0;
|
|
// osp := 0;
|
|
FRSP := 0;
|
|
FInDevice := 'dialog';
|
|
FOutDevice := 'dialog';
|
|
FScriptTimeOut := 30; // seconds
|
|
end;
|
|
|
|
destructor TJvForthScript.Destroy;
|
|
begin
|
|
FAtoms.Free;
|
|
FIncludes.Free;
|
|
FSubsList.Free;
|
|
FVarsList.Free;
|
|
FDSOList.Free;
|
|
FXMLList.Free;
|
|
FXMLSelect.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvForthScript.VPush(AValue: Variant);
|
|
begin
|
|
//FVStack.push(AValue);
|
|
FVStack[FVSP] := AValue;
|
|
if FVSP < StackMax then
|
|
Inc(FVSP)
|
|
else
|
|
raise EJvJanScriptError.CreateRes(@RsEStackOverflow);
|
|
end;
|
|
|
|
(*
|
|
procedure TJvForthScript.opush(AValue: TToken);
|
|
begin
|
|
ostack[osp] := AValue;
|
|
if osp < StackMax then
|
|
Inc(osp);
|
|
end;
|
|
*)
|
|
(*
|
|
function TJvForthScript.opop: TToken;
|
|
begin
|
|
showmessage('opop');
|
|
if osp <= 0 then
|
|
Result := dfonop
|
|
else
|
|
begin
|
|
Dec(osp);
|
|
Result := ostack[osp];
|
|
end;
|
|
end;
|
|
*)
|
|
(*
|
|
procedure TJvForthScript.ppush(AValue: TToken);
|
|
begin
|
|
FPStack[FPSP] := AValue;
|
|
if FPSP < StackMax then
|
|
Inc(FPSP);
|
|
end;
|
|
*)
|
|
(*
|
|
function TJvForthScript.ppop: TToken;
|
|
begin
|
|
if FPSP = 0 then
|
|
Result := dfoError
|
|
else
|
|
begin
|
|
Dec(FPSP);
|
|
Result := FPStack[FPSP];
|
|
end;
|
|
end;
|
|
*)
|
|
function TJvForthScript.VPop: Variant;
|
|
begin
|
|
if FVSP = 0 then
|
|
raise EJvJanScriptError.CreateRes(@RsEStackUnderflow)
|
|
else
|
|
begin
|
|
Dec(FVSP);
|
|
Result := FVStack[FVSP];
|
|
end;
|
|
end;
|
|
|
|
procedure TJvForthScript.SetScript(const Value: string);
|
|
begin
|
|
if Value <> FScript then
|
|
begin
|
|
FScript := Value;
|
|
ParseScript;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvForthScript.ParseScript;
|
|
var
|
|
S: string;
|
|
I, P, P2: Integer;
|
|
Atom: TAtom;
|
|
// atomoperation: TToken;
|
|
AtomSymbol: string;
|
|
AtomValue: Variant;
|
|
// atomproc: TProcVar;
|
|
Token: string;
|
|
VInteger: Integer;
|
|
VFloat: Double;
|
|
VDate: TDateTime;
|
|
// handling of includes:
|
|
IncFile: string;
|
|
Handled: Boolean;
|
|
IncScript: string;
|
|
ErrStr: string;
|
|
TimeOutTicks: Cardinal;
|
|
DeltaTicks: Cardinal;
|
|
|
|
function PushAtom(AToken: TToken): Integer;
|
|
// var cc: Integer;
|
|
begin
|
|
Atom := TAtom.Create;
|
|
Atom.Token := AToken;
|
|
Atom.Symbol := AtomSymbol;
|
|
Atom.Value := AtomValue;
|
|
Result := FAtoms.Add(Atom);
|
|
end;
|
|
|
|
procedure OPush(AToken: TToken);
|
|
// var cc: Integer;
|
|
begin
|
|
Atom := TAtom.Create;
|
|
Atom.Token := AToken;
|
|
Atom.Symbol := Token;
|
|
Atom.Value := AtomValue;
|
|
FAtoms.Add(Atom);
|
|
end;
|
|
|
|
procedure BrcPush(Proc: TProcVar);
|
|
// var cc: Integer;
|
|
begin
|
|
Atom := TAtom.Create;
|
|
Atom.Proc := Proc;
|
|
Atom.Symbol := AtomSymbol;
|
|
Atom.Value := AtomValue;
|
|
Atom.IsOperand := False;
|
|
FAtoms.Add(Atom);
|
|
end;
|
|
|
|
function GetToken: Boolean;
|
|
begin
|
|
Result := False;
|
|
S :=TrimLeft(S);
|
|
if S = '' then
|
|
Exit;
|
|
P := 1;
|
|
if S[1] = '"' then
|
|
begin // get string
|
|
P := PosStr('"', S, 2);
|
|
if P = 0 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEUnterminatedStringNears, [S]);
|
|
Token := Copy(S, 1, P);
|
|
Delete(S, 1, P);
|
|
Result := True;
|
|
end
|
|
else
|
|
if S[1] = '[' then
|
|
begin // get block
|
|
P := PosStr(']', S, 2);
|
|
if P = 0 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEUnterminatedBlockNear, [S]);
|
|
Token := Copy(S, 1, P);
|
|
Delete(S, 1, P);
|
|
Result := True;
|
|
end
|
|
else
|
|
begin
|
|
P := Pos(' ', S);
|
|
if P = 0 then
|
|
begin
|
|
Token := S;
|
|
Result := True;
|
|
S := '';
|
|
end
|
|
else
|
|
begin
|
|
Token := Copy(S, 1, P - 1);
|
|
Delete(S, 1, P);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
FAtoms.ClearObjects;
|
|
FSubsList.Clear;
|
|
// reset return stack; needed in resolving flow statements
|
|
FRSP := 0;
|
|
S := FScript;
|
|
// include any include files, include files start with $$ and end with ;
|
|
// when the parser detects and include file it will raise the oninclude event
|
|
// include files can also include files (nested includes)
|
|
DeltaTicks := FScriptTimeOut * 1000;
|
|
TimeOutTicks := GetTickCount + DeltaTicks;
|
|
FIncludes.Clear; // Clear the includes List
|
|
repeat
|
|
if GetTickCount > TimeOutTicks then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEParserTimedOutAfterdSecondsYouMayHa, [FScriptTimeout]);
|
|
P := PosStr('$$', S);
|
|
if P > 0 then
|
|
begin
|
|
P2 := PosStr(';', S, P);
|
|
if P2 = 0 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEUnterminatedIncludeNears, [Copy(S, P, Length(S))]);
|
|
IncFile := Copy(S, P + 2, P2 - P - 2) + '.jan';
|
|
if PosStr(' ', IncFile, 1) > 0 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEIllegalSpaceCharacterInTheIncludeFi, [IncFile]);
|
|
I := FIncludes.IndexOf(IncFile);
|
|
if I <> -1 then
|
|
Delete(S, P, P2 - P + 1)
|
|
else
|
|
begin
|
|
ErrStr := Format(RsECanNotFindIncludeFiles, [IncFile]);
|
|
Handled := False;
|
|
IncScript := '';
|
|
if not Assigned(OnInclude) then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEOnIncludeHandlerNotAssignedCanNotHa, [Copy(S, P, Length(S))]);
|
|
OnInclude(Self, IncFile, IncScript, Handled, ErrStr);
|
|
if not Handled then
|
|
raise EJvJanScriptError.Create(ErrStr);
|
|
Delete(S, P, P2 - P + 1);
|
|
Insert(IncScript, S, P);
|
|
FIncludes.Append(IncFile);
|
|
end;
|
|
end;
|
|
until P = 0;
|
|
S := Trim(StringReplace(S, sLineBreak, ' ', [rfReplaceAll]));
|
|
// remove comments
|
|
repeat
|
|
P := Pos('{', S);
|
|
if P > 0 then
|
|
begin
|
|
P2 := PosStr('}', S, P);
|
|
if P2 = 0 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEMissingCommentTerminatorNears, [S]);
|
|
Delete(S, P, P2 - P + 1);
|
|
end;
|
|
until P = 0;
|
|
if S = '' then
|
|
Exit;
|
|
while GetToken do
|
|
begin
|
|
if Token = 'cstr' then
|
|
OPush(dfoCstr)
|
|
else
|
|
if Token = 'seldir' then
|
|
OPush(dfoSelDir)
|
|
else
|
|
if Token = 'dsobase' then
|
|
OPush(dfoDSOBase)
|
|
else
|
|
if Token = 'dup' then
|
|
OPush(dfoDup)
|
|
else
|
|
if Token = 'drop' then
|
|
OPush(dfoDrop)
|
|
else
|
|
if Token = 'swap' then
|
|
OPush(dfoSwap)
|
|
else
|
|
if Token = 'if' then
|
|
begin
|
|
P := PushAtom(dfoIf);
|
|
RPush(P);
|
|
end
|
|
else
|
|
if Token = 'endif' then
|
|
begin
|
|
P := PushAtom(dfoEndIf);
|
|
P2 := RPop;
|
|
Atom := TAtom(FAtoms[P2]);
|
|
Atom.Value := P + 1;
|
|
end
|
|
else
|
|
if Token = 'else' then
|
|
begin
|
|
P := PushAtom(dfoElse);
|
|
P2 := RPop;
|
|
RPush(P);
|
|
Atom := TAtom(FAtoms[P2]);
|
|
Atom.Value := P + 1;
|
|
end
|
|
else
|
|
if Token = 'repeat' then
|
|
begin
|
|
P := PushAtom(dfoRepeat);
|
|
RPush(P);
|
|
end
|
|
else
|
|
if Token = 'until' then
|
|
begin
|
|
AtomValue := RPop;
|
|
PushAtom(dfoUntil);
|
|
end
|
|
else
|
|
if Token = 'now' then
|
|
OPush(dfoNow)
|
|
else
|
|
if Token = 'datestr' then
|
|
OPush(dfoDateStr)
|
|
else
|
|
if Token = 'timestr' then
|
|
OPush(dfoTimeStr)
|
|
else
|
|
if Token = 'shellexecute' then
|
|
OPush(dfoShellExecute)
|
|
else
|
|
if Token = ';' then
|
|
OPush(dfoEndSub)
|
|
else
|
|
if Token = 'crlf' then
|
|
OPush(dfoCrLf)
|
|
else
|
|
if Token = '--' then
|
|
OPush(dfoNegate)
|
|
else
|
|
if Token = '-' then
|
|
OPush(dfoSubtract)
|
|
else
|
|
if Token = '+' then
|
|
OPush(dfoAdd)
|
|
else
|
|
if Token = '*' then
|
|
OPush(dfoMultiply)
|
|
else
|
|
if Token = '/' then
|
|
OPush(dfoDivide)
|
|
else
|
|
if Token = '^' then
|
|
OPush(dfoPower)
|
|
else
|
|
if Token = 'abs' then
|
|
OPush(dfoAbs)
|
|
else
|
|
if Token = 'left' then
|
|
OPush(dfoLeft)
|
|
else
|
|
if Token = 'right' then
|
|
OPush(dfoRight)
|
|
else
|
|
if Token = 'sqr' then
|
|
OPush(dfoSqr)
|
|
else
|
|
if Token = 'sqrt' then
|
|
OPush(dfoSqrt)
|
|
else
|
|
if Token = 'sin' then
|
|
OPush(dfoSin)
|
|
else
|
|
if Token = 'cos' then
|
|
OPush(dfoCos)
|
|
else
|
|
if Token = 'tan' then
|
|
OPush(dfoTan)
|
|
else
|
|
if Token = 'arcsin' then
|
|
OPush(dfoArcSin)
|
|
else
|
|
if Token = 'arccos' then
|
|
OPush(dfoArcCos)
|
|
else
|
|
if Token = 'arctan' then
|
|
OPush(dfoArcTan)
|
|
else
|
|
if Token = 'arctan2' then
|
|
OPush(dfoArcTan2)
|
|
else
|
|
if Token = 'pi' then
|
|
OPush(dfoPi)
|
|
else
|
|
if Token = '<>' then
|
|
OPush(dfoNe)
|
|
else
|
|
if Token = '>=' then
|
|
OPush(dfoGe)
|
|
else
|
|
if Token = '>' then
|
|
OPush(dfoGt)
|
|
else
|
|
if Token = '<=' then
|
|
OPush(dfoLe)
|
|
else
|
|
if Token = '<' then
|
|
OPush(dfoLt)
|
|
else
|
|
if Token = '=' then
|
|
OPush(dfoEq)
|
|
else
|
|
if Token = 'or' then
|
|
OPush(dfoOr)
|
|
else
|
|
if Token = 'and' then
|
|
OPush(dfoAnd)
|
|
else
|
|
if Token = 'in' then
|
|
OPush(dfoIn)
|
|
else
|
|
if Token = 'xor' then
|
|
OPush(dfoXor)
|
|
else
|
|
if Token = 'not' then
|
|
OPush(dfoNot)
|
|
else
|
|
if Token = 'like' then
|
|
OPush(dfoLike)
|
|
else
|
|
if Token = 'unlike' then
|
|
OPush(dfoUnlike)
|
|
// check for block
|
|
else
|
|
if Token[1] = '[' then
|
|
begin
|
|
AtomSymbol := Token;
|
|
AtomValue := Copy(Token, 2, Length(Token) - 2);
|
|
PushAtom(dfoSet);
|
|
end
|
|
// check for sub
|
|
else
|
|
if Token[Length(Token)] = '=' then
|
|
begin
|
|
AtomSymbol := Copy(Token, 1, Length(Token) - 1);
|
|
P := PushAtom(dfoSub);
|
|
FSubsList.AddObject(AtomSymbol, TObject(P + 1));
|
|
end
|
|
// check for xml object
|
|
else
|
|
if (Token[1] = '?') and (Length(Token) > 1) then
|
|
begin
|
|
P := Pos('.', Token);
|
|
if (P = 0) or (P < 3) or (P = Length(Token)) then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEMissingXmlMethodSpecifierNears, [S]);
|
|
AtomSymbol := Copy(Token, 2, P - 2);
|
|
AtomValue := Copy(Token, P + 1, Length(Token));
|
|
PushAtom(dfoXML);
|
|
end
|
|
// check for data source object
|
|
else
|
|
if (Token[1] = '_') and (Length(Token) > 1) then
|
|
begin
|
|
P := Pos('.', Token);
|
|
if (P = 0) or (P < 3) or (P = Length(Token)) then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEMissingDataSourceMethodSpecifierNea, [S]);
|
|
AtomSymbol := Copy(Token, 2, P - 2);
|
|
AtomValue := Copy(Token, P + 1, Length(Token));
|
|
PushAtom(dfoDSO);
|
|
end
|
|
// system
|
|
else
|
|
if (Token[1] = ')') and (Length(Token) > 1) then
|
|
begin
|
|
P := Pos('.', Token);
|
|
if (P = 0) or (P < 3) or (P = Length(Token)) then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEMissingSystemMethodSpecifierNears, [S]);
|
|
AtomSymbol := Copy(Token, 2, P - 2);
|
|
AtomValue := Copy(Token, P + 1, Length(Token));
|
|
PushAtom(dfoSystem);
|
|
end
|
|
// external variable
|
|
else
|
|
if (Token[1] = '>') and (Length(Token) > 1) then
|
|
begin
|
|
P := Pos('.', Token);
|
|
if (P = 0) or (P < 3) or (P = Length(Token)) then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEMissingExternalVariableMethodSpecif, [S]);
|
|
AtomSymbol := Copy(Token, 2, P - 2);
|
|
AtomValue := Copy(Token, P + 1, Length(Token));
|
|
PushAtom(dfoExtVar);
|
|
end
|
|
// check for internal variable
|
|
else
|
|
if (Token[1] = ':') and (Length(Token) > 1) then
|
|
begin
|
|
P := Pos('.', Token);
|
|
if (P = 0) or (P < 3) or (P = Length(Token)) then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEMissingInternalVariableMethodSpecif, [S]);
|
|
AtomSymbol := Copy(Token, 2, P - 2);
|
|
AtomValue := Copy(Token, P + 1, Length(Token));
|
|
PushAtom(dfoIntVar);
|
|
end
|
|
// check for string
|
|
else
|
|
if Token[1] = '"' then
|
|
begin
|
|
AtomSymbol := Token;
|
|
AtomValue := Copy(Token, 2, Length(Token) - 2);
|
|
PushAtom(dfoString);
|
|
end
|
|
// check Integer, float or date
|
|
else
|
|
begin
|
|
try // Integer
|
|
VInteger := StrToInt(Token);
|
|
AtomSymbol := Token;
|
|
AtomValue := VInteger;
|
|
PushAtom(dfoInteger);
|
|
except
|
|
try // float
|
|
VFloat := StrToFloat(Token);
|
|
AtomSymbol := Token;
|
|
AtomValue := VFloat;
|
|
PushAtom(dfoFloat);
|
|
except
|
|
try // date
|
|
VDate := StrToDate(Token);
|
|
AtomSymbol := Token;
|
|
AtomValue := VDate;
|
|
PushAtom(dfoDate);
|
|
except // must be call to sub
|
|
AtomSymbol := Token;
|
|
P := FSubsList.IndexOf(AtomSymbol);
|
|
if P = -1 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEUndefinedWordsNears, [AtomSymbol, S]);
|
|
P := Integer(FsubsList.Objects[P]);
|
|
AtomValue := P;
|
|
PushAtom(dfoCall);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvForthScript.DoToken(AToken: TToken);
|
|
begin
|
|
case AToken of
|
|
dfoNow:
|
|
ProcNow;
|
|
dfoDateStr:
|
|
ProcDateStr;
|
|
dfoTimeStr:
|
|
ProcTimeStr;
|
|
dfoShellExecute:
|
|
ProcShellExecute;
|
|
dfoCrLf:
|
|
ProcCrLf;
|
|
dfoCStr:
|
|
ProcCStr;
|
|
dfoXML:
|
|
ProcXML;
|
|
dfoDSO:
|
|
ProcDSO;
|
|
dfoSeldir:
|
|
ProcSelDir;
|
|
dfoDSOBase:
|
|
ProcDSOBase;
|
|
dfoIntVar:
|
|
ProcIntVar;
|
|
dfoExtVar:
|
|
ProcExtVar;
|
|
dfoSystem:
|
|
ProcSystem;
|
|
// dfoVarGet: ProcVarGet;
|
|
// dfoVarset: ProcVarSet;
|
|
// dfoSysGet: ProcSysGet;
|
|
// dfoSysSet: ProcSysSet;
|
|
dfoSub:
|
|
ProcSub;
|
|
dfoEndSub:
|
|
ProcEndSub;
|
|
dfoCall:
|
|
ProcCall;
|
|
dfoDrop:
|
|
ProcDrop;
|
|
dfoDup:
|
|
ProcDup;
|
|
dfoSwap:
|
|
ProcSwap;
|
|
dfoIf:
|
|
ProcIf;
|
|
dfoElse:
|
|
ProcElse;
|
|
dfoEndIf:
|
|
ProcEndIf;
|
|
dfoRepeat:
|
|
ProcRepeat;
|
|
dfoUntil:
|
|
ProcUntil;
|
|
dfoNop:
|
|
ProcNop;
|
|
// dfoAssign: ProcAssign;
|
|
// dfoVariable: ProcVariable;
|
|
dfoInteger:
|
|
ProcInteger;
|
|
dfoFloat:
|
|
ProcFloat;
|
|
dfoSet:
|
|
ProcSet;
|
|
dfoString:
|
|
ProcString;
|
|
dfoBoolean:
|
|
ProcBoolean;
|
|
dfoDate:
|
|
ProcDate;
|
|
dfoEq:
|
|
ProcEq;
|
|
dfoNe:
|
|
ProcNe;
|
|
dfoGt:
|
|
ProcGt;
|
|
dfoLt:
|
|
ProcLt;
|
|
dfoGe:
|
|
ProcGe;
|
|
dfoLe:
|
|
ProcLe;
|
|
dfoLike:
|
|
ProcLike;
|
|
dfoUnlike:
|
|
ProcUnlike;
|
|
dfoNot:
|
|
ProcNot;
|
|
dfoAnd:
|
|
ProcAnd;
|
|
dfoXor:
|
|
ProcXor;
|
|
dfoOr:
|
|
ProcOr;
|
|
dfoIn:
|
|
ProcIn;
|
|
dfoAdd:
|
|
ProcAdd;
|
|
dfoSubtract:
|
|
ProcSubtract;
|
|
dfoMultiply:
|
|
ProcMultiply;
|
|
dfoDivide:
|
|
ProcDivide;
|
|
dfoPower:
|
|
ProcPower;
|
|
dfoAbs:
|
|
ProcAbs;
|
|
dfoPi:
|
|
ProcPi;
|
|
dfoSin:
|
|
ProcSin;
|
|
dfoCos:
|
|
ProcCos;
|
|
dfoTan:
|
|
ProcTan;
|
|
dfoArcSin:
|
|
ProcArcSin;
|
|
dfoArcCos:
|
|
ProcArcCos;
|
|
dfoArcTan:
|
|
ProcArcTan;
|
|
dfoArcTan2:
|
|
ProcArcTan2;
|
|
dfoNegate:
|
|
ProcNegate;
|
|
dfoSqr:
|
|
ProcSqr;
|
|
dfoSqrt:
|
|
ProcSqrt;
|
|
dfoLeft:
|
|
ProcLeft;
|
|
dfoRight:
|
|
ProcRight;
|
|
end;
|
|
end;
|
|
|
|
function TJvForthScript.Execute: Variant;
|
|
var
|
|
C: Integer;
|
|
Atom: TAtom;
|
|
Token: TToken;
|
|
TimeOutTicks: Cardinal;
|
|
DeltaTicks: Cardinal;
|
|
begin
|
|
Result := Null;
|
|
// osp := 0;
|
|
FVSP := 0;
|
|
FPSP := 0;
|
|
FRSP := 0;
|
|
C := FAtoms.Count;
|
|
FVarsList.ClearObjects;
|
|
FDSOList.ClearTables;
|
|
FXMLList.ClearXMLS;
|
|
FXMLSelect.Clear;
|
|
FXMLSelectRecord := -1;
|
|
if C = 0 then
|
|
Exit;
|
|
FPC := 0;
|
|
DeltaTicks := FScriptTimeOut * 1000;
|
|
TimeOutticks := GetTickCount + DeltaTicks;
|
|
// evaluate all FAtoms
|
|
while FPC < C do
|
|
begin
|
|
if GetTickCount > TimeOutTicks then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEScriptTimedOutAfterdSeconds, [FScriptTimeout]);
|
|
Atom := TAtom(FAtoms[FPC]);
|
|
Inc(FPC);
|
|
FCurrentValue := Atom.Value;
|
|
FCurrentSymbol := Atom.Symbol;
|
|
Token := Atom.Token;
|
|
case Token of
|
|
dfoInteger..dfoDate:
|
|
VPush(FCurrentValue);
|
|
else
|
|
DoToken(Token);
|
|
end;
|
|
end;
|
|
if FVSP <= 0 then
|
|
Result := Null
|
|
else
|
|
Result := VPop;
|
|
end;
|
|
|
|
procedure TJvForthScript.SetOnGetVariable(const Value: TOnGetVariable);
|
|
begin
|
|
FOnGetVariable := Value;
|
|
end;
|
|
|
|
(*)
|
|
procedure TJvForthScript.ClearAtoms;
|
|
var
|
|
i, c: Integer;
|
|
begin
|
|
c := FAtoms.Count;
|
|
if c = 0 then
|
|
Exit;
|
|
for i := 0 to c - 1 do
|
|
Tobject(FAtoms[i]).Free;
|
|
FAtoms.Clear;
|
|
end;
|
|
(*)
|
|
|
|
procedure TJvForthScript.SetOnSetVariable(const Value: TOnSetVariable);
|
|
begin
|
|
FOnSetVariable := Value;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcAdd;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
Value := VPop + Value;
|
|
VPush(Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcAnd;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop and Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcAssign;
|
|
var
|
|
Value: Variant;
|
|
Handled: Boolean;
|
|
Err: string;
|
|
begin
|
|
Value := VPop;
|
|
VPush(Value);
|
|
Handled := False;
|
|
Err := Format(RsECanNotAssignVariables, [FCurrentSymbol]);
|
|
if Assigned(OnSetVariable) then
|
|
begin
|
|
OnSetVariable(Self, FCurrentSymbol, Value, Handled, Err);
|
|
if not Handled then
|
|
raise EJvJanScriptError.Create(Err);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcBoolean;
|
|
begin
|
|
VPush(FCurrentValue);
|
|
DoProc;
|
|
end;
|
|
|
|
procedure TJvForthScript.DoProc;
|
|
var
|
|
Token: TToken;
|
|
begin
|
|
if FPSP <= 0 then
|
|
Exit;
|
|
Dec(FPSP);
|
|
Token := FPStack[FPSP];
|
|
DoToken(Token);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcCos;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(Cos(Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcDate;
|
|
begin
|
|
VPush(FCurrentValue);
|
|
DoProc;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcDivide;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop / Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcEq;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop = Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcFloat;
|
|
begin
|
|
VPush(FCurrentValue);
|
|
DoProc;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcGe;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop >= Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcGt;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop > Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcIn;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(FuncIn(VPop, Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcInteger;
|
|
begin
|
|
VPush(FCurrentValue);
|
|
DoProc;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcLe;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop <= Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcLeft;
|
|
var
|
|
Value, V2: Variant;
|
|
Vali: Integer;
|
|
Vals: string;
|
|
begin
|
|
Value := VPop;
|
|
V2 := VPop;
|
|
Vali := Value;
|
|
Vals := V2;
|
|
Value := Copy(Vals, 1, Vali);
|
|
VPush(Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcLike;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VarToStr(VPop);
|
|
VPush(Pos(LowerCase(Value), LowerCase(VarToStr(VPop))) > 0);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcLt;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop < Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcMultiply;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
Value := VPop * Value;
|
|
VPush(Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcNe;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop <> Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcNegate;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(0 - Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcNop;
|
|
begin
|
|
// just do nothing
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcNot;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(not Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcOr;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop or Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcRight;
|
|
var
|
|
Value, V2: Variant;
|
|
Vali: Integer;
|
|
Vals: string;
|
|
begin
|
|
Value := VPop;
|
|
V2 := VPop;
|
|
Vali := Value;
|
|
Vals := V2;
|
|
if Vali <= Length(Vals) then
|
|
Value := Copy(Vals, Length(Vals) - Vali + 1, Vali)
|
|
else
|
|
Value := Vals;
|
|
VPush(Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSet;
|
|
begin
|
|
VPush(FCurrentValue);
|
|
DoProc;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSin;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(Sin(Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSqr;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(Sqr(Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSqrt;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(Sqrt(Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcString;
|
|
begin
|
|
VPush(FCurrentValue);
|
|
DoProc;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSubtract;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop - Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcUnlike;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VarToStr(VPop);
|
|
VPush(Pos(LowerCase(Value), LowerCase(VarToStr(VPop))) = 0);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVariable;
|
|
var
|
|
Value: Variant;
|
|
Handled: Boolean;
|
|
Err: string;
|
|
begin
|
|
Handled := False;
|
|
Err := Format(RsEVariablesNotDefined, [FCurrentSymbol]);
|
|
if Assigned(FOnGetVariable) then
|
|
FOnGetVariable(Self, FCurrentSymbol, Value, Handled, Err);
|
|
if not Handled then
|
|
raise EJvJanScriptError.Create(Err)
|
|
else
|
|
VPush(Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcXor;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(VPop xor Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcIf;
|
|
var
|
|
V: Variant;
|
|
begin
|
|
V := VPop;
|
|
if V then
|
|
Exit
|
|
else
|
|
FPC := FCurrentValue;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcElse;
|
|
begin
|
|
FPC := FCurrentValue;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcDrop;
|
|
begin
|
|
VPop;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcDup;
|
|
var
|
|
V: Variant;
|
|
begin
|
|
V := VPop;
|
|
VPush(V);
|
|
VPush(V);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSwap;
|
|
var
|
|
V1, V2: Variant;
|
|
begin
|
|
V1 := VPop;
|
|
V2 := VPop;
|
|
VPush(V1);
|
|
VPush(V2);
|
|
end;
|
|
|
|
// just a marker
|
|
|
|
procedure TJvForthScript.ProcEndif;
|
|
begin
|
|
// do nothing
|
|
end;
|
|
|
|
// keep looping until vpop=True
|
|
|
|
procedure TJvForthScript.ProcUntil;
|
|
begin
|
|
if not VPop then
|
|
FPC := FCurrentValue;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcRepeat;
|
|
begin
|
|
// do nothing
|
|
end;
|
|
|
|
function TJvForthScript.RPop: Integer;
|
|
begin
|
|
if FRSP <= 0 then
|
|
raise EJvJanScriptError.CreateRes(@RsEReturnStackUnderflow)
|
|
else
|
|
begin
|
|
Dec(FRSP);
|
|
Result := FRStack[FRSP];
|
|
end;
|
|
end;
|
|
|
|
procedure TJvForthScript.RPush(AValue: Integer);
|
|
begin
|
|
FRStack[FRSP] := AValue;
|
|
if FRSP < StackMax then
|
|
Inc(FRSP)
|
|
else
|
|
raise EJvJanScriptError.CreateRes(@RsEReturnStackOverflow);
|
|
end;
|
|
|
|
procedure TJvForthScript.SetScriptTimeOut(const Value: Integer);
|
|
begin
|
|
FScriptTimeOut := Value;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcEndsub;
|
|
begin
|
|
FPC := RPop;
|
|
end;
|
|
|
|
// just skip till endSub
|
|
|
|
procedure TJvForthScript.ProcSub;
|
|
var
|
|
C: Integer;
|
|
Token: TToken;
|
|
begin
|
|
{ TODO -oJVCL -cPOSSIBLEBUG : (p3) What should "c" really be here? }
|
|
C := FAtoms.Count; //??
|
|
while FPC < C do
|
|
begin
|
|
Token := TAtom(FAtoms[FPC]).Token;
|
|
if Token = dfoEndSub then
|
|
begin
|
|
Inc(FPC);
|
|
Exit;
|
|
end;
|
|
Inc(FPC);
|
|
end;
|
|
end;
|
|
|
|
// call to a user sub, just look it up
|
|
|
|
procedure TJvForthScript.ProcCall;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
// Index:=FSubsList.IndexOf(FCurrentSymbol);
|
|
Index := FCurrentValue;
|
|
if Index <> -1 then
|
|
begin
|
|
RPush(FPC);
|
|
// FPC:=Integer(FsubsList.Objects[Index]);
|
|
FPC := Index;
|
|
Exit;
|
|
end
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEProceduresNotDefined, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarGet;
|
|
var
|
|
V: Variant;
|
|
begin
|
|
V := FVarsList.GetVariable(FCurrentSymbol);
|
|
if V <> null then
|
|
VPush(V)
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarSet;
|
|
var
|
|
V: Variant;
|
|
begin
|
|
V := VPop;
|
|
FVarsList.SetVariable(FCurrentSymbol, V);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcCStr;
|
|
var
|
|
S: string;
|
|
begin
|
|
S := VPop;
|
|
VPush(S);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSysGet;
|
|
var
|
|
Value: Variant;
|
|
Handled: Boolean;
|
|
Err, Prompt: string;
|
|
begin
|
|
Prompt := VPop;
|
|
Handled := False;
|
|
Err := Format(RsESystemsNotDefined, [FCurrentSymbol]);
|
|
if Assigned(OnGetSystem) then
|
|
OnGetSystem(Self, FCurrentSymbol, Prompt, Value, Handled, Err);
|
|
if not Handled then
|
|
raise EJvJanScriptError.Create(Err)
|
|
else
|
|
VPush(Value);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSysSet;
|
|
var
|
|
Value: Variant;
|
|
Handled: Boolean;
|
|
Err: string;
|
|
begin
|
|
Value := VPop;
|
|
VPush(Value);
|
|
Handled := False;
|
|
Err := Format(RsECanNotAssignSystems, [FCurrentSymbol]);
|
|
if Assigned(FOnSetSystem) then
|
|
begin
|
|
FOnSetSystem(Self, FCurrentSymbol, Value, Handled, Err);
|
|
if not Handled then
|
|
raise EJvJanScriptError.Create(Err);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvForthScript.SetOnGetSystem(const Value: TOnGetSystem);
|
|
begin
|
|
FOnGetSystem := Value;
|
|
end;
|
|
|
|
procedure TJvForthScript.SetOnSetSystem(const Value: TOnSetSystem);
|
|
begin
|
|
FOnSetSystem := Value;
|
|
end;
|
|
|
|
function TJvForthScript.PopValue: Variant;
|
|
begin
|
|
Result := VPop;
|
|
end;
|
|
|
|
procedure TJvForthScript.PushValue(AValue: Variant);
|
|
begin
|
|
VPush(AValue);
|
|
end;
|
|
|
|
function TJvForthScript.CanPopValue: Boolean;
|
|
begin
|
|
Result := FVSP > 0;
|
|
end;
|
|
|
|
function TJvForthScript.CanPushValue: Boolean;
|
|
begin
|
|
Result := FVSP < StackMax;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcPi;
|
|
begin
|
|
VPush(Pi);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcDSO;
|
|
var
|
|
AName, AMethod: string;
|
|
Table: TJvJanDSO;
|
|
AField, AValue: string;
|
|
AKey: Variant;
|
|
C: Integer;
|
|
begin
|
|
AName := FCurrentSymbol;
|
|
AMethod := FCurrentValue;
|
|
Table := FDSOList.Table(AName);
|
|
if AMethod = 'set' then
|
|
begin
|
|
AKey := VPop;
|
|
AField := VPop;
|
|
AValue := VPop;
|
|
Table.SetValue(AKey, AField, AValue);
|
|
end
|
|
else
|
|
if AMethod = 'get' then
|
|
begin
|
|
AKey := VPop;
|
|
AField := VPop;
|
|
AValue := Table.GetValue(AKey, AField);
|
|
VPush(AValue);
|
|
end
|
|
else
|
|
if AMethod = 'load' then
|
|
Table.LoadFromFile(FDSOBase + PathDelim + AName + '.txt')
|
|
else
|
|
if AMethod = 'save' then
|
|
Table.SaveToFile(FDSOBase + PathDelim + AName + '.txt')
|
|
else
|
|
if AMethod = 'Clear' then
|
|
Table.Clear
|
|
else
|
|
if AMethod = 'Count' then
|
|
begin
|
|
C := Table.Count;
|
|
VPush(C);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcDSOBase;
|
|
var
|
|
S: string;
|
|
begin
|
|
S := VPop;
|
|
FDSOBase := S;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSelDir;
|
|
{$IFDEF VCL}
|
|
var
|
|
Dir: string;
|
|
begin
|
|
Dir := FDSOBase;
|
|
if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt], 0) then
|
|
FDSOBase := Dir;
|
|
end;
|
|
{$ENDIF VCL}
|
|
{$IFDEF VisualCLX}
|
|
var
|
|
Dir: WideString;
|
|
begin
|
|
Dir := FDSOBase;
|
|
if SelectDirectory('Select Directory', PathDelim, Dir {$IFDEF UNIX}, True {$ENDIF}) then
|
|
FDSOBase := Dir;
|
|
end;
|
|
{$ENDIF VisualCLX}
|
|
|
|
procedure TJvForthScript.ProcExtVar;
|
|
var
|
|
AName, AMethod: string;
|
|
begin
|
|
AName := FCurrentSymbol;
|
|
AMethod := FCurrentValue;
|
|
if AMethod = 'set' then
|
|
ProcAssign
|
|
else
|
|
if AMethod = 'get' then
|
|
ProcVariable
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEUnrecognizedExternalVariableMethodss, [AName, AMethod]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcIntVar;
|
|
var
|
|
AName, AMethod: string;
|
|
begin
|
|
AName := FCurrentSymbol;
|
|
AMethod := FCurrentValue;
|
|
if AMethod = 'set' then
|
|
ProcVarSet
|
|
else
|
|
if AMethod = 'get' then
|
|
ProcVarGet
|
|
else
|
|
if AMethod = '1+' then
|
|
ProcVarInc
|
|
else
|
|
if AMethod = '[1+]' then
|
|
ProcVarIncIndex
|
|
else
|
|
if AMethod = '1-' then
|
|
ProcVarDec
|
|
else
|
|
if AMethod = '1-?0' then
|
|
ProcVarDecTestZero
|
|
else
|
|
if AMethod = '+' then
|
|
ProcVarAdd
|
|
else
|
|
if AMethod = '-' then
|
|
ProcVarSub
|
|
else
|
|
if AMethod = '*' then
|
|
ProcVarMul
|
|
else
|
|
if AMethod = '/' then
|
|
ProcVarDiv
|
|
else
|
|
if AMethod = '--' then
|
|
ProcVarNeg
|
|
else
|
|
if AMethod = 'load' then
|
|
ProcVarLoad
|
|
else
|
|
if AMethod = 'save' then
|
|
ProcVarSave
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEUnrecognizedInternalVariableMethodss, [AName, AMethod]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcSystem;
|
|
var
|
|
AName, AMethod: string;
|
|
begin
|
|
AName := FCurrentSymbol;
|
|
AMethod := FCurrentValue;
|
|
if AMethod = 'set' then
|
|
ProcSysSet
|
|
else
|
|
if AMethod = 'get' then
|
|
ProcSysGet
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEUnrecognizedSystemMethodss, [AName, AMethod]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarDec;
|
|
var
|
|
VO: TVariantObject;
|
|
begin
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
VO.Value := VO.Value - 1
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarInc;
|
|
var
|
|
VO: TVariantObject;
|
|
begin
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
VO.Value := VO.Value + 1
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarAdd;
|
|
var
|
|
VO: TVariantObject;
|
|
begin
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
VO.Value := VO.Value + VPop
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarDiv;
|
|
var
|
|
VO: TVariantObject;
|
|
begin
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
VO.Value := VO.Value / VPop
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarMul;
|
|
var
|
|
VO: TVariantObject;
|
|
begin
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
VO.Value := VO.Value * VPop
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarSub;
|
|
var
|
|
VO: TVariantObject;
|
|
begin
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
VO.Value := VO.Value - VPop
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarNeg;
|
|
var
|
|
VO: TVariantObject;
|
|
begin
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
VO.Value := 0 - VO.Value
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcPower;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(Power(VPop, Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcAbs;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(Abs(Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.SetOnInclude(const Value: TOnInclude);
|
|
begin
|
|
FOnInclude := Value;
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcTan;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(Tan(Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcArcCos;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(ArcCos(Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcArcSin;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(ArcSin(Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcArcTan;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(ArcTan(Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcArcTan2;
|
|
var
|
|
Value: Variant;
|
|
begin
|
|
Value := VPop;
|
|
VPush(ArcTan2(VPop, Value));
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarLoad;
|
|
var
|
|
VO: TVariantObject;
|
|
AP, FN, S: string;
|
|
begin
|
|
FN := VPop;
|
|
AP := ExtractFilePath(ParamStr(0));
|
|
FN := StringReplace(FN, '%', AP, []);
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
begin
|
|
S := LoadString(FN);
|
|
VO.Value := S;
|
|
end
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarSave;
|
|
var
|
|
VO: TVariantObject;
|
|
AP, FN, S: string;
|
|
begin
|
|
FN := VPop;
|
|
AP := ExtractFilePath(ParamStr(0));
|
|
FN := StringReplace(FN, '%', AP, []);
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
begin
|
|
S := VO.Value;
|
|
SaveString(FN, S);
|
|
end
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcXML;
|
|
var
|
|
AName, AMethod: string;
|
|
XmlDSO: TJvXMLTree;
|
|
N: TJvXMLNode;
|
|
A: TJvXMLAttribute;
|
|
APath, AtName: string;
|
|
AValue: Variant;
|
|
C, I, C2: Integer;
|
|
ApplDir: string;
|
|
B: Boolean;
|
|
begin
|
|
N := nil;
|
|
ApplDir := ExtractFilePath(ParamStr(0));
|
|
AName := FCurrentSymbol;
|
|
AMethod := FCurrentValue;
|
|
XmlDSO := FXMLList.Xml(AName);
|
|
if AMethod = 'set' then
|
|
begin
|
|
APath := VPop;
|
|
AValue := VPop;
|
|
N := XmlDSO.ForceNamePathNode(APath);
|
|
N.Value := AValue;
|
|
end
|
|
else
|
|
if AMethod = '@set' then
|
|
begin
|
|
APath := VPop;
|
|
AtName := VPop;
|
|
AValue := VPop;
|
|
XmlDSO.ForceNamePathNodeAttribute(APath, AtName, AValue);
|
|
end
|
|
else
|
|
if AMethod = 'get' then
|
|
begin
|
|
APath := VPop;
|
|
N := XmlDSO.GetNamePathNode(APath);
|
|
if N = nil then
|
|
AValue := ''
|
|
else
|
|
AValue := N.Value;
|
|
VPush(AValue);
|
|
end
|
|
else
|
|
if AMethod = 'Count' then
|
|
begin
|
|
APath := VPop;
|
|
N := XmlDSO.GetNamePathNode(APath);
|
|
AValue := 0;
|
|
C2 := 0;
|
|
if N <> nil then
|
|
begin
|
|
// now Count named node
|
|
C := N.Nodes.Count;
|
|
APath := VPop;
|
|
if C > 0 then
|
|
begin
|
|
for I := 0 to C - 1 do
|
|
if TJvXMLNode(N.Nodes[I]).Name = APath then
|
|
Inc(C2);
|
|
end;
|
|
AValue := C2;
|
|
end;
|
|
VPush(AValue);
|
|
end
|
|
else
|
|
if AMethod = '@get' then
|
|
begin
|
|
APath := VPop;
|
|
AtName := VPop;
|
|
A := XmlDSO.GetNamePathNodeAttribute(APath, AtName);
|
|
if N = nil then
|
|
AValue := ''
|
|
else
|
|
AValue := A.Value;
|
|
VPush(AValue);
|
|
end
|
|
else
|
|
if AMethod = 'load' then
|
|
begin
|
|
APath := VPop;
|
|
APath := StringReplace(APath, '%', ApplDir, []);
|
|
if not FileExists(APath) then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEFilesDoesNotExist, [APath]);
|
|
XmlDSO.LoadFromFile(APath);
|
|
end
|
|
else
|
|
if AMethod = 'save' then
|
|
begin
|
|
APath := VPop;
|
|
APath := StringReplace(APath, '%', ApplDir, []);
|
|
try
|
|
XmlDSO.SaveToFile(APath);
|
|
except
|
|
raise EJvJanScriptError.CreateResFmt(@RsECanNotSaveToFiles, [APath]);
|
|
end
|
|
end
|
|
else
|
|
if AMethod = 'astext' then
|
|
begin
|
|
AValue := XmlDSO.AsText;
|
|
VPush(AValue);
|
|
end
|
|
else
|
|
if AMethod = 'Delete' then
|
|
begin
|
|
APath := VPop;
|
|
XmlDSO.deleteNamePathNode(APath);
|
|
end
|
|
else
|
|
if AMethod = '@Delete' then
|
|
begin
|
|
APath := VPop;
|
|
AtName := VPop;
|
|
XmlDSO.DeleteNamePathNodeAttribute(APath, AtName);
|
|
end
|
|
else
|
|
if AMethod = 'select' then
|
|
begin
|
|
APath := VPop;
|
|
APath := StringReplace(APath, '''', '"', [rfReplaceAll]);
|
|
FXMLSelect.Clear;
|
|
FXMLSelectRecord := -1;
|
|
XmlDSO.SelectNodes(APath, FXMLSelect);
|
|
VPush(FXMLSelect.Count > 0);
|
|
end
|
|
else
|
|
if AMethod = 'selectfirst' then
|
|
begin
|
|
B := FXMLSelect.Count <> 0;
|
|
if B then
|
|
FXMLSelectRecord := 0
|
|
else
|
|
FXMLSelectRecord := -1;
|
|
AValue := B;
|
|
VPush(AValue);
|
|
end
|
|
else
|
|
if AMethod = 'selectnext' then
|
|
begin
|
|
B := FXMLSelect.Count <> 0;
|
|
if B then
|
|
Inc(FXMLSelectRecord)
|
|
else
|
|
FXMLSelectRecord := -1;
|
|
if FXMLSelectRecord >= FXMLSelect.Count then
|
|
begin
|
|
B := False;
|
|
FXMLSelectRecord := -1;
|
|
end;
|
|
AValue := B;
|
|
VPush(AValue);
|
|
end
|
|
else
|
|
if AMethod = 'selectget' then
|
|
begin
|
|
if FXMLSelect.Count = 0 then
|
|
raise EJvJanScriptError.CreateRes(@RsEXMLSelectionIsEmpty);
|
|
if FXMLSelectRecord = -1 then
|
|
raise EJvJanScriptError.CreateRes(@RsENoXMLSelectionSelected);
|
|
if FXMLSelectRecord >= FXMLSelect.Count then
|
|
raise EJvJanScriptError.CreateRes(@RsEXMLSelectionOutOfRange);
|
|
N := TJvXMLNode(FXMLSelect[FXMLSelectRecord]);
|
|
AValue := N.Value;
|
|
VPush(AValue);
|
|
end
|
|
else
|
|
if AMethod = '@selectget' then
|
|
begin
|
|
if FXMLSelect.Count = 0 then
|
|
raise EJvJanScriptError.CreateRes(@RsEXMLSelectionIsEmpty);
|
|
if FXMLSelectRecord = -1 then
|
|
raise EJvJanScriptError.CreateRes(@RsENoXMLSelectionSelected);
|
|
if FXMLSelectRecord >= FXMLSelect.Count then
|
|
raise EJvJanScriptError.CreateRes(@RsEXMLSelectionOutOfRange);
|
|
N := TJvXMLNode(FXMLSelect[FXMLSelectRecord]);
|
|
AtName := VPop;
|
|
AValue := N.GetAttributeValue(AtName);
|
|
VPush(AValue);
|
|
end
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEInvalidXmlMethodSpecifiers, [AMethod]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarDecTestZero;
|
|
var
|
|
V: Variant;
|
|
VO: TVariantObject;
|
|
begin
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
begin
|
|
V := VO.Value - 1;
|
|
VO.Value := V;
|
|
VPush(V = 0);
|
|
end
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcVarIncIndex;
|
|
var
|
|
VO: TVariantObject;
|
|
S, SIdx: string;
|
|
PB, PE: Integer;
|
|
Index: Integer;
|
|
begin
|
|
VO := FVarsList.GetObject(FCurrentSymbol);
|
|
if VO <> nil then
|
|
begin
|
|
S := VO.Value;
|
|
PB := LastPosChar('[', S);
|
|
if PB = 0 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEIncrementIndexExpectedIns, [S]);
|
|
PE := LastPosChar(']', S);
|
|
if PE = 0 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEIncrementIndexExpectedIns_, [S]);
|
|
SIdx := Copy(S, PB + 1, PE - PB - 1);
|
|
try
|
|
Index := StrToInt(SIdx);
|
|
Inc(Index);
|
|
S := Copy(S, 1, PB - 1) + '[' + IntToStr(Index) + ']';
|
|
VO.Value := S;
|
|
VPush(S);
|
|
except
|
|
raise EJvJanScriptError.CreateResFmt(@RsEIncrementIndexExpectedIntegerBetwee, [S]);
|
|
end;
|
|
end
|
|
else
|
|
raise EJvJanScriptError.CreateResFmt(@RsEVariablesNotDefined_, [FCurrentSymbol]);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcCrLf;
|
|
begin
|
|
VPush(sLineBreak);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcShellExecute;
|
|
var
|
|
AFile: string;
|
|
ApplDir: string;
|
|
begin
|
|
ApplDir := ExtractFilePath(ParamStr(0));
|
|
AFile := VPop;
|
|
AFile := StringReplace(AFile, '%', ApplDir, []);
|
|
Launch(AFile);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcDateStr;
|
|
var
|
|
S: string;
|
|
begin
|
|
S := FormatDateTime('dd-mmm-yyyy', Now);
|
|
VPush(S);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcTimeStr;
|
|
var
|
|
S: string;
|
|
begin
|
|
S := FormatDateTime('hh:nn:ss', Now);
|
|
VPush(S);
|
|
end;
|
|
|
|
procedure TJvForthScript.ProcNow;
|
|
begin
|
|
VPush(Now);
|
|
end;
|
|
|
|
//=== { TAtom } ==============================================================
|
|
|
|
procedure TAtom.SetIsOperand(const Value: Boolean);
|
|
begin
|
|
FIsOperand := Value;
|
|
end;
|
|
|
|
procedure TAtom.SetToken(const Value: TToken);
|
|
begin
|
|
FToken := Value;
|
|
end;
|
|
|
|
procedure TAtom.SetProc(const Value: TProcVar);
|
|
begin
|
|
FProc := Value;
|
|
end;
|
|
|
|
procedure TAtom.SetSymbol(const Value: string);
|
|
begin
|
|
FSymbol := Value;
|
|
end;
|
|
|
|
procedure TAtom.SetValue(const Value: Variant);
|
|
begin
|
|
FValue := Value;
|
|
end;
|
|
|
|
//=== { TAtomList } ==========================================================
|
|
|
|
procedure TAtomList.ClearObjects;
|
|
var
|
|
I, C: Integer;
|
|
begin
|
|
C := Count;
|
|
if C = 0 then
|
|
Exit;
|
|
for I := 0 to C - 1 do
|
|
TAtom(Items[I]).Free;
|
|
Clear;
|
|
end;
|
|
|
|
destructor TAtomList.Destroy;
|
|
begin
|
|
ClearObjects;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
//=== { TVariantObject } =====================================================
|
|
|
|
procedure TVariantObject.SetValue(const Value: Variant);
|
|
begin
|
|
FValue := Value;
|
|
end;
|
|
|
|
//=== { TVariantList } =======================================================
|
|
|
|
procedure TVariantList.ClearObjects;
|
|
var
|
|
I, C: Integer;
|
|
begin
|
|
C := Count;
|
|
if C = 0 then
|
|
Exit;
|
|
for I := 0 to C - 1 do
|
|
TVariantObject(Objects[I]).Free;
|
|
Clear;
|
|
end;
|
|
|
|
destructor TVariantList.Destroy;
|
|
begin
|
|
ClearObjects;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TVariantList.GetObject(const Symbol: string): TVariantObject;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
Result := nil;
|
|
if Count = 0 then
|
|
Exit;
|
|
Index := IndexOf(Symbol);
|
|
if Index = -1 then
|
|
Exit;
|
|
Result := TVariantObject(Objects[Index]);
|
|
end;
|
|
|
|
function TVariantList.GetVariable(const Symbol: string): Variant;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
Result := null;
|
|
if Count = 0 then
|
|
Exit;
|
|
Index := IndexOf(Symbol);
|
|
if Index = -1 then
|
|
Exit;
|
|
Result := TVariantObject(Objects[Index]).Value;
|
|
end;
|
|
|
|
procedure TVariantList.SetVariable(const Symbol: string; AValue: Variant);
|
|
var
|
|
Index: Integer;
|
|
Obj: TVariantObject;
|
|
begin
|
|
Index := IndexOf(Symbol);
|
|
if Index = -1 then
|
|
begin
|
|
Obj := TVariantObject.Create;
|
|
Obj.Value := AValue;
|
|
AddObject(Symbol, Obj);
|
|
end
|
|
else
|
|
begin
|
|
TVariantObject(Objects[Index]).Value := AValue;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvJanDSOList } ======================================================
|
|
|
|
procedure TJvJanDSOList.ClearTables;
|
|
var
|
|
I, C: Integer;
|
|
begin
|
|
C := Count;
|
|
if C <> 0 then
|
|
for I := 0 to C - 1 do
|
|
TJvJanDSO(Objects[I]).Free;
|
|
Clear;
|
|
end;
|
|
|
|
destructor TJvJanDSOList.Destroy;
|
|
begin
|
|
ClearTables;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJvJanDSOList.Table(const AName: string): TJvJanDSO;
|
|
var
|
|
Index: Integer;
|
|
DSO: TJvJanDSO;
|
|
begin
|
|
Index := IndexOf(AName);
|
|
if Index = -1 then
|
|
begin
|
|
DSO := TJvJanDSO.Create;
|
|
AddObject(AName, DSO);
|
|
Result := DSO;
|
|
end
|
|
else
|
|
Result := TJvJanDSO(Objects[Index]);
|
|
end;
|
|
|
|
//=== { TJvJanDSO } ==========================================================
|
|
|
|
function TJvJanDSO.GetValue(AKey: Variant; const AField: string): string;
|
|
var
|
|
Index: Integer;
|
|
Key: string;
|
|
StrKey: Boolean;
|
|
begin
|
|
Key := AKey;
|
|
StrKey := False;
|
|
Index := 0;
|
|
try
|
|
Index := StrToInt(Key)
|
|
except
|
|
StrKey := True;
|
|
end;
|
|
if not StrKey then
|
|
begin
|
|
if Index >= Count then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEDSOIndexOutOfRanged, [Index])
|
|
else
|
|
Result := InternalGetValue(Index, AField);
|
|
end
|
|
else
|
|
begin
|
|
Index := IndexOfName(Key);
|
|
if Index = -1 then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEDSOUnknownKeys, [Key]);
|
|
Result := InternalGetValue(Index, AField);
|
|
end
|
|
end;
|
|
|
|
function TJvJanDSO.InternalGetValue(Index: Integer; const AField: string): string;
|
|
var
|
|
Key, S: string;
|
|
P: Integer;
|
|
begin
|
|
S := Strings[Index];
|
|
P := Pos('=', S);
|
|
Key := Copy(S, 1, P - 1);
|
|
S := Copy(S, P + 1, Length(S));
|
|
Result := GlobalGetValue(S, AField);
|
|
end;
|
|
|
|
procedure TJvJanDSO.InternalSetValue(Index: Integer; const AField, AValue: string);
|
|
var
|
|
Key, S: string;
|
|
P: Integer;
|
|
begin
|
|
S := Strings[Index];
|
|
P := Pos('=', S);
|
|
Key := Copy(S, 1, P - 1);
|
|
S := Copy(S, P + 1, Length(S));
|
|
GlobalSetValue(S, AField, AValue);
|
|
Strings[Index] := Key + '=' + S;
|
|
end;
|
|
|
|
procedure TJvJanDSO.SetValue(AKey: Variant; const AField, AValue: string);
|
|
var
|
|
Index: Integer;
|
|
Key: string;
|
|
StrKey: Boolean;
|
|
begin
|
|
Key := AKey;
|
|
StrKey := False;
|
|
Index := 0;
|
|
try
|
|
Index := StrToInt(Key)
|
|
except
|
|
StrKey := True;
|
|
end;
|
|
if not StrKey then
|
|
begin
|
|
if Index >= Count then
|
|
raise EJvJanScriptError.CreateResFmt(@RsEDSOIndexOutOfRanged, [Index])
|
|
else
|
|
InternalSetValue(Index, AField, AValue);
|
|
end
|
|
else
|
|
begin
|
|
Index := IndexOfName(Key);
|
|
if Index = -1 then
|
|
Index := Add(Key + '=');
|
|
InternalSetValue(Index, AField, AValue);
|
|
end
|
|
end;
|
|
|
|
//=== { TJvJanXMLList } ======================================================
|
|
|
|
procedure TJvJanXMLList.ClearXMLS;
|
|
var
|
|
I, C: Integer;
|
|
begin
|
|
C := Count;
|
|
if C <> 0 then
|
|
for I := 0 to C - 1 do
|
|
TJvXMLTree(Objects[I]).Free;
|
|
Clear;
|
|
end;
|
|
|
|
destructor TJvJanXMLList.Destroy;
|
|
begin
|
|
ClearXMLS;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJvJanXMLList.Xml(const AName: string): TJvXMLTree;
|
|
var
|
|
Index: Integer;
|
|
XmlDSO: TJvXMLTree;
|
|
begin
|
|
Index := IndexOf(AName);
|
|
if Index = -1 then
|
|
begin
|
|
XmlDSO := TJvXMLTree.Create(AName, '', nil);
|
|
AddObject(AName, XmlDSO);
|
|
Result := XmlDSO;
|
|
end
|
|
else
|
|
Result := TJvXMLTree(Objects[Index]);
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|