I'm writing a compiler for a C-like language, and I'm looking for an elegant way to traverse my abstract syntax tree. I'm trying to implement the Visitor pattern, although I'm not convinced that I'm doing it correctly.
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 is overloaded for each type, and by default each overload will call visit(ASTNode&) which subclasses are forced to implement. This makes it easier to do quick and dirty things, although defining a visit for each type is tedious. Each subclass of ASTNode must implement an accept method which is used to traverse the tree structure.
class ASTNode { public: virtual ~ASTNode(); virtual void accept(Visitor& visitor) = 0; }; However, this design is quickly becoming tedious because the accept methods are often very similar.
Who should be responsible for traversing the structure, the nodes or the visitor? I'm leaning towards having ASTNode provide an iterator for accessing its children, and then having the visitor traverse the structure. If you have any experience designing Abstract Syntax Trees, please share your wisdom with me!
VisitFoofunctions andTraverseFoofunctions, and evenWalkUpFromFoofunctions that can walk up the class hierarchy, to achieve quite good flexibility.