[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

More Visitors



Unless I'm missing something, in SableCC you can't write a single
visitor method to handles multiple alternatives.  Take a sample class
hierarchy:


abstract class Shape implements Switchable { ... }

abstract class RoundShape extends Shape { ... }
class Circle extends RoundShape { ... }
class Oval extends RoundShape { ... }

abstract class CorneredShape extends Shape { ... }
class Square extends CorneredShape { ... }
class Triangle extends CorneredShape { ... }


Now, suppose I want a visitor that does a depth-first traversal over a
parse tree, and prints "RoundShape!" every time it finds a subclass of
RoundShape.  I could write one method for Circle and a separate but
identical method for Oval.  (In SableCC, they'd be called caseCircle
and caseOval).  But what I really want is a single caseRoundShape
method, and SableCC doesn't give me that.

It seems to me that SableCC could in fact output such methods.  You'd
probably need two visitors to make this work.  The first visitor
(which I call MainVisitor) has "case" methods for both abstract and
concrete classes: not just Circle but Shape and RoundShape as well.
Each "case" method calls the corresponding method for the superclass:
caseCircle calls caseRoundShape, which calls caseShape.

What does caseShape do?  The most useful thing would be to do nothing
with the current node, but somehow iterate over the children nodes.
This is where you need a second visitor (which I've called the
HelperVisitor).  It'd be a lot like DepthFirstAdaptor, but it'd take
an additional paramater (the first visitor), and instead of applying
itself to the children, it would apply the first visitor.

Example:


// Has cases for both abstract and concrete classes
class MainVisitor {
  private HelperVisitor treeWalker;

  MainVisitor (HelperVisitor treeWalker) {
    this.treeWalker = treeWalker;
  }

  void caseShape (Shape node) {
    treeWalker.apply(node, this);
  }

  void caseRoundShape (RoundShape node) {
    caseShape(node);
  }

  void caseCircle (Circle node) {
    caseRoundShape(node);
  }

  ...
}

// Only has cases for the concrete classes
class HelperVisitor {
  void caseCircle (Circle node, MainVisitor main) {
    node.getFirstChild().apply(main);
    node.getSecondChild().apply(main);
  }
  
  ...
}


So what do people think?  Could something like this be added to SableCC?

-Nick Kramer