2010-12-30 23 views
4

私はカスタムLISPインタープリタを開発しています。 LISPのような関数を定義することはできませんが、すべての関数はCの関数にマッピングされます。それはC関数への可変引数LISP関数のマッピング - C

(substr 'input '1 '1) 

、のような表現を見つけると、それは内部substr関数を呼び出して結果を返すことを知っています。

今、基本的な書式設定をサポートし、出力をstdoutに書き込むmessage関数を実装する予定です。何かのように、

(message "Hello, %s" name) 

%sは、変数nameの値に置き換えられます。

現在の計画では、フォーマットと引数をprintfのような関数に直接渡します。そのようにして、printfがサポートするすべての形式をサポートできます。しかし、問題にはさまざまな議論があります。 1つの方法は次のようなものになります

if(argcount == 1) 
    /* call printf with one arg */ 
else if(argcount == 2) 
    /* call printf with two arg */ 
.... 

これは機能しますが、これを実現するにはより良い方法があると思いますか?

答えて

2

私はこれを行う方法があるのか​​疑いがあります。その理由は、あなたのlisp関数へのパラメータの数は実行時にしか分かりませんが、C関数への引数の数はコンパイル時に知る必要があるからです。

これは、特定の種類のプラットフォーム固有の方法でハッキングしない限り、va_listsを含みます。

あなたが本当にできることは、一度に1つずつ引数をループして何かを行うことができる関数をC言語で書くことです。私がこれを見ることができる唯一の方法は、それぞれの内部関数の関数ポインタを格納するのではなく、通常の方法でパラメータを取るかどうか、またはそれが終了するかどうかに関する情報を与える "呼び出し規約" va_listに相当する

printfのような関数には、printf_wrapperというラッパーがあり、ラッパーへの関数ポインタを格納します。このラッパーは、フォーマット文字列を通常のパラメータとして受け取り、その後に他のパラメータのリストまたは配列(va_listにほぼ類似しています)を受け取ります。

printf_wrapperは、printf_wrapper関数の呼び出し規約を "va_list_type"として指定することで、リストを必要とするパラメータで終了することを示している可能性があります。つまり、通常の固定パラメータが使用され、残りのパラメータはすべてバンドルされます。これをリストとして提供します。

もちろん、書式文字列を複数の書式文字列に分割して解析できるprintf_wrapper関数を書くことは少しの作業です。私は自分のカスタム書式指定子を追加することができるように、ここで私は正確にこれをした場所の例を示します。

https://github.com/wbhart/bsdnt/blob/v0.26/helper.c

+0

ありがとう。私はあなたのコードを見ていきます。 –

0

C関数には、argc/argvのようなパラメータがあります。つまり、パラメータの数を指定するパラメータをとり、各パラメータのポインタのリストへのポインタを取得します。

+0

私はこれを理解しています。しかし、問題は 'printf'やそれに類する既存の関数を内部的に使用しなければならないことです。 –

+0

代わりに 'vprintf()'を使ってください。 –

+0

さて、 'vprintf'は' va_list'を必要とします。私は議論からそれを作ることができると思いますか? –

0

のif-elseチェーンよりもわずかに良いがスイッチだろう。

switch(argcount){ 
    case 1: printf(arg[0]); break; 
    case 2: printf(arg[0],arg[1]); break; 
    //etc. 
}