[英]What are some good ways of implementing tail call elimination?
比編寫編譯器和VM更簡單的方法是注冊和蹦出您的解釋器。 既然你有一個解釋器而不是編譯器(我假設),你只需要幾個簡單的轉換來獲得對尾調用的適當支持。
你必須先用延續傳遞方式編寫所有內容,這在C / C ++中可能很奇怪。 Dan Friedman的ParentheC教程將指導您將高級遞歸程序轉換為可機器轉換為C的表單。
最后,你將實際上實現一個簡單的VM,而不是使用常規函數調用來執行eval,applyProc等,你通過設置全局變量傳遞參數,然后goto
下一個參數(或使用top-級別循環和程序計數器)...
return applyProc(rator, rand)
變
reg_rator = rator
reg_rand = rand
reg_pc = applyProc
return
也就是說,通常以遞歸方式相互調用的所有函數都被簡化為偽程序集,在偽程序集中,它們只是不會重復出現的代碼塊。 頂級循環控制程序:
for(;;) {
switch(reg_pc) {
case EVAL:
eval();
break;
case APPLY_PROC:
applyProc();
break;
...
}
}
編輯:我使用JavaScript編寫了我的業余愛好Scheme解釋器的相同過程。 我利用了很多匿名程序,但它可能有助於作為一個具體的參考。 查看FoxScheme的提交歷史,從2011-03-13( 30707a0432563ce1632a )開始到2011-03-15( 5dd3b521dac582507086 )。
編輯^ 2:非尾遞歸仍會占用內存,即使它不在堆棧中。
在不知道你擁有什么的情況下,我會說最簡單(也是最有啟發性)的方法是從Dybvig的“Three Implementation Models for Scheme”中實現方案編譯器和VM。
我在這里用Javascript完成了(Dybvig的PDF副本也在那里): https : //github.com/z5h/zb-lisp
檢查src / compiler.js:compileCons,並在src / vm.js中執行“操作碼”
如果您對口譯員的實施技術感興趣,那么Christian Queinnec的書“LiSP - Lisp in Small Pieces”是無法解決的。 它通過完整的代碼非常徹底地解釋了實現Scheme系統的所有方面。 這是一本很棒的書。
http://www.amazon.com/exec/obidos/ASIN/0521562473/qid=945541473/sr=1-2/002-2995245-1849825
但不要忘記查看ReadScheme.org上的論文。
這部分
編譯器技術/實現技術和優化http://library.readscheme.org/page8.html
有很多關於尾調用優化的論文。
除此之外,您還可以找到Dybvig論文(經典)的鏈接,該論文編寫得非常好。 它以非常清晰的方式解釋和激勵一切。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.