Delphi/C++Builderのアプリケーションにプログラム言語を組み込むことができるライブラリ

Delphi/C++Builderのアプリケーションにプログラム言語を組み込むことができるライブラリを調べてみた。

RemObjects Pascal Script

  • 無料
  • Pascal
  • 有名なフリーのインストーラ「Inno Setup」でも使用されている。

Python for Delphi

  • 無料
  • Python
  • 有名なPythonの統合開発環境「PyScripter」でも使用されている。

DelphiWebScript

  • 無料
  • Pascal

JVCL Interpreter

TMS Scripter

  • 有料
  • Pascal/Basic

FastScript

paxCompiler

  • 有料
  • Pascal/Basic/JavaScript

LMD ScriptPack

  • 有料
  • PascalScript/Windows Scripting Host(VB Script, JScript, etc)

FastScriptを使ってみる スクリプトをデバッグする(2)

DelphiのコードからFastScriptの変数の値を取得するには、TfsScriptのVariablesプロパティを使用します。

変数の値を取得する

val := fsScript1.Variables['i'];

変数の値を設定する

変数の値を設定することもできます。

fsScript1.Variables['i'] := 10;

##サンプルアプリケーション

次のプログラムでは1秒ごとに1行ずつ処理を進め、変数の値を表示します。

001

procedure TForm1.fsScript1RunLine(Sender: TfsScript;
  const UnitName, SourcePos: string);
var
  P: TPoint;
  I: Integer;
  VariableName: string;
begin
  // 処理中の行を表示
  StatusBar1.SimpleText := SourcePos;
  P := fsPosToPoint(SourcePos);
  Dec(P.Y);
  fsSyntaxMemo1.SetActiveLine(P.Y);

  // 変数の値を表示
  ValueListEditor1.Strings.BeginUpdate;
  try
    ValueListEditor1.Strings.Clear;
    for I := 0 to fsScript1.Count - 1 do
    begin
      if fsScript1.Items[I] is TfsVariable then
      begin
        VariableName := fsScript1.Items[I].Name;
        ValueListEditor1.Strings.Values[VariableName] :=
          fsScript1.Items[I].Value;
      end;
    end;
  finally
    ValueListEditor1.Strings.EndUpdate;
  end;

  // 1秒待機
  Sleep(1000);
  Application.ProcessMessages;
end;

FastScriptを使ってみる スクリプトをデバッグする

FastScriptのスクリプトをデバッグするアプリケーションを作成してみます。

005

スクリプトを実行するときTfsScriptのOnRunLineイベントが呼ばれます。
引数から実行するコードがわかります。

procedure TForm1.fsScript1RunLine(Sender: TfsScript;
  const UnitName, SourcePos: string);
begin
  …
end;

引数SourcePosはfsPosToPoint関数でTPoint型に変換できます。
TPointのYプロパティに行、Xプロパティに文字の場所が設定されます。

uses
  fs_itools;
var
  p: TPoint;
begin
  p := fsPosToPoint(SourcePos);

取得した実行位置をTfsSyntaxMemoコンポーネントのSetPosプロパティに設定することで、実行しているコードの場所にカーソルを配置できます。

fsSyntaxMemo1.SetPos(p.X, p.Y);

TfsSyntaxMemoコンポーネントのSetActiveLineメソッドに実行している行番号を設定することで、実行中の行をアクティブにできます。

Dec(p.Y);
fsSyntaxMemo1.SetActiveLine(p.Y);

フォームにBoolean型のメンバ変数FExecを追加します。

type
  TForm1 = class(TForm)
  private
    FExec: Boolean;

fsScript1のOnRunLineイベント内でメンバ変数FExecがTrueになるまで、スクリプトの実行を待機します。

FExec := False;
while not FExec do
begin
  Sleep(10);
  Application.ProcessMessages;
end;

fsScript1RunLine関数は次のようになります。

procedure TForm1.fsScript1RunLine(Sender: TfsScript;
  const UnitName, SourcePos: string);
var
  p: TPoint;
begin
  p := fsPosToPoint(SourcePos);
  fsSyntaxMemo1.SetPos(p.X, p.Y);
  Dec(p.Y);
  fsSyntaxMemo1.SetActiveLine(p.Y);
  fsSyntaxMemo1.SetFocus;

  FExec := False;
  while not FExec do
  begin
    Sleep(10);
    Application.ProcessMessages;
  end;
end;

「次の処理へ」ボタンを押したときに、メンバ変数FExecをTrueにします。

procedure TForm1.Button2Click(Sender: TObject);
begin
  FExec := True;
end;

「中止」ボタンを押すと、fsScript1のTerminateメソッドを呼び出し、処理を中止します。

procedure TForm1.Button3Click(Sender: TObject);
begin
  fsScript1.Terminate;
end;

FastScriptを使ってみる DelphiのコードからFastScriptの関数を実行する

DelphiのコードからFastScriptの関数を実行するには、TfsScriptのCallFunctionメソッドを使用します。

最初の引数に関数名、2番目の引数に関数の引数を設定します。

val := fsScript1.CallFunction(
  'ScriptFunc',
  VarArrayOf(['hello', 1]));

次のサンプルコードでは、Script内のPlus関数をDelphiのコードから呼び出します。

var
  Val: Integer;
begin
  fsScript1.Parent := fsGlobalUnit;
  fsScript1.Lines.Add('function Plus(A, B: Integer): Integer;');
  fsScript1.Lines.Add('begin');
  fsScript1.Lines.Add('  Result := A + B;');
  fsScript1.Lines.Add('end;');
  fsScript1.Lines.Add('begin;');
  fsScript1.Lines.Add('end.');

  if not fsScript1.Compile then
  begin
     //文法に間違いがあるとき
    ShowMessage(Format('%s:%s', [fsScript1.ErrorPos, fsScript1.ErrorMsg]));
    Exit;
  end;

  Val := fsScript1.CallFunction('Plus', VarArrayOf([1, 2]));
  ShowMessage(IntToStr(Val));
end;