I have a hierarchical structure of objects to represent arithmetic expressions. Something like the following:
TreeNode
/ \
/ \
/ \
NumericNode BinaryOpNode
/ | \ \
/ | \ \
/ | \ \
AddNode MulNode DivNode ...etc
I have the lexer and parser working. Now I'm trying to figure out the best way to do actions over the generated AST in a practical and easy to adapt manner. Right now I had implemented the Visitor Pattern with a Visitor and Visitable interface, but I'm not sure if I really need all the concrete classes to implement the Visitable interface.
Since i want to control the traverse order in the visitor, i find myself repeating a lot of code. For example, for a PrintInOrder Visitor i have methods like:
public void visit(AddNode node) {
node.getLeft().accept(this);
System.out.print(node + " ");
node.getRight().accept(this);
}
for every concrete node representing some arithmetic operation.
But i can achieve the same implementing Visitable in the super classes. For example the same PrintInOrder Visitor would look like:
public void visit(BinaryOpNode node) {
node.getLeft().accept(this);
System.out.print(node + " ");
node.getRight().accept(this);
}
However, I don't know what is the most common approach for this task.
Question 1: If I want my design to let me do almost whatever I want over the AST, I really need to visit all the concrete nodes and write all that repeated code?.
Question 2: Assuming a Visitor that could return some type, like:
public interface Visitor<T> {
public T visit(AddNode node);
public T visit(MulNode node);
...
}
This looks more versatile than the common void version. But it has useful benefits? And can be used in the same way as the void version?
