POJ (JVM 上の Pascal) をフォローしていない人のために説明すると、これは サブセット を Pascal から JASM に変換するコンパイラーです ( Java アセンブリ) を使用して、JVM を実行環境として使用できるようにします。
前回の投稿では、特に アセンブリ の生成におけるいくつかの重要なバグを解決しました。この投稿では、ネストされた文の アセンブリ を正しく生成する方法について説明します。
JVM 用にコンパイルしているので、この素晴らしい仮想マシンのさまざまな点の機能を詳しく説明する必要があります。したがって、私はさまざまな機会に、JVM の内部機能とその命令 (オペコード) の一部について詳しく説明します。
ネストされた文を正しく処理するために必要な機能の 1 つは、パーサー に複数のコンテキストを含めることができることです。これは、パーサーが 1 つのコンテキストのみを想定している場合、ラベル を生成してジャンプするネストされた制御文 (if、for、while および repeat) は、ジャンプ アドレス指定を正しく生成しませんでした。
コンテキストを処理するには、次の 2 つの方法があります。
パーサー アプローチを使用します。ただし、ANTLR で再帰的パーサーを実装するには、POJ での文法の構造により、コードを文法に直接挿入する必要がありますが、このアプローチは推奨されません。結果として、私たちはコンテキストを積み重ねるというアプローチを選択しました。
パーサーが JVM でスタック/アンスタックした型を監視するスタック実装がすでに存在したため、特定の型に対して別のスタックを作成する必要がないように、パーサー を 1 つ作成することにしました。 🎜 >スタック この PR のジェネリック。この実装を後で利用できることに加えて、古いコードをリファクタリングして、既存の特定の スタック.
を削除することもできます。この commit では、関数コンテキストを正しくスタック/スタック解除するように パーサー が変更されました。基本的に、関数の パーサー の開始時にコンテキストがスタックされ、最後にコンテキストがアンスタックされます。
if、for、while、repeat などの 制御文は正しく機能しました。ただし、ネストされた文がある場合、POJ はコンテキストを保存せず、誤って ラベル とジャンプを生成してしまいました。 アセンブリ の生成がこれらの制御文に対してどのように機能するかについて、こことここで説明しました。
以下の例では、別の中にネストされた if が含まれていますが、POJ は ラベル と必要なジャンプを誤って生成しました:
program NestedIfs; begin if (1 > 2) then if (2 > 3 ) then writeln('1 > 2 and 2 > 3') else writeln('1 > 2 and 2 <= 3') else writeln('1 <= 2'); end.
このバグは既知であり、パーサーがコンテキストをサポートしたときに解決することにしました。
このコミットでは、次の labels:
を含む LabelsContext 構造が作成されました。アセンブリの正しい生成を検証するために、ネストされたif、ネストされたrepeat、ネストされたwhileおよびforを検証するテストが作成されました。 がネストされています。ここでは、再帰関数の場合に アセンブリ の生成を検証するためにテストが作成されました。さらに、すべての既存のテストの予想されるアセンブリを更新する必要がありました。最後に、この PR では、新しいコンテキスト構造を使用するように parser が更新されました。
これらの変更の完全な PR は次のとおりです。ここには、if 文を正しく機能させるための変更を含む commit があります。ここでの commit は、repeat を参照しています。 commit は while を参照し、ここでの commit は for を参照します。
次の投稿では、データ入力について説明します。このプロジェクトの目的の 1 つである、標準入力から数値を読み取り、その階乗を計算するまで、それほど時間はかかりません。
プロジェクトの完全なコードとドキュメントが含まれるリポジトリはここにあります。
以上が入れ子の文の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。