Componentes.Terceros.jvcl/official/3.32/run/JvForth.pas

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.