私は、変数が変更されたときに、それらの変数に依存するすべての関数 (およびそれらの関数に依存する関数など) が同時に更新されるように、単純な関数を一緒にバインドできるようにする実験的な関数エバリュエーターを作成しました。これを行う方法は、関数が入力されたときにすぐに関数を評価するのではなく、関数を保存することです。出力値が要求されたときのみ関数を評価し、出力値が要求されるたびに評価します。
例えば:
pi = 3.14159
rad = 5
area = pi * rad * rad
perim = 2 * pi * rad
'pi' と 'rad' を変数 (定数を返す関数) として定義し、'area' と 'perim' を関数として定義します。「pi」または「rad」のいずれかが変化するたびに、「area」と「perim」の結果も同じように変化することを期待しています。同様に、「面積」または「周縁」に依存する関数があれば、それらの結果も変化します。
これはすべて期待どおりに機能しています。ここでの問題は、ユーザーが偶発的または意図的に再帰を導入した場合です。私の文法には論理がありません - それは単なる評価器です - そのため、ユーザーに再帰から「抜け出す」方法を提供することはできません。私はそれがまったく起こらないようにしたいと思っています。つまり、それを検出し、問題のある入力を無効であると宣言する方法が必要です。
例えば:
a = b
b = c
c = a
現在、最後の行を評価すると StackOverflowException が発生します (最初の 2 行は「0」と評価されますが、宣言されていない変数/関数は 0 に等しくなります)。私がやりたいことは、循環論理の状況を検出し、ユーザーがそのようなステートメントを入力することを禁止することです。循環ロジックがどれほど深く隠されているかに関係なく、これを実行したいのですが、どうすればよいかわかりません。
ちなみに、舞台裏では、入力文字列は単純なスキャナーを介してトークンに変換され、次に手書きの再帰降下パーサーを介して抽象構文ツリーに変換され、AST が評価されます。言語は C# ですが、コード ソリューションを探しているわけではありません。ロジックだけで十分です。
注: これは、パーサーとコンパイラーがどのように機能するかを学ぶために私が使用している個人的なプロジェクトであるため、ミッション クリティカルではありません。皆さんが提供できるどんな助けも大歓迎です。=)
編集: 誰かが興味を持っている場合は、私のブログのこの投稿で、私がこれを学ぼうとしている理由と、そこから何を得ているかを説明しています。