2013-05-29 39 views
3

嗯,不完全是。我有更多的功能性數據結構問題。haskell中的CPU仿真,函數式數據結構和拉鍊?

說我想要一個CPU的執行模型。我有一些改變CPU狀態的指令(比如它是一個基於堆棧的cpu,只有跳轉有操作數......或其他),一些構成程序的指令列表和標籤。跳轉是通過引用某個標籤來完成的,而不是一些偏移量。我如何表達這一點?

如果我有一個看起來像[Label "foo", Add, Add, Mult, Label "bar", Jnz "foo"]的程序,那麼當我點擊Jnz "foo"時,我需要向後搜索並轉發標籤「foo」以繼續執行。這似乎有點愚蠢。我想我應該能夠有一個更好的數據結構,允許快速跳轉到標籤。現在,我會說我不想存儲偏移量。假設CPU允許自修改代碼或類似的東西。我應該如何修補代碼,同時確保引用仍指向當前版本的代碼?

我喜歡拉鍊的想法。 我只是不知道如果做拉鍊跳轉到在O預定位置的想法(1)時間是有道理

回答

1

我建議是這樣

import Data.Map as M 
data Code = Code { instructions :: [Instruction], labels :: M.Map String [Instruction] } 

在標籤映射的值與說明列表共享。您可以將標籤保留在指令流中,並執行類似於

mkCode is = Code is (scan is) 
       where scan [] = M.empty 
        scan (Label l:js) = M.insert l js (scan js) 
        scan (_:js) = (scan js) 

以構建適當的代碼值。

注意Data.Map實現二叉搜索樹。如果你想要一個散列表有Data.Hashtable

+0

那麼我該如何修改代碼,同時保持引用的機智? – Evan

+0

哦,我錯過了有關自修改代碼的部分。這確實使它有點棘手。我會考慮並更新答案。 –

2

的答案(但我不知道這是你想要的)是做什麼的呢LLVM和存儲代碼BasicBlock秒。在這個系統中,每個塊都是一段只能從頭開始輸入的代碼。最後的指令必須跳轉到另一個塊。然後,您的標籤,而不是在指令列表中,附加到基本塊。程序可能看起來像:

newtype Lable = [Char] 
data Code = Data.Map Label [Instruction] 

當你點擊跳轉指令您只需lookup其在地圖塊,繼續向前。

這有一些真正的優勢,如果你的目標是(LLVM再次使用它的原因)優化代碼,但它確實打破了單純代表你的代碼的指令列表模式。

在另一方面,我想不出哪裏的標籤都包含在程序代碼中的任何CPU或計算模型。在彙編中,它們只是描述下一行代碼的固定偏移量的便捷方式。它們不會在輸出中結束,並且如果代碼在運行時可修改,則還需要修改指令。