私は現在、以下に基づいて式エバリュエーター(式のような単一行式)を実装しています。
私のエバリュエーターはうまく機能していますが、if()
がまだ足りず、どうすればよいのか疑問に思っています。
私のシャントヤードポストフィックスとスタックベースの評価で、if()
をtrueとfalseの部分を持つ別の関数として追加すると、単一のif(true, msgbox("ok"), msgbox("not ok"))
が両方のメッセージを表示し、表示したい唯一。これは、関数を評価する必要がある場合、その引数はすべて評価済みでスタックに配置されているためです。
if()
を遅延して実装する方法を教えていただけませんか?
私はこれらを一種のマクロとして処理することを考えましたが、初期の段階ではまだ条件評価ができていません。おそらく、キューとは別の種類の構造を使用して、条件とtrue/false式を別々に保持する必要があるのでしょうか?今のところ、式は評価の前に解析されますが、将来の評価のために中間表現を一種のプリコンパイルされた式として保存することも計画しています。
編集:問題の後で、式のツリー表現を構築できると思います(線形トークンストリームの代わりにAST))。 if()
のブランチを簡単に無視できます。
ここには2つのオプションがあります。
1)if
を関数として実装しないでください。特別なセマンティクスを持つ言語機能にします。簡単ですが、すべてを機能にしたい場合は、「純粋」ではありません。
2)「名前で呼び出す」セマンティクスを実装します。これははるかに複雑ですが、if
を言語要素ではなく関数として保持しながら、コンパイラーマジックで遅延評価問題を処理できます。こんなふうになります:
if
は2つのパラメーターを取る関数で、どちらも「名前で」宣言されています。コンパイラがby-nameパラメータに何かを渡していることを検出すると、生成されるコードを変更します。式を評価して値を渡す代わりに、式を評価するクロージャーを作成し、それを渡します。また、関数内でby-nameパラメーターを呼び出すと、コンパイラーはクロージャーを評価するコードを生成します。
シグネチャを持つ関数ではなく、
object if(bool, object, object)
署名を付けます:
object if(bool, object function(), object function())
次に、if
関数は条件に基づいて適切な関数を呼び出し、そのうちの1つのみを評価します。
すべてをレイジーにコンパイルすれば、それは非常に簡単です。値がすでに評価されているかどうか、またはさらに評価が必要かどうかを確認する手段が必要です。
次に、次の操作を実行できます。リテラルまたは変数の場合(それらはありますか?つまり、関数の名前ですか?)、スタックにプッシュします。関数のアプリケーションの場合は、個別にコンパイルし、スタックにエントリポイントをプッシュします。
したがって、プログラムの実行は、スタックではなく関数が評価されるまでループするだけです。評価されていない場合や関数の場合は、スタックの一番上を指すコードを呼び出します。