2012-07-20 82 views
4

我有一個自定義的基於堆棧的語言,我試圖編譯爲CIL,因此它可以被JITed。語言本身非常簡單,因爲它只有整數和布爾值。但是,每種數據類型都有一個專用堆棧。語言本身是一個命令流,每個命令都可以從任一堆棧中窺視,推送和/或彈出值。由命令推送/放置的整數或布爾值的數量不會改變(因此命令具有固定的義數)。還有一個扁平的整型數組,語言讀取和寫入數值,代表外部存儲器。堆棧本身可以是任意深的。編譯基於堆棧的語言CIL

對於簡單的命令如「add」,「subtract」等,將整數堆棧命令轉換爲CIL幾乎很簡單:CIL堆棧可以批量替換整數堆棧(儘管我有一個問題:是否存在在規範或實踐中,CIL堆棧的深度有多大?)但是也有類似StoreIfTrue的命令,它只會在某個索引處存儲一個值(從整數堆棧)到平坦整數數組(索引也是來自整數堆棧)如果布爾堆棧的最高值爲真。所以我需要同時訪問一些命令的布爾堆棧和整數堆棧。

現在我要保持System.Collections.Generic.Stack表示布爾堆棧。但是我想知道是否有一種已知的算法或方法可以將我的自定義語言的兩個堆棧模型「拼合」成一個與CIL更直接兼容的堆棧模型。

+0

的CIL堆棧是類型更小,它可以處理和混合整數和布爾變量。應該有一種方法可以將多堆棧執行模型轉換爲無類型的單堆棧,但從您的問題中不清楚應該如何實現。 – 2012-07-21 10:34:08

回答

0

你是否知道如何生成,例如,C#CIL代碼我無法從你的問題推斷。要做到這一點,您可以使用ReflectionCecil

對於虛擬執行系統(VES,將執行該指令CIL的虛擬系統的模型)在棧上的值(和在寄存器中)沒有關聯的複雜類型。只有簡單的類型(int32,int64,託管對象引用,託管指針和浮點數)由VES跟蹤。因此,VES無法看到堆棧中布爾值和整數之間的差異(在內部,VES將布爾值視爲32位整數),因此無法使用執行堆棧來模擬布爾堆棧和整數堆棧。你可以做同樣的事情:將布爾值視爲整數和非零整數作爲布爾值true。所以兩個整數的比較會導致另一個整數。然而,那麼你只有一個堆棧而不是兩個。


編輯

啊,我明白了。您的語言旨在成爲一種通用編程語言,因此必須具有高度的可靠性,並對所有可能的輸入(包括無效輸入)具有一些預定義(或不​​具有)行爲。通過爲每種可能的類型分別設置堆棧,更有可能使用兼容操作數而不是隨機操作數。因爲不可能使用單個堆棧來模擬多個堆棧,我會爲每個類型使用一個真實的Stack<T>對象,而不是嘗試使用CIL堆棧。這有幾個優點:

  • 更容易在未來
  • 添加新類型允許棧的邊界檢查(例如,使操作無操作)
  • 更容易比混合類型的任何自定義方案來管理在一個堆棧上
  • 隨機訪問,如果你需要它
  • 不需要知道CIL內部,所以可以運行在單聲道和。淨
  • CIL堆棧則僅用於臨時操作數棧幀和返回地址
+0

我可以生成CIL,是的。我不介意把布爾變成整數。但我沒有看到將兩個邏輯堆棧合併到一個物理執行堆棧的方法。這真是我問題的核心。 – 2012-07-20 23:06:34

+0

或更改:我的語言使用兩臺堆棧機器。我如何處理它(作爲我的編譯步驟的一部分)纔能有效地使用單個堆棧機器? – 2012-07-20 23:09:35

+0

通常不可能使用一個堆棧模擬兩個堆棧。爲什麼你首先有兩個邏輯堆棧?對我來說更有意義(除非我完全誤解了你)只有一個堆棧,並將所有布爾值和整數值混合在一起。一個'add'指令可能會彈出兩個值(不管它們的類型如何),然後添加它們並將結果返回。然後,將採取的布爾隨後'if'指令只是獲取堆棧(一個由'add'推動)的頂部整數,假裝它是一個布爾值。另一種方式。 – Virtlink 2012-07-21 15:06:24

1

我想在一個堆疊存儲兩個獨立的堆棧是不可能的(至少在沒有外部臨時存儲,但你會得到可怕的表現)。這是因爲無論如何將堆棧的頂部始終靠近實際堆棧的頂部,無論使用哪種表示形式,都無法實現。

但是CIL不只是有棧和堆,它也有局部變量。但是你只能通過一個不變的索引訪問局部變量。因此,如果您在編譯時總是知道堆棧頂部的索引,並且您也知道堆棧的最大大小,則可以使用局部變量來表示它。但我認爲這兩個條件不適用於你的情況。

正因爲如此,我認爲使用Stack<T>一個或兩個你堆的是你的最佳選擇。

+0

處理堆棧的深度可能會非常棘手,但因爲每個命令有固定的參數數量,我認爲找出一個恆定的指標正在擡頭將是可能的。我將不得不測試它,看看它是否比使用Stack 快得多。 – 2012-07-23 17:00:40