Sto scrivendo un compilatore per un linguaggio simile a C, e sto cercando un modo elegante per attraversare il mio albero di sintassi astratto. Sto cercando di implementare il pattern Visitor, anche se non sono convinto che lo stia facendo correttamente.
struct Visitor {
// Expressions
virtual void visit(AsgnExpression&);
virtual void visit(ConstantExpression&);
...
virtual void visit(Statement&);
...
virtual void finished(ASTNode&);
protected:
virtual void visit(ASTNode&) = 0;
};
visit
è sovraccarico per ogni tipo e, per impostazione predefinita, ciascun overload chiamerà visit(ASTNode&)
che le sottoclassi sono costrette a implementare. Questo rende più facile fare cose veloci e sporche, sebbene la definizione di un visit
per ogni tipo sia noiosa. Ogni sottoclasse di ASTNode
deve implementare un metodo accept
che viene utilizzato per attraversare la struttura ad albero.
class ASTNode {
public:
virtual ~ASTNode();
virtual void accept(Visitor& visitor) = 0;
};
Tuttavia, questo design sta diventando noioso perché i metodi accept
sono spesso molto simili.
Chi dovrebbe essere responsabile per attraversare la struttura, i nodi o il visitatore? Mi sto proponendo di avere ASTNode
di fornire un iteratore per accedere ai suoi figli, e quindi di far attraversare il visitatore alla struttura . Se hai qualche esperienza nella progettazione di Abstract Syntax Trees, per favore condividi la tua saggezza con me!