2

ご存知のように、TCL には次のように()括弧を使用してexprコマンドで呼び出されるsincoshypotなどの数学関数があります。

puts [expr sin(1.57)]

TCLライブラリ関数を使用して関数を追加し、まったく同じ方法で呼び出され、特定のprocが定義することを実行するにはどうすればよいでしょうか。

私の質問を明確にしたいと思います。次のような proc (文字列) があるとします。

proc add { a b } { return [expr $a+$b] } ;# string of a proc

また、私の C++ コードには TCL インタープリターがあります。ここで、proc の文字列を取得し、 addという名前の関数をtcl::mathfunc 名前空間にランタイム登録して(私はTcl_CreateObjCommandを使用する必要があると思います)、以下を呼び出すことができるようにします。

puts [expr add(1.57, 1.43)]

これを行う方法。簡単な例を書いていただけませんか。このコマンドの使用法を説明している例は、TCL のドキュメントや本にも見つかりませんでした。

4

1 に答える 1

3

C から関数を作成することはそれほど難しくありません。そのためには、操作を実行するコマンドの実装を作成し、その実装をコマンドとして正しい名前空間に登録する必要があります。(8.4 以前では、関数は別のインターフェイスで実行されていましたが、これは使用するのがかなり面倒でした。メカニズムは 8.5 で完全に見直されました。)

コマンドの実装

ここでは署名が定義されており、ignoredパラメーターは使用されていないことに注意してください。(コマンドをオブジェクトにバインドするようvoid *なことをしたい場合には非常に便利ですが、追加を行うには必要ありません。)

static int AddCmd(ClientData ignored, Tcl_Interp *interp, int objc,
        Tcl_Obj *const objv[]) {
    double x, y, sum;

    /* First, check number of arguments: command name is objv[0] always */
    if (objc != 3) {
        Tcl_WrongNumArgs(interp, 1, objv, "x y");
        return TCL_ERROR;
    }

    /* Get our arguments as doubles */
    if (    Tcl_GetDoubleFromObj(interp, objv[1], &x) != TCL_OK ||
            Tcl_GetDoubleFromObj(interp, objv[2], &y) != TCL_OK) {
        return TCL_ERROR;
    }

    /* Do the real operation */
    sum = x + y;

    /* Pass the result out */
    Tcl_SetObjResult(interp, Tcl_NewDoubleObj(sum));
    return TCL_OK;
}

ここで値を割り当てているという事実について心配する必要はありません。Tcl には非常に高性能なカスタム メモリ マネージャーがあり、これにより操作が安価になります。

コマンド登録

これは通常、Tcl パッケージ定義の一部として登録される、アプリケーション全体の初期化の一部として呼び出される初期化関数内で行われます。Tcl_CreateInterp手動で呼び出している場合は、直接行うこともできます。どちらを行うかは、Tcl とどのように統合しているかによって異なります。これは、それ自体が非常に大きなトピックです。そこで、初期化関数の作成方法を示します。これは通常、すべてのシナリオで適切なスタートです。

int Add_Init(Tcl_Interp *interp) {
    /* Use the fully-qualified name */
    Tcl_CreateObjCommand(interp, "::tcl::mathfunc::add", AddCmd, NULL, NULL);
    return TCL_OK;
}

1 つ目は、最初の ( ) パラメータとして実装NULLに渡される値です。2 つ目は、 (ここのようにアクションが必要ない場合は NULL)ClientDataを破棄するためのコールバックです。ClientData

これらすべてを C++ から実行することも非常に実用的ですが、Tcl はCライブラリであるため、それらは関数 (メソッドではなく、アダプターなしではなく) である必要があり、C リンケージが必要であることを覚えておいてください。


C (または C++) からプロシージャの本体を取得する最も簡単なメカニズムは、Tcl_Eval実行する単純なスクリプトを使用することinfo body theCmdNameです。プロシージャーの実装は非常に複雑なので、それらへのインターフェースは純粋にスクリプト・レベルにあります (実際に賢明である以上に Tcl に巻き込まれない限り)。

于 2012-06-11T23:37:58.663 に答える