2013-04-23 6 views
10

मुझे एएसटी नेविगेट करने के लिए एक विज़िटर पैटर्न लिखना है। क्या कोई मुझे और बता सकता है कि मैं इसे कैसे लिखना शुरू करूंगा? जहां तक ​​मैं समझता हूं, एएसटी में प्रत्येक नोड में विज़िट() विधि (?) होती है जिसे किसी भी तरह से कहा जाता है (कहां से?)। यह मेरी समझ को समाप्त करने के बारे में है। सब कुछ आसान बनाने के लिए, मैं नोड्स रूट, अभिव्यक्ति, संख्या, Op और पेड़ इस तरह दिखता है लगता है:सी # में एक सार सिंटेक्स ट्री के लिए विज़िटर पैटर्न कैसे लिखें?

 Root 
     | 
     Op(+) 
    / \ 
    / \ 
Number(5) \ 
      Op(*) 
      / \ 
      / \ 
     /  \ 
     Number(2) Number(444) 
+0

गृहकार्य? यदि नहीं - आप क्या करने की कोशिश कर रहे हैं? –

+1

आप इस परियोजना में रुचि रखते हैं, [अभिव्यक्ति इंजन] (https://github.com/gsscoder/exprengine)। सी # में लिखा गया; आगंतुक पैटर्न का प्रयोग करें। – jay

+2

पहले से ही पूछा गया है? http://stackoverflow.com/questions/2525677/how-to-write-the-visitor-pattern-for-abstract-syntax-tree-in-python – jwaliszko

उत्तर

18

पैटर्न आगंतुक एक डिजाइन पैटर्न है कि आप मनमाने ढंग से संचालन को लागू करने की अनुमति देता है (आगंतुकों के रूप में लागू) पर है पार्स पेड़ (उदाहरण के लिए टाइप-चेकिंग) पार्स पेड़ के नोड्स के कार्यान्वयन को संशोधित किए बिना।

यह नीचे दिए तरीक़े (i स्यूडोकोड उपयोग कर रहा हूँ) में लागू किया जा सकता है:

पहले तुम पेड़ नोड्स कि सभी नोड्स को लागू करना का आधार वर्ग को परिभाषित करने की जरूरत है।

abstract class VisitableNode { 
    abstract void accept(Visitor v); 
} 

नोड कक्षाओं को लागू करने वाली एकमात्र विधि स्वीकृति विधि है।

फिर आपको अपने पार्स-पेड़ के विज़िटर नोड के बेस-क्लास को परिभाषित करना चाहिए।

abstract class Visitor { 
    abstract void visit(Root rootNode); 
    abstract void visit(Op opNode); 
    abstract void visit(Number number); 
} 

ध्यान दें कि आगंतुक का आधार स्तर के केवल अपने पार्स पेड़ के लिए किया जाता है, और हर नोड प्रकार आप अपने पार्स पेड़ में परिभाषित के लिए एक यात्रा विधि होनी चाहिए।

फिर, आप अपने नोड कक्षाएं कार्यान्वयन निम्नलिखित तरीके से VisitableNode वर्ग का विस्तार देना चाहिए:

class Root : VisitableNode { 
    [...] 
    void accept(Visitor v) { 
     v.visit(this); 
    } 
} 

class Op : VisitableNode { 
    [...] 
    void accept(Visitor v) { 
     v.visit(this); 
    } 
} 

class Number : VisitableNode { 
    [...] 
    void accept(Visitor v) { 
     v.visit(this); 
    } 
} 

अब आप अपने पार्स-वृक्ष संरचना है कि परिवर्तन नहीं होना चाहिए, और आप के रूप में कई को लागू करने के लिए स्वतंत्र हैं आगंतुकों (संचालन) जैसा आप चाहें। आदि NumberFloat, NumberInteger, NumberDouble,

:

आदेश प्रकार की जाँच करने के लिए, आप अपने मूल्य के साथ एक साथ संख्या वर्ग के अंदर एक प्रकार की दुकान, या अन्यथा हर प्रकार के समर्थन के लिए एक संख्या वर्ग के लिए होगा

उदाहरण के तौर पर, मान लीजिए कि आपके पास अपनी संख्या वर्ग से मूल्य के स्थिर प्रकार का अनुमान लगाने का एक तरीका है।

मैं यह भी मानूंगा कि आप विधि getChild (int childIndex) विधि से नोड के बच्चों तक पहुंच सकते हैं।

अंत में, मैं एक वर्ग प्रकार का उपयोग करूंगा जो तुच्छ रूप से एक स्थिर प्रकार का प्रतिनिधित्व करता है जिसका आप समर्थन करना चाहते हैं (जैसे फ्लोट, इंटेगर, आदि ...)।

class TypeCheckVisitor : Visitor { 

    // Field used to save resulting type of a visit 
    Type resultType; 


    void visit(Root rootNode) 
    { 
     rootNode.getChild(0).accept(this); 
    } 

    void visit(Op opNode) 
    { 
     opNode.getChild(0).accept(this); 
     Type type1 = resultType; 

     opNode.getChild(1).accept(this); 
     Type type2 = resultType; 

     // Type check 
     if(!type1.isCompatible(type2)){ 
     // Produce type error 
     } 

     // Saves the return type of this OP (ex. Int + Int would return Int) 
     resultType = typeTableLookup(opNode.getOperator(), type1, type2); 
    } 

    void visit(Number number) 
    { 
     // Saves the type of this number as result 
     resultType = number.getType(); 
    } 
} 

उसके बाद, आप एक तरह से करने के लिए इसी में एक enum के रूप में शायद प्रकार वर्ग को लागू होगा:

enum Type { 
    Double, 
    Float, 
    Integer; 

    boolean isCompatible(Type type1, Type type2){ 
     // Lookup some type table to determine types compatibility 
    } 
} 

और अंत में आप केवल अपने प्रकार टेबल और ऑपरेटर टेबल लागू करने के लिए की जरूरत है।

संपादित करें: विज़िट रिकर्सन में, वास्तव में उन नोड्स की स्वीकृति विधि का उपयोग करके पुनरावृत्ति करना सही है, जिन पर आप पुनरावृत्ति करना चाहते हैं।

TypeCheckVisitor v = new TypeCheckVisitor(); 
rootNode.accept(v); 
print("Root type is: " + v.resultType); 

तुम भी की एक मनमाना नोड टाइप-जाँच कर सकते हैं:

उपयोग के लिए के रूप में, आप प्रकार की जाँच पार्स पेड़ की जड़ नोड पर से प्रदर्शन कर सकते हैं (और साथ ही अभिव्यक्ति के प्रकार का निर्धारण) पार्स पेड़ उसी तरह रूट से अलग है।

+0

धन्यवाद, यह एक उपयोगी स्पष्टीकरण था। –

संबंधित मुद्दे