RemObjects Pascal Script使用說明 (转载)

RemObjects Pascal Script使用說明 (转载)
2007-09-20 11:19

来源: http://blog.csdn.net/truexf/archive/2007/02/28/1516749.aspx

翻譯這篇文章源於我的一個通用工資計算平台的想法,在工資的計算中,不可避免的需要使用到自定義公式,然而對於自定義公式的實現,我自己想了一些,也在網上搜索了很多,解決辦法大致有以下幾種:
1. 自己寫代碼去解析公式。這種方法的缺點是,解析的代碼很難實現,如果公式的功能比較完整,如增加條件判斷或自定義函數。不亞於實現了一個簡單的語言編譯囂或解釋囂。所以,只能實現一些諸如加減乘除之類的簡單公式。
2. 打包成SQL傳給數據庫去執行。這顯然不是一種好辦法。而且需要與特定的數據庫和表結構進行適應。
3. 我想到在foxpro中有宏替換功能&,那不如就借用它的這個功能,即利用foxpro寫一個dll,在這個dll中實現了將字符串轉換成指令執行的功能,然後在delphi中加載這個dll,將公式傳入dll中的函數執行。這應該是一個辦法,但我還沒有去實現它。
4. 內嵌腳本語言。
也只有第四種辦法比較理想的,於是我就找到了RemObjects Pascal Script,安裝,並翻譯了這篇使用說明。
再把應用范圍擴大一點,其實在編譯型程序中嵌入腳本語言可以解決很多應用程序自動化的問題,在了解並實際寫了幾個RemObjects Pascal Script的實從程序後。內心還是蠻興奮的。
使用RemObjects Pascal Script
這篇文章提供了RemObjects Pascal Script的一個概覽,以及說明了如何去創建一些簡單的腳本。
Pascal Script由兩個部分組成:
編譯囂(UPSCompiler.pas)
運行時(uPSRuntime.pas)
這兩部分之間是沒有相互依賴的。你可以直接使用她們,或才你可以透過TPSSCript組件來使用她們,TPSSCript組件在uPSComponent.pas單元中,她對上述兩個部分進行一些包裝以便我們可以很容易的使用。
要使用Pascal Script組件,你首先要將它從組件面板中拖置窗體或module中,然後設置它的script屬性,然後調用它的Compile方法進行編譯,再然後調用它的Execute方法來執行腳本。編譯的errors,hints,warnings可以通過其屬性CompilerMessages取得,這個屬性是一個數組。如果是運行時的錯誤,則可以通過屬性ExecErrorToString取得。
下面的例子將編譯並執行一個空腳本("begin end."):
var
Messages: string;
compiled: boolean;
begin
ce.Script.Text := 'begin end.';
Compiled := Ce.Compile;
for i := 0 to ce.CompilerMessageCount -1 do
      Messages := Messages +
                  ce.CompilerMessages[i].MessageToString +
                  #13#10;
if Compiled then
      Messages := Messages + 'Succesfully compiled'#13#10;
ShowMessage('Compiled Script: '#13#10+Messages);
if Compiled then begin
      if Ce.Execute then
        ShowMessage('Succesfully Executed')
      else
        ShowMessage('Error while executing script: '+
                    Ce.ExecErrorToString);
end;
end;
缺省情況下,組件只加入一少部分標准的functions到腳本引擎中(具體可以在uPSComponents.pas單元頭中找到)
除了這些標准的functions之外,Pascal Script還包含了一少部分程式庫:
TPSDllPlugin        允許腳本可以使用外部DLL函數,其調用語法類似下例:
function FindWindow(C1, C2: PChar): Longint; external '[email protected] stdcall';
TPSImport_Classes 導入對應於TObject和Classes單元的libraries;
TPSImport_DateUtils      導入日期時間相關的libraries;
TPSImport_ComObj 在腳本中訪問COM對象;
TPSImport_DB        導入對應於db.pas單元的libraries;
TPSImport_Forms     導入對應於Forms和Menus單元的libraries;
TPSImport_Controls 導入對應於Controls.pas和Graphics.pas單元的libraries;
TPSImport_StdCtrls 導入對應於ExtCtrls和Buttons的libraries.
要使用這些libraries,將它們從組件面板中拖至窗體數據data module中,然後設置TPSCompiler的plugins屬性,在其中增加條目,並將條目指向這些plugin組件。
除了這些標准的libraries之外,你還可以很方便地向腳本引擎中添加新的函數。要做到這一點,創建一個你要加入到腳本中的method,如下例:
procedure TForm1.ShowNewMessage(const Message: string);
begin
ShowMessage('ShowNewMessage invoked:'#13#10+Message);
end;
然後,在TPSCompiler 的OnCompile事件中將該方法添加入腳本中:
procedure TForm1.CECompile(Sender: TPSScript);
begin
Sender.AddMethod(Self, @TForm1.ShowNewMessage,
                     'procedure ShowNewMessage
                     (const Message: string);');
end;
這樣, 你就可以在腳本中使用這個函數,如下:
begin
ShowNewMessage('Show This !');
end.
高級功能
Pascal Script包含了一個預處理程序,以便你可以在腳本中使用編譯預定義(defines)({$IFDEF}, {$ELSE}, {$ENDIF}) 以及在腳本中包含其它腳本 ({$I filename.inc})。要達到這個功能,你需要設置UsePreprocessor屬性為true,and the MainFileName property to match the name of the script in the Script property. 。Defines屬性指定要缺省時定義哪些defines;OnNeedFile事件代碼在需要包含的文件時被執行。
function TForm1.ceNeedFile(Sender: TObject;
const OrginFileName: String;
var FileName, Output: String): Boolean;
var
path: string;
f: TFileStream;
begin
Path := ExtractFilePath(ParamStr(0)) + FileName;
try
      F := TFileStream.Create(Path, fmOpenRead or fmShareDenyWrite);
except
      Result := false;
      exit;
end;
try
      SetLength(Output, f.Size);
      f.Read(Output[1], Length(Output));
finally
f.Free;
end;
Result := True;
end;
當這些屬性被設置以後,CompilerMessages屬性可就將可能包含這些文件名。
另外,你可以在Delphi中調用腳本裡的函數。如下函數被定義在腳本中,後面將會在delphi中被調用:
function TestFunction(Param1: Double; Data: String): Longint;
begin
ShowNewMessage('Param1: '+FloatToString(param1)
                   +#13#10+'Data: '+Data);
Result := 1234567;
end;
begin
end.
在使用調用這個函數之前,必須對其進行一個校驗,校驗其參數和返回值類型,在OnVerifyProc執行這個校驗。
procedure TForm1.CEVerifyProc(Sender: TPSScript;
                                Proc: TPSInternalProcedure;
                                const Decl: String;
                                var Error: Boolean);
begin
if Proc.Name = 'TESTFUNCTION' then begin
      if not ExportCheck(Sender.Comp, Proc,
                 [btS32, btDouble, btString], [pmIn, pmIn]) then begin
        Sender.Comp.MakeError('', ecCustomError, 'Function header for
        TestFunction does not match.');
        Error := True;
      end
      else begin
        Error := False;
      end;
end
else
      Error := False;
end;
ExportCheck函數檢查參數的匹配情況。在這個例子中,btu8是一個布爾型(返回值類型),btdouble是第一個參數,btString是第二個參數。[pmIn, pmIn]表示兩個參數都是輸入參數。要調用這個腳本函數,你需要為它創建一個函數類型聲明。
type
TTestFunction = function (Param1: Double;
                              Data: String): Longint of object;
//...
var
Meth: TTestFunction;
Meth := TTestFunction(ce.GetProcMethod('TESTFUNCTION'));
if @Meth = nil then
      raise Exception.Create('Unable to call TestFunction');
ShowMessage('Result: '+IntToStr(Meth(pi, DateTimeToStr(Now))));
還可以向腳本引擎中添加變量,然後就可以在腳本中使用這些變量 。要做到這一點,你需要使用AddRegisteredVariable函數。可以在OnExecute設置它:
procedure TForm1.ceExecute(Sender: TPSScript);
begin
CE.SetVarToInstance('SELF', Self);
// ^^^ For class variables
VSetInt(CE.GetVariable('MYVAR'), 1234567);
end;
若要再去讀取這個變量的值,在腳本執行完成後,在OnAfterExecute事件中訪問:
VGetInt(CE.GetVariable('MYVAR')).
注冊一個外部變量到腳本引擎中也是可以的。這需要兩個步驟,首先在OnCompile事件中使用AddRegisteredPTRVariable函數將變量類型添加到腳本中。
procedure TMyForm.PSScriptCompile(Sender: TPSScript);
begin
Sender.AddRegisteredPTRVariable('MyClass', 'TButton');
Sender.AddRegisteredPTRVariable('MyVar', 'Longint');
end;
這樣就注冊了MyClass 和 MyVar這兩個變量。第二步,在OnExecute中通過將變量值的地址指針傳給變量來實現給變量賦值:
procedure TMyForm.PSScriptExecute(Sender: TPSScript);
begin
PSScript.SetPointerToData('MyVar', @MyVar, PSScript.FindBaseType(bts32));
PSScript.SetPointerToData('Memo1', @Memo1, PSScript.FindNamedType('TMemo'));
end;
在Pascal Script中有兩種類型的變量,一種是基本類型,包含一些簡單的類型,下面會列出;另一種是類類型。基本類型是在uPSUtils.pas被注冊進去的,可以通過FindBaseType函數找到。類類型需要使用FindNamedType函數通過名稱找到。改變這些變量將直接地影響到實際的變量。
Base types:
btU8       Byte
btS8       Shortint
btU16      Word
btS16      Smallint
btU32      Longword
btS32      Longint
btS64      Int64
btSingle        Single
btDouble        Double
btExtended      Extended
btVariant       Variant
btString        String
btWideString WideString
btChar    Char
btWideChar      WideChar
Pascal Script組件同樣也支持腳本函數。這通過ExecuteFunction來調用。
ShowMessage(CompExec.ExecuteFunction([1234.5678, 4321,
                                        'test'],
                                       'TestFunction'));
這個例子將執行一個名為TestFunction的函數,這個函數包含3個參數,一個float,一個integer和一個string。函數的返回值傳回給ShowMessage。
注意:
一些必要的函數和常量應該被加入到uses 列表中:uPSCompiler.pas, uPSRuntime.pas, uPSUtils.pas;
腳本引擎不會自行調用Application.ProcessMessages,因此在腳本執行時你的應用程序可能會終止。要避免這一點,你可以將Application.ProcessMessages加入到TPSScript的OnLine事件中;
可能需要在腳本中引入你自己的類,Pascal Script包含一個工具以便創建引入的庫,這個工具在Bin目錄中;
安裝目錄中可以找到單獨使用Comiler和Runtim的實例;
腳本調試需要SynEdit http://synedit.sourceforge.net/.

你可能感兴趣的:(String,function,dll,Delphi,pascal,output)