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:
This macro is invoked in definition 25.
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;
};
Every tree class must be modified to accept visitor invocations by providing an Accept method. These methods all have the same prototype:
This macro is invoked in definitions 4, 5, 6, and 9.
virtual void Accept (Visitor*)
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:
This macro is invoked in definitions 1 and 2.
Prototype for the Accept method[8] = 0
Accept methods for the rule classes follow identical patterns:
This macro is invoked in definition 26.
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); }
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.
The declaration of the interpreter subclass of Visitor is almost identical to the definition of Visitor itself:
This macro is invoked in definition 27.
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]
};
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.