next up previous
Next: Expression evaluation Up: Interpret the Program Previous: Interpret the Program

   
Visitors

Visitor is the superclass of all computation classes. Although it has no class relationship with any of the classes of the abstract tree, it and all of its subclasses are specific to that tree. Each abstract tree implementation must have its own visitor, because the methods of the visitor are in 1-to-1 correspondence to the rule classes of the tree:

Declare the abstract visitor class[7] :

class Visitor {
  public:
    virtual SPMtilde;Visitor() {}
    virtual void VisitCompoundStm(CompoundStm*) = 0;
    virtual void VisitAssignStm(AssignStm*)     = 0;
    virtual void VisitPrintStm(PrintStm*)       = 0;
    virtual void VisitIdExp(IdExp*)             = 0;
    virtual void VisitNumExp(NumExp*)           = 0;
    virtual void VisitOpExp(OpExp*)             = 0;
    virtual void VisitEseqExp(EseqExp*)         = 0;
    virtual void VisitPairExpList(PairExpList*) = 0;
    virtual void VisitLastExpList(LastExpList*) = 0;
    virtual void VisitPlus(Plus*)               = 0;
    virtual void VisitMinus(Minus*)             = 0;
    virtual void VisitTimes(Times*)             = 0;
    virtual void VisitDiv(Div*)                 = 0;
};
This macro is invoked in definition 25.

Every tree class must be modified to accept visitor invocations by providing an Accept method. These methods all have the same prototype:

Prototype for the Accept method[8] :

virtual void Accept (Visitor*)
This macro is invoked in definitions 4, 5, 6, and 9.

Only the rule classes define bodies for their Accept methods. The general tree node class and all of the symbol classes define empty Accept methods:

Empty Accept method[9] :

Prototype for the Accept method[8] = 0
This macro is invoked in definitions 1 and 2.

Accept methods for the rule classes follow identical patterns:

Accept method definitions for rule classes[10] :

void CompoundStm        :: Accept (Visitor* v) { v->VisitCompoundStm(this); }
void AssignStm          :: Accept (Visitor* v) { v->VisitAssignStm(this); }
void PrintStm           :: Accept (Visitor* v) { v->VisitPrintStm(this); }
void IdExp              :: Accept (Visitor* v) { v->VisitIdExp(this); }
void NumExp             :: Accept (Visitor* v) { v->VisitNumExp(this); }
void OpExp              :: Accept (Visitor* v) { v->VisitOpExp(this); }
void EseqExp            :: Accept (Visitor* v) { v->VisitEseqExp(this); }
void PairExpList        :: Accept (Visitor* v) { v->VisitPairExpList(this); }
void LastExpList        :: Accept (Visitor* v) { v->VisitLastExpList(this); }
void Plus               :: Accept (Visitor* v) { v->VisitPlus(this); }
void Minus              :: Accept (Visitor* v) { v->VisitMinus(this); }
void Times              :: Accept (Visitor* v) { v->VisitTimes(this); }
void Div                :: Accept (Visitor* v) { v->VisitDiv(this); }
This macro is invoked in definition 26.

Suppose that a routine needs to perform a specific computation at a specific node of the tree, to which it has a pointer. The routine does not know what kind of tree node that pointer points to.

1.
The routine invokes the node's Accept method, passing a pointer to the visitor subclass for the computation.

2.
Every tree node is an instance of a rule class. The Accept method for that rule class is therefore the one invoked. That method invokes the corresponding method of the visitor subclass for the computation, passing a pointer to the tree node.

3.
The method of the visitor subclass for the computation carries out the specific computation, accessing information from the node as required.

The declaration of the interpreter subclass of Visitor is almost identical to the definition of Visitor itself:

Declare the concrete interpreter subclass[11] :

class Interpreter : public Visitor {
  public:
    virtual void VisitCompoundStm(CompoundStm*);
    virtual void VisitAssignStm(AssignStm*);
    virtual void VisitPrintStm(PrintStm*);
    virtual void VisitIdExp(IdExp*);
    virtual void VisitNumExp(NumExp*);
    virtual void VisitOpExp(OpExp*);
    virtual void VisitEseqExp(EseqExp*);
    virtual void VisitPairExpList(PairExpList*);
    virtual void VisitLastExpList(LastExpList*);
    virtual void VisitPlus(Plus*);
    virtual void VisitMinus(Minus*);
    virtual void VisitTimes(Times*);
    virtual void VisitDiv(Div*);
  private:
    Declare the expression evaluation stack[12]
    Declare the print line stack[18]
    Declare the interpreter memory[15]
};
This macro is invoked in definition 27.

All of the method declarations are the same, but Interpreter must use private fields to pass information among its methods. These fields are explained in subsequent subsections.


next up previous
Next: Expression evaluation Up: Interpret the Program Previous: Interpret the Program
William Waite
1998-08-30