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!