2012-12-21 57 views
2

我知道還有關於編譯器/解釋器技術的其他問題,也有很好的代碼來研究,如IronPythonJurassic。 對我來說很清楚如何從源代碼構建一個AST(抽象語法樹),編寫頂級解析器(目前我比寫代碼生成工具更喜歡編寫代碼)。使用c#編寫一個真正的解釋器來自AST

作爲解釋程序使用時,我試圖學習的大多數源代碼都是使用API​​(如Reflection.Emit)編譯程序。 現在我想知道構建一個真正的解釋器的最佳實踐,該解釋器不會編譯爲.NET VM的源代碼。

一旦我得到了AST,我該如何執行代碼?我應該使用解釋器還是訪客設計模式?或做一些不同的事情?什麼是最好的或規範的方式?

我知道這裏已經有一個question like,但如果可能的話,我更喜歡.NET/C#實現的更多信息和更具體的內容。

問候,賈科莫

+0

最佳做法是將編譯與解釋相結合。 AST通常不太適合高效的解釋,因此將它降低到更簡單的表示,擴展所有語法糖,儘可能解析標識符(如果有詞法範圍界定)是有意義的。然後纔可以開始翻譯。 下面答案中的「解釋者」模式是一個很好的起點,雖然有很多有趣的優化。請參閱SISC的靈感。 –

回答

2

我應該使用解釋或訪問者設計模式?

我覺得名字給出提示;-)

遊客有利於對AST的一般操作,但用於執行單一功能(執行/解釋),你只需要一個方法,從而解釋模式。

這裏是一個非常簡單的例子(但它確實沒有變得更加複雜,重要的是,即使是複雜的翻譯):

// Holds function scope etc. 
class Context { … } 

abstract class Node { 
    public abstract object Execute(Context ctx); 
} 

class Number { 
    private readonly int x; 

    public Number(int x) { this.x = x; } 

    public object Execute(Context ctx) { return x; } 
} 

class Addition { 
    private readonly Node left, right; 

    public Addition(Node left, Node right) { 
     this.left = left; 
     this.right = right; 
    } 

    public object Execute(Context ctx) { 
     // Verification omitted: do the nested expressions evaluate to a number? 
     return ((int) (left.Execute(ctx)) + ((int) (right.Execute(ctx)) 
    } 
} 

...和你有它。一個簡單的解釋器,知道加法。下面是一個使用示例:

var ast = new Addition(new Number(23), new Number(42)); 
Console.WriteLine("Result = {0}", ast.Execute(new Context())); 
+0

+1感謝您的快速和明確的迴應!還有一件事...當覆蓋表示像for子句這樣的結構化代碼的節點時,我應該執行for循環並執行所有子節點,或者有更好的方法來實現結構節點?再次感謝 – gsscoder

+2

@gsscoder的確,基本上在'Execute'方法中實現了結構(在'for'子句的情況下,通過'for'循環;在if子句的情況下, 'if'語句 - 等等)。 –

+0

其他+1;現在一切都很清晰......問候,賈科莫 – gsscoder