1.2. Motivation ¶
์ปดํ์ผ๋ฌ๊ฐ abstact syntax tree๋ก ํ๋ก๊ทธ๋จ์ ํํํ๋ค๊ณ ํ์. ์ปดํ์ผ๋ฌ๋ ๋ชจ๋ ๋ณ์๋ค์ด ์ ์๊ฐ ๋์ด์๋ ์ง๋ฅผ ๊ฒ์ฌํ๋ ๊ฒ๊ณผ ๊ฐ์ '์ ์ ์ธ ์๋ฏธ' ๋ถ์์ ์ํด abstract syntax tree์ ๋ํด operation์ ์ํํ ํ์๊ฐ ์์ ๊ฒ์ด๋ค. ์ปดํ์ผ๋ฌ๋ ๋ํ code ๋ณํ์ ํ ํ์๊ฐ ์๋ค. ๋ํ ์ปดํ์ผ๋ฌ๋ type-checking, code optimization, flow analysis ์ ํด๋น ๋ณ์๊ฐ ์ด์ฉ๋๊ธฐ ์ ์ ์ธ๋์๋์ง ๋ฑ์ ์ฌ๋ถ๋ฅผ ๊ฒ์ฌํ๊ธฐ ์ํด์ ํด๋น operations๋ค์ ์ํํ ํ์๊ฐ ์๋ค. ๋ ๋์๊ฐ ์ฐ๋ฆฌ๋ pretty-printing, program restructuring, code instrumentation, ๊ทธ๋ฆฌ๊ณ ํ๋ก๊ทธ๋จ์ ๋ค์ํ ๊ธฐ์ค๋ค์ ๋ํ ๊ณ์ฐ์ ํ๊ธฐ ์ํด abstract syntax tree๋ฅผ ์ด์ฉํ ๊ฒ์ด๋ค.
์ด๋ฌํ operations๋ค์ ๋๋ถ๋ถ๋ค์ variable๋ค์ด๋ arithmetic expression๋ค์ ํํํ๋ node๋ค๊ณผ ๋ค๋ฅด๊ฒ assignment statement๋ค์ ํํํ๋ node๋ฅผ ์ทจ๊ธํ ํ์๊ฐ ์๋ค. ๋ฐ๋ผ์, ๊ฐ๊ฐ assignment statement ๋ฅผ ์ํ ํด๋์ค์, variable ์ ์ ๊ทผ ํ๊ธฐ ์ํ ํด๋์ค, arithmetic expression์ ์ํ ํด๋์ค๋ค์ด ์์ด์ผ ํ ๊ฒ์ด๋ค. ์ด๋ฌํ node class๋ค์ ์ปดํ์ผ ๋ ์ธ์ด์ ์์กด์ ์ด๋ฉฐ, ๋ํ ์ฃผ์ด์ง ์ธ์ด๋ฅผ ์ํด ๋ฐ๋์ง ์๋๋ค.
์ด ๋ค์ด์ด๊ทธ๋จ์ Node class ๊ณ์ธต๊ตฌ์กฐ์ ์ผ๋ถ๋ถ์ ๋ณด์ฌ์ค๋ค. ์ฌ๊ธฐ์์ ๋ฌธ์ ๋ ๋ค์ํ node class๋ค์ ์๋ ์ด๋ฌํ operation๋ค์ ๋ถ์ฐ์ ์์คํ
์ผ๋ก ํ์ฌ๊ธ ์ดํดํ๊ธฐ ์ด๋ ต๊ณ , ์ ์งํ๊ฑฐ๋ ์ฝ๋๋ฅผ ๋ฐ๊พธ๊ธฐ ํ๋ค๊ฒ ํ๋ค. Node ์ type-checking ์ฝ๋๊ฐ pretty-printing code๋ flow analysis code๋ค๊ณผ ์์ฌ ์๋ ๊ฒ์ ํผ๋์ค๋ฝ๋ค. ๊ฒ๋ค๊ฐ ์๋ก์ด operation์ ์ถ๊ฐํ๊ธฐ ์ํด์๋ ์ผ๋ฐ์ ์ผ๋ก ์ด ํด๋์ค๋ค์ ์ฌ์ปดํ์ผํด์ผ ํ๋ค. ๋ง์ผ ๊ฐ๊ฐ์ ์ operation์ด ๋
๋ฆฝ์ ์ผ๋ก ์ถ๊ฐ๋ ์ ์๊ณ , ์ด node class๋ค์ด operation๋ค์ ๋ํด ๋
๋ฆฝ์ ์ด๋ผ๋ฉด ๋์ฑ ์ข์ ๊ฒ์ด๋ค.
์ฐ๋ฆฌ๋ ๊ฐ๊ฐ์ ํด๋์ค๋ค๋ก๋ถํฐ ๊ด๋ จ๋ operation๋ค์ ํจํค์งํ ํ๊ณ , traverse ๋ (tree ์ ๊ฐ node๋ค์ ์ด๋) abstract syntax tree์ element๋ค์๊ฒ ์ธ์๋ก ๋๊ฒจ์ค ์ ์๋ค. ์ด๋ฅผ visitor๋ผ๊ณ ํ๋ค. element๊ฐ visitor๋ฅผ 'accepts' ํ ๋ element๋ element์ ํด๋์ค๋ฅผ ์ธ์ฝ๋ฉํ visitor์๊ฒ request๋ฅผ ๋ณด๋ธ๋ค. ์ด request ๋ํ ํด๋น element๋ฅผ ์ธ์๋ก ํฌํจํ๊ณ ์๋ค. ๊ทธ๋ฌ๋ฉด visitor๋ ํด๋น element์ ๋ํ operation์ ์ํํ ๊ฒ์ด๋ค.
์๋ฅผ๋ ๋ค๋ฉด, visitor๋ฅผ ์ด์ฉํ์ง ์๋ ์ปดํ์ผ๋ฌ๋ ์ปดํ์ผ๋ฌ์ abstact syntax tree์ TypeCheck operation์ ํธ์ถํจ์ผ๋ก์ type-check ์ ์ํํ ๊ฒ์ด๋ค. ๊ฐ๊ฐ์ node๋ค์ node๋ค์ด ๊ฐ์ง๊ณ ์๋ TypeCheck๋ฅผ ํธ์ถํจ์ผ๋ก์จ TypeCheck๋ฅผ ๊ตฌํํ ๊ฒ์ด๋ค. (์์ class diagram ์ฐธ์กฐ). ๋ง์ผ visitor๋ฅผ ์ด์ฉํ๋ค๋ฉด, TypeCheckingVisior ๊ฐ์ฒด๋ฅผ ๋ง๋ ๋ค, TypeCheckingVisitor ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ๋๊ฒจ์ฃผ๋ฉด์ abstract syntax tree์ Accept operation์ ํธ์ถํ ๊ฒ์ด๋ค. ๊ฐ๊ฐ์ node๋ค์ visitor๋ฅผ ๋๋ก ํธ์ถํจ์ผ๋ก์จ Accept๋ฅผ ๊ตฌํํ ๊ฒ์ด๋ค (์๋ฅผ ๋ค์ด, assignment node์ ๊ฒฝ์ฐ visitor์ VisitAssignment operation์ ํธ์ถํ ๊ฒ์ด๊ณ , varible reference๋ VisitVaribleReference๋ฅผ ํธ์ถํ ๊ฒ์ด๋ค.) AssignmentNode ํด๋์ค์ TypeCheck operation์ ์ด์ TypeCheckingVisitor์ VisitAssignment operation์ผ๋ก ๋์ฒด๋ ๊ฒ์ด๋ค.
type-checking ์ ๊ธฐ๋ฅ์ ๋์ด ์ผ๋ฐ์ ์ธ visitor๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋ abstract syntax tree์ ๋ชจ๋ visitor๋ค์ ์ํ abstract parent class์ธ NodeVisitor๊ฐ ํ์ํ๋ค. NodeVisitor๋ ๊ฐ node class๋ค์ ์๋ operation๋ค์ ์ ์ํด์ผ ํ๋ค. ํด๋น ํ๋ก๊ทธ๋จ์ ๊ธฐ์ค ๋ฑ์ ๊ณ์ฐํ๊ธฐ ์ํ๋ application์ node class ์ application-specificํ ์ฝ๋๋ฅผ ์ถ๊ฐํ ํ์ ์์ด, ๊ทธ๋ฅ NodeVisitor์ ๋ํ ์๋ก์ด subclass๋ฅผ ์ ์ํ๋ฉด ๋๋ค. VisitorPattern์ ํด๋น Visitor ์ ์ฐ๊ด๋ ๋ถ๋ถ์์ ์ปดํ์ผ๋ ๊ตฌ๋ฌธ๋ค์ ์ํ operation๋ค์ ์บก์ํํ๋ค.
VisitorPattern์ผ๋ก, ๊ฐ๋ฐ์๋ ๋๊ฐ์ ํด๋์ค ๊ณ์ธต์ ์ ์ํ๋ค. ํ๋๋ operation์ด ์ํ๋ element์ ๋ํ ๊ณ์ธต์ด๊ณ (Node hierarchy), ํ๋๋ element์ ๋ํ operation๋ค์ ์ ์ํ๋ visitor๋ค์ด๋ค. (NodeVisitor hierarchy). ๊ฐ๋ฐ์๋ visitor hierarchy ์ ์๋ก์ด subclass๋ฅผ ์ถ๊ฐํจ์ผ๋ก์ ์ operation์ ๋ง๋ค ์ ์๋ค.
1.5. Participants ¶
- Visitor (NodeVisitor)
- declares a Visit operations for each class of ConcreteElement in the object structure. The operation's name and signature identifies the class that sends the Visit request to the visitor. That lets the visitor determine the concrete class of the element being visited. Then the visitor can access the element directly through its particular interface.
- ConcreteVisitor (TypeCheckingVisitor)
- implements each operation declared by Visitor. Each operation implements a fragment of the algorithm defined for the corresponding class of object in the structure. ConcreteVisitor provides the context for the algorithm and stores its local state. This state often accumulates result during the traversal of the structure.
- Element (Node)
- defines an Accept operation that takes a visitor as an argument.
- ConcreteElement (AssignmentNode, VariableRefNode)
- implements an Accept operation that takes a visitor as an argument.
- ObjectStructure (Program)
- can enumerate its elements.
- may provide a high-level interface to allow the visitor to visit its elements.
- may either be a composite (See CompositePattern) or a collection such as a list or a set.
1.7. Consequences ¶
template <class Item> class Iterator { // ... Item CurrentItem () const; };
class Visitor { public: // ... void VisitMyType (MyType*); void VisitYourType (YourType*); };
1.8. Implementation ¶
class Visitor { public: virtual void VisitElementA (ElementA*); virtual void VisitElementB (ElementB*); // and so on for other concrete elements protected: Visitor (); };
class Element { public: virtual ~Element (); virtual void Accept (Visitor&) = 0; protected: Element (); }; class ElementA : public Element { public: ElementA (); virtual void Accept (Visitor& v) { v.VisitElementA (this); } }; class ElementB : public Element { public: ElementB (); virtual void Accept (Visitor& v) { v.VisitElementB (this); } };
class CompositeElement : public Element { public: virtual void Accept (Visitor&); private: List<Element*>* _children; }; void CompositeElement::Accept (Visitor& v) { ListIterator<Element*> i (_children); for (i.First (); !i.IsDone(); i.Next ()) { i.CurrentItem ()->Accept (v); } v.VisitCompositeElement (this); }
1.9. Sample Code ¶
class Equipment { public: virtual ~Equipment (); const char* Name () { return _name; } virtual Watt Power (); virtual Currency NetPrice (); virtual Currency DiscountPrice (); virtual void Accept (EquipmentVisitor&); protected: Equipment (const char*); private: const char* _name; };
class EquipmentVisitor { public: virtual ~EquipmentVisitor (); virtual void VisitFloppyDisk (FloppyDisk*); virtual void VisitCard (Card*); virtual void VisitrChassis (Chassis*); virtual void VisitBus (Bus*); // and so on for other concrete subclasses of Equipment protected: EquipmentVisitor (); };
void FloppyDisk::Accept (EquipmentVisitor& visitor) { visitor.VisitFloppyDisk (this); }
void Chassis::Accept (EquipmentVisitor& visitor) { for (ListIterator<Equipment*> i(_parts); !i.IsDone (); i.Next ()) { i.CurrentItem ()->Accept (visitor); } visitor.VisitChassis (this); }
class PricingVisitor : public EquipmentVisitor { public: PricingVisitor (); Currency& GetTotalPrice (); virtual void VisitFloppyDisk (FloppyDisk*); virtual void VisitCard (Card*); virtual void VisitChassis (Chassis*); virtual void VisitBus (Bus*); // ... private: Currency _total; }; void PricingVisitor::VisitFloppyDisk (FloppyDisk* e) { _total += e->NextPrice (); } void PricingVisitor::VisitChassis (Chassis* e) { _total += e->DiscountPrice (); }
class InventoryVisitoy : public EquipmentVisitor { public: InventoryVisitor (); Inventory& GetInventory (); virtual void VisitFloppyDisk (FloppyDisk*); virtual void VisitCard (Card*); virtual void VisitChassis (Chassis*); virtual void VisitBus (Bus*); // ... private: Inventory _inventory; };
void InventoryVisitor::VisitFloppyDisk (FloppyDisk* e) { _inventory.Accumulate (e); } void InventoryVisitor::VisitChassis (Chassis* e) { _inventory.Accumulate (e); }
Equipment* component; InventoryVisitor visitor; component->Accept (visitor); cout << "Inventory " << componet->Name () << visitor.GetInventory ();
accept: aVisitor ^ aVisitor visitSequence : self
visitSequence: sequenceExp inputState := sequenceExp expression1 accept: self. ^ sequenceExp expression2 accept: self. visitRepeat : repeatExp | finalState | finalState := inputState copy. [inputState isEmpty] whileFalse: [inputState := repeatExp repetition accept: self. finalState addAll: inputState]. ^ finalState visitAlternation: alternateExp | finalState originalState | originalState := inputState. finalState := alternateExp alternative1 accept: self. inputState := originalState. finalState addAll: (alternateExp alternative2 accept: self). ^ finalState visitLiteral: literalExp | finalState tStream | finalState := Set new. inputState do: [:stream | tStream := stream copy. (tStream nextAvailable: literalExp components size ) = literalExp components ifTrue: [finalState add: tStream] ]. ^ finalState