C で書かれた関数を呼び出すことができる「単純な」プログラミング言語を書きたいと考えています。たとえば、その言語をソケット ライブラリと統合したいと考えています。
カスタム プログラミング言語から C 関数を呼び出す最も簡単な方法は何ですか?
注: これは、複数の言語が 1 つのプロジェクトでどのように対話しますか? に似ています。、しかし、この質問が、相互運用性のために言語を設計する最も簡単な方法にもっと焦点を当てていることを願っています.
C で書かれた関数を呼び出すことができる「単純な」プログラミング言語を書きたいと考えています。たとえば、その言語をソケット ライブラリと統合したいと考えています。
カスタム プログラミング言語から C 関数を呼び出す最も簡単な方法は何ですか?
注: これは、複数の言語が 1 つのプロジェクトでどのように対話しますか? に似ています。、しかし、この質問が、相互運用性のために言語を設計する最も簡単な方法にもっと焦点を当てていることを願っています.
1. ハードでユニバーサルな「一度書けばどこでも実行できる」アプローチ:
あなたのプログラミング言語は、使用するC関数の宣言を何らかの方法で提供することをユーザーに強制します(おそらく動的にリンク可能/ロード可能なライブラリとしての実装と同様に)。プログラミング言語のパーサー/コンパイラ/インタープリターは関数シグネチャを解釈し、おそらくlibFFIなどの外部関数インターフェイス ライブラリを使用して、プラットフォームの ABI および C 呼び出し規約に従う呼び出しを行います。このようにして、バインディングを記述せずに、言語内から任意の C 関数を呼び出すことができます。
このメソッドは、いくつかのプログラミング言語で使用されています。たとえば、PyObjCは、Python プログラマーが Python から Objective-C API を直接呼び出すことを可能にするライブラリです。
2.簡単で、普遍的ではない、「使いたいだけ何度でも書く」方法:
プログラミング言語のユーザーが、事前に指定された署名を使用して C 拡張関数を作成する必要があります。つまり、すべてのプログラミング言語拡張機能は次のようになります。
GenericValueType *extension_function(int argc, GenericValueType **argv);
そして、他のコードをプログラミング言語に接続したい人は誰でも、関数とプログラミング言語の専用 API を使用してバインディングを作成する必要があります。たとえばstrlen()
、C 標準ライブラリの関数を使用する場合は、次の (疑似) コードを記述します。
GenericValueType *my_ext_strlen(int argc, GenericValueType **argv)
{
GenericValueType *arg1 = argv[0];
const char *input = ValueToCString(arg1);
size_t len = strlen(input);
return NewValueFromInteger(len);
}
これは、言語の作成者にとって実装が簡単ですが、前述したように、普遍的ではありません.すべての関数は、互換性を保つためにバインド/移植する必要があります. これは、ほとんどのスクリプト言語が採用しているアプローチです。たとえば、Python、PHP、Lua では、外部ライブラリへのバインディングをこの方法で記述する必要があります。
この答えはあまりにも明白に思えるかもしれませんが、真実です。言語は、C プログラムが同じ関数を呼び出すために使用するのと同じマシン命令を (何らかの方法で) 生成して実行することにより、C の関数を呼び出すことができます。新しい言語にマシン コードを出力するコンパイラがある場合、C と同じ呼び出し規則をすべてに使用するように実際に設計できるため、C 関数を簡単に呼び出すだけでなく、C コードからその言語で記述された関数を簡単に呼び出すことができます。 .
これは、x86 プロセッサで C (およびその他の言語) の関数を呼び出すために使用される標準メカニズムに関する情報を含む Wiki ページです。少し調べてみると、関心のある他のプロセッサやアーキテクチャについても同様の規則が見つかります。