首頁 >後端開發 >Golang >支援 Pascal 函數

支援 Pascal 函數

王林
王林原創
2024-07-16 08:03:50622瀏覽

Suporte às funções do Pascal

對於那些不遵循POJ(JVM 上的Pascal)的人來說,它是一個將子集 從Pascal 轉換為JASM 的編譯器( Java Assembly),以便我們可以使用JVM 作為執行環境。

在上一篇文章中,我們在錯誤捕獲、對 string 類型的關係運算符的支持以及定義(和使用)Pascal 的 過程 的可能性。

在本出版品中,我們將介紹對 Pascal 函數(函數)的支持。不久之後我們就可以完成這個專案的最後一個目標:從標準輸入中讀取一個數字並計算其階乘。

當我們為 JVM 進行編譯時,有必要詳細說明這個令人難以置信的虛擬機器的各個點的功能。因此,我多次詳細介紹 JVM 的內部功能及其一些指令(操作碼)。

支援 Pascal 函數(函數

到目前為止,我們有一種方法來定義和呼叫 Pascal 的過程。從此 PR 中還可以定義並呼叫 Pascal 的 函數.

在此提交中,實作了一個 Java 程式來了解 JVM 如何處理定義和呼叫函數。來自下面的 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 中只能堆疊一次結果;
  • 為什麼排在第 100 名?函數或流程的局部變數從位置 0 開始,因此任意選擇位置 100 來儲存回傳值;
  • 但是是否可以進行最佳化,以便在此範例中僅產生 ldc "Hello from myfunction!" 指令,然後產生 areturn 指令?是的,確實如此,但 POJ 並未實現市場編譯器中存在的最佳化階段,而這在未來可能會實現。

此提交實現了符號表和解析器中的「函數」類型的支援。

在上面的範例中,函數沒有參數。在此提交中,實現了帶有參數的函數的預期結果。來自下面的 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
    }
}

後續步驟

在下一篇文章中,我們將討論上下文、發現的錯誤、嵌套句子、資料輸入,並總結該項目的最後一個目標:遞歸計算階乘。

完整的專案程式碼

包含項目完整程式碼和文件的儲存庫位於此處。

以上是支援 Pascal 函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn