0

我已經開始在C++中編寫多態遞歸下降解析器。但是我遇到了一個問題。這些課程都設置這樣的:多態抽象語法樹(遞歸下降解析器):不可能?

class Node { 
public: 
    std::vector<Node*> children; 
}; 

class NodeBinary : public Node { 
public: 
    Node* left; 
    Node* right; 
}; 

class NodeUnary : public Node { 
public: 
    Node* operand; 
}; 

class NodeVar : public Node { 
public: 
    std::string string; 
    NodeVar(std::string str) : string(str) {}; 
}; 

class NodeNumber : public Node { 
public: 
    signed long number; 
    NodeNumber(signed long n) : number(n) {}; 
}; 

// etc. 

然後像NodeDeclarationNodeCallNodeNotNodeAssignmentNodePlusNodeMinusNodeIf等類將繼承無論是從Node或東西少通用像NodeBinaryNodeUnary

但是,其中一些需要更具體的操作數。 NodeAssignment總是需要一個var和一個數字/表達式。因此,我將不得不將Node *留在NodeVar * left和NodeExpr *上。問題來自諸如NodePlus之類的問題。左邊可以是NodeVarNodeExpr!而根節點也有類似的問題:在頂層解析以將子節點添加到根節點時,如何判斷子節點是否爲NodeExprNodePlusNodeIf等?

我可以讓所有的節點都有一個枚舉「類型」,它說明了它是什麼類型,但那麼有什麼好點的多態繼承樹呢?

這個問題通常如何解決?

回答

0

如果您爲AST節點使用類繼承,則需要創建適當的繼承層次結構,就像任何面向對象的設計一樣。

因此,舉例來說,NodeAssignment(這大概是的NodeStatement一個專門化)需要含有(其中一個NodeVariable是一個專門化)一個NodeLValueNodeValue。像往常一樣,LValues(即您可以分配的東西)是Values的子集,因此NodeLValue將是NodeValue的專業化版本。等等。你的二進制運算節點將包含leftright成員,這兩者都是NodeValue基本對象(我希望NodeValue是純虛擬的,有大量具體的專業領域。)

如果你堅持使用遞歸下降解析器,每個解析函數需要返回一個合適的子類Node,以便解析分配左側的函數邏輯上返回NodeLValue*,準備插入NodeAssignment構造函數。 (坦率地說,我會在所有這些類名稱中排除Node這個詞,將它們全部放入命名空間node::並省去一些鍵入操作。)

+0

我明白你的意思了,但我的問題的一部分是如何能夠告訴即使是在一個NodeValue中,如果它是一個數字或變量被使用,它的區別(例如,在一個左右可以是值或變量的加號中)? – Accumulator

+0

@accumulator:面向對象設計的本質是每個對象都做它被要求做的事情。如果你需要向對象詢問它爲了做什麼而做的事情,那麼你沒有正確地將行爲封裝到對象中。 – rici

+0

那麼什麼是可以是var或val的東西的正確封裝? – Accumulator