ホームページ >バックエンド開発 >Golang >パスカル関数のサポート

パスカル関数のサポート

王林
王林オリジナル
2024-07-16 08:03:50619ブラウズ

Suporte às funções do Pascal

POJ (JVM 上の Pascal) をフォローしていない人のために説明すると、これは サブセット を Pascal から JASM に変換するコンパイラーです ( Java アセンブリ) を使用して、JVM を実行環境として使用できるようにします。

前回の投稿では、エラー キャプチャ、string 型の関係演算子のサポート、Pascal の プロシージャ の定義 (および使用) の可能性がいくつか改善されました。

この出版物では、Pascal 関数 (関数) のサポートについて説明します。プロジェクトの最後の目標、つまり標準入力から数値を読み取り、その階乗を計算するまであと少しです。

JVM 用にコンパイルしているので、この素晴らしい仮想マシンのさまざまな点の機能を詳しく説明する必要があります。したがって、私はさまざまな機会に、JVM の内部機能とその命令 (オペコード) の一部について詳しく説明します。

Pascal 関数 (関数) のサポート

これまで、Pascal の プロシージャ を定義して呼び出す方法がありました。この PR から、Pascal の 関数 を定義して呼び出すこともできます。

このコミットでは、JVM が関数の定義と呼び出しをどのように処理するかを理解するために Java プログラムが実装されました。以下の Java プログラムから:

public class FunctionCall {
    public static void main(String[] args) {
        System.out.println("Hello from main!");
        System.out.println(myMethod());
    }

    static String myMethod() {
        return "Hello from myMethod!";
    }
}

クラスを逆アセンブルすると、次のアセンブリが得られます。

1:  public class FunctionCall {
2:      public static main([java/lang/String)V {
3:          getstatic java/lang/System.out java/io/PrintStream
4:          ldc "Hello from main!"
5:          invokevirtual java/io/PrintStream.println(java/lang/String)V
6:
7:          getstatic java/lang/System.out java/io/PrintStream
8:          invokestatic FunctionCall.myMethod()java/lang/String
9:          invokevirtual java/io/PrintStream.println(java/lang/String)V
10:
11:         return
12:     }
13:
14:     static myMethod()java/lang/String {
15:         ldc "Hello from myMethod!"
16:
17:         areturn
18:     }
19: }

この例では、次のことを識別できました。

  • メソッドを呼び出すために、JVM は命令「invokestatic FunctionCall.myMethod()java/lang/String」(8 行目) を使用しました。ここで:
    • invokestatic は、呼び出されるメソッドの完全なシグネチャを引数として受け取る命令です。
    • FunctionCall はクラスの名前です。
    • myMethod()java/lang/String は、パラメータ (この例ではなし) と戻り値の型 (この例では java/lang/String) を含むメソッドの完全な署名です。 ;
  • 命令 areturn (行 17) は関数を終了し、戻り文字列をスタックに残します。

つまり、以下の Pascal プログラムから:

program function_call_wo_params;

function myfunction : string;
begin
    myfunction := 'Hello from myfunction!';
end;

begin
    writeln('Hello from main!');
    writeln(myfunction());
end.

POJ は次の JASM を生成するように調整されました:

// Code generated by POJ 0.1
public class function_call_wo_params {
    ;; function myfunction : string;
    static myfunction()java/lang/String {
        ldc "Hello from myfunction!"
        astore 100   ;; Posição 100 guarda o retorno da função
        aload 100    ;; Empilha o retorno da função
        areturn      ;; Deixa "Hello from myfunction!" na pilha
    }

    ;; procedure principal (main)
    public static main([java/lang/String)V {
        ;; writeln('Hello from main!');
        getstatic java/lang/System.out java/io/PrintStream
        ldc "Hello from main!"
        invokevirtual java/io/PrintStream.print(java/lang/String)V
        getstatic java/lang/System.out java/io/PrintStream
        invokevirtual java/io/PrintStream.println()V

        ;; writeln(myfunction());
        getstatic java/lang/System.out java/io/PrintStream
        invokestatic function_call_wo_params.myfunction()java/lang/String 
        invokevirtual java/io/PrintStream.print(java/lang/String)V
        getstatic java/lang/System.out java/io/PrintStream
        invokevirtual java/io/PrintStream.println()V

        return
    }
}

最も注意深い人は、上記の「astore 100」に気づき、次のように考えたに違いありません:

  • なぜ関数の戻り値をローカル変数に保存するのでしょうか?これは、Pascal では関数の戻り値を関数中に N 回設定できるが、JVM にスタックできる結果は 1 つだけであるためです。
  • なぜ 100 位なのか?関数またはプロシージャのローカル変数は位置 0 から始まるため、戻り値を格納するために位置 100 が任意に選択されました。
  • しかし、この例では ldc "Hello from myfunction!" 命令のみが生成され、その後に areturn 命令が続くように最適化することはできないでしょうか?はい、そうなりますが、POJ は市場のコンパイラーに存在する、将来実装される可能性のある最適化フェーズを実装していません。

このコミットは、シンボル テーブルと パーサー で "function" タイプのサポートを実装します。

上記の例では、関数には引数がありませんでした。このコミットでは、引数を持つ関数に対して期待される結果が実装されました。これは以下の Pascal プログラムからのものです:

program function_call_with_two_params;

function addvalues(value1, value2: integer) : integer;
begin
    addvalues := value1 + value2;
end;

begin
    writeln('2+4=', addvalues(2, 4));
end.

POJ は次の JASM を正しく生成しました:

// Code generated by POJ 0.1
public class function_call_with_two_params {
    ;; function addvalues(value1, value2: integer) : integer;
    static addvalues(I, I)I {
        ;; addvalues := value1 + value2;
        iload 0
        iload 1
        iadd 
        istore 100
        iload 100

        ireturn 
    }

    ;; procedure main
    public static main([java/lang/String)V {
        ;; writeln('2+4=', ...);
        getstatic java/lang/System.out java/io/PrintStream
        ldc "2+4="
        invokevirtual java/io/PrintStream.print(java/lang/String)V
        getstatic java/lang/System.out java/io/PrintStream

        ;; aqui código para invocar addvalues(2, 4)
        sipush 2
        sipush 4
        invokestatic function_call_with_two_params.addvalues(I, I)I 

        ;; aqui código para invocar writeln com retorno addvalues
        invokevirtual java/io/PrintStream.print(I)V
        getstatic java/lang/System.out java/io/PrintStream
        invokevirtual java/io/PrintStream.println()V

        return
    }
}

次のステップ

次の出版物では、コンテキスト、見つかったバグ、ネストされた文、データ入力について説明し、このプロジェクトの最後の目的である階乗の再帰計算を締めくくります。

完全なプロジェクトコード

プロジェクトの完全なコードとドキュメントが含まれるリポジトリはここにあります。

以上がパスカル関数のサポートの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。