POJ (JVM 上の Pascal) をフォローしていない人のために、 サブセット を Pascal から JASM (Java アセンブリ) を使用して、JVM を実行環境として使用できるようにします。
前回の投稿では、Pascal の 関数のサポートを実装しました。
この投稿では、クールなことについて話しますか?それほどではありません(笑)。今回はバグについてだけ話します :-)
JVM 用にコンパイルしているため、この素晴らしい仮想マシンのさまざまな点の機能を詳しく説明する必要があります。したがって、私はさまざまな機会に、JVM の内部機能とその命令の一部 (opcodes) について詳しく説明します。
変数宣言を実装したとき、JVM では main 関数の最初の変数が args (プログラムに渡される引数を含む配列) であるという事実に注意を払いませんでした。したがって、この PR では、暗黙的に最初の位置を args.
に予約します。テスト用の Pascal プログラムにはグローバル変数のみが含まれていたため、JASM 生成における重大なエラーには気づきませんでした。グローバル変数とローカル変数を含むプログラムを作成した瞬間、何かがおかしいことに気づきました (笑)。
以下の Pascal プログラムより:
program global_var_declaration; var globalvar : integer; begin globalvar := 123; write (globalvar); end.
POJ は次の JASM を生成しました:
// Code generated by POJ 0.1 public class global_var_declaration { public static main([java/lang/String)V { ;; globalvar := 123; bipush 123 istore 1 ;; write (globalvar); getstatic java/lang/System.out java/io/PrintStream iload 1 invokevirtual java/io/PrintStream.print(I)V return } }
問題を特定するために、上記の Pascal プログラムと同等の Java プログラムを作成しました。
public class GlobalVarDeclaration { public static int globalVar; public static void main(String[] args) { globalVar = 123; System.out.println(globalVar); } }
クラスを逆アセンブルすると、次のようなアセンブリ:
が得られました。
1: public class GlobalVarDeclaration { 2: public static globalVar I 3: 4: public static main([java/lang/String)V { 5: bipush 123 6: putstatic GlobalVarDeclaration.globalVar I 7: 8: getstatic java/lang/System.out java/io/PrintStream 9: getstatic GlobalVarDeclaration.globalVar I 10: invokevirtual java/io/PrintStream.println(I)V 11: 12: return 13: } 14: }
この時点で、「public static globalVar I」宣言 (2 行目) と、命令 putstatic (6 行目) および getstatic (行目) に気づきました。 9) 。予期されていたのは、これまで POJ で使用されていた命令 astore および istore でした。 JVM ドキュメントを読んでいると、POJ がグローバル変数を JVM の関数のローカル変数であるかのように宣言していることに気付きました。:-D
とにかく、これまでPOJはopcodes aload/iload/astore/ Istoreを(誤って)使用していました。 はグローバル変数の場合ですが、正しいオプションは変数を public として宣言し (2 行目のように)、getstatic/putstatic.
を使用することです。その結果、シンボル テーブルがローカル宣言とグローバル宣言を処理できるように、ここでコードがリファクタリングされました。そしてここでは、シンボル テーブルがローカル変数とグローバル変数に対して正しい命令を生成できるようにコードがリファクタリングされました。
JASM コード生成は、関数またはプロシージャの終了後にローカル宣言をクリーンアップするだけでなく、新しいシンボル テーブルを処理するためにここで変更されました。
これで、以下の Pascal プログラムから:
program GlobalVarDeclaration; var globalvar : integer; begin globalvar := 123; write (globalvar); end.
POJ は次の JASM を正しく生成するようになりました:
// Code generated by POJ 0.1 public class global_var_declaration { public static globalvar I public static main([java/lang/String)V { ;; globalvar := 123; bipush 123 putstatic global_var_declaration.globalvar I ;; write (globalvar); getstatic java/lang/System.out java/io/PrintStream getstatic global_var_declaration.globalvar I invokevirtual java/io/PrintStream.print(I)V return } }
次の投稿では、コンテキストとネストされた文について説明します。
プロジェクトの完全なコードとドキュメントを含むリポジトリはここにあります。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3