अधिक आत्मा पागलपन - पार्सर-प्रकार (नियम बनाम int_parser <>) और मेटा-प्रोग्रामिंग तकनीक


80

सवाल नीचे की ओर बोल्ड है, समस्या को अंत तक आसवन कोड के टुकड़े द्वारा संक्षेपित किया गया है।

मैं अपने कंपोनेंट सिस्टम को टाइप करने की कोशिश कर रहा हूं (टाइप सिस्टम से टाइप करने के लिए स्ट्रिंग से) सिंगल कंपोनेंट में (जैसा कि लक्की द्वारा परिभाषित किया गया है)। मैं उपयोग कर रहा हूँ boost::array, boost::variantऔर boost::mpl, क्रम में इस लक्ष्य को हासिल करने के लिए। मैं चाहता हूं कि एक प्रकार में एकीकृत मेरे प्रकार के लिए पार्सर और जनरेटर नियम हों। एक अपरिभाषित प्रकार है, एक int4 (नीचे देखें) प्रकार और एक int8 प्रकार। संस्करण के रूप में पढ़ता है variant<undefined, int4,int8>

int4 लक्षण:

struct rbl_int4_parser_rule_definition
{
  typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type;

  boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;

  rule_type rule;

  rbl_int4_parser_rule_definition()
  {
    rule.name("rbl int4 rule");
    rule = parser_int32_t;  
  }
};

template<>
struct rbl_type_parser_rule<rbl_int4>
{
  typedef rbl_int4_parser_rule_definition string_parser;
};

उपरोक्त संस्करण अपरिभाषित के रूप में बाहर शुरू होता है, और फिर मैं नियमों को आरंभ करता हूं। मुझे एक समस्या थी, जिसके कारण 50 पृष्ठों की त्रुटियां हुईं, और मैं अंत में इसे नीचे ट्रैक करने में कामयाब रहा, वेरिएंट का उपयोग करता हैoperator= हुईं असाइनमेंट के दौरान और किसी boost::spirit::qi::int_parser<>अन्य (ऑपरेटर =) को नहीं सौंपा जा सकता है।

इसके विपरीत, मुझे अपने अपरिभाषित प्रकार से कोई समस्या नहीं है:

struct rbl_undefined_parser_rule_definition
{
  typedef boost::spirit::qi::rule<std::string::iterator, void()> rule_type;
  rule_type rule;

  rbl_undefined_parser_rule_definition()
  {
    rule.name("undefined parse rule");
    rule = boost::spirit::qi::eps;
  }
};

template<>
struct rbl_type_parser_rule<rbl_undefined>
{
  typedef rbl_undefined_parser_rule_definition string_parser;
};

समस्या का आसवन:

#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <boost/cstdint.hpp>

typedef boost::spirit::qi::rule<std::string::iterator,void()> r1;
typedef boost::spirit::qi::rule<std::string::iterator,int()> r2;

typedef boost::variant<r1,r2> v;

int main()
{
  /*
  problematic
  boost::spirit::qi::int_parser<int32_t> t2;
  boost::spirit::qi::int_parser<int32_t> t1;


  t1 = t2;
  */

  //unproblematic
  r1 r1_;
  r2 r2_;
  r1_ = r2_;

  v v_;
  // THIS is what I need to do.
  v_ = r2();
}

कंक्रीट पार्सर और नियमों के बीच एक अर्थपूर्ण अंतर है। मेरा मस्तिष्क इस समय धूम्रपान कर रहा है, इसलिए मैं व्यावहारिकता के बारे में सोचने वाला नहीं हूं, मेरा सवाल यह है कि मैं इस समस्या को कैसे हल करूं? मैं समस्या को हल करने के लिए तीन तरीकों के बारे में सोच सकता हूं।

एक: स्टेटिक फ़ंक्शन सदस्य:

struct rbl_int4_parser_rule_definition
{
  typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type;

  //boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;

  rule_type rule;

  rbl_int4_parser_rule_definition()
  {
    static boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;

    rule.name("rbl int4 rule");
    rule = parser_int32_t;  
  }
};

मुझे लगता है कि दृष्टिकोण एक सुरक्षित कोड को रोकता है? ?

दो: इंटीग्रल पार्सर एक शेयर्ड_प्ट्र में लपेटा जाता है। टाइपिंग सिस्टम के लिए टीएमपी के साथ परेशान होने के दो कारण हैं: 1 दक्षता, 2 केंद्रीयकरण संबंधी चिंताएं घटकों में। पॉइंटर्स का उपयोग करना पहला कारण है।

तीन: ऑपरेटर = को नो-ऑप के रूप में परिभाषित किया गया है। वेरिएंट गारंटी देता है कि lhsअसाइनमेंट से पहले डिफ़ॉल्ट रूप से निर्मित है।

संपादित करें: मैं सोच रहा हूं विकल्प 3 सबसे अधिक समझ में आता है (ऑपरेटर = एक नो-ऑप है)। एक बार नियम कंटेनर बन जाने के बाद यह नहीं बदलेगा, और मैं केवल एक प्रकार के नियम विशेषता को इसकी भरपाई करने के लिए बाध्य करने का काम कर रहा हूं।


1
विकल्प 1 केवल थ्रेड असुरक्षित है यदि: parser_int32_tराज्य है और एक संदर्भ लिया गया है। यदि स्टेटलेस है या कॉपी बनाई गई है, तो यह सुरक्षित है। शब्दार्थ से, मैं कहूंगा कि एक प्रति बनाई गई है।
मैथ्यू एम।

यह काफी भ्रामक चिंता है, मैं निश्चित नहीं हो सकता कि पार्सर वस्तु में स्थिति नहीं है। इसके अलावा, नियम यांत्रिकी के साथ संदर्भ और ठोस शब्दार्थ हैं, -आई, एक नियम अन्य नियमों के संदर्भ में पकड़ सकता है, लेकिन वे खुद भी कंक्रीट पार्सर हो सकते हैं (मुझे लगता है), और मुझे नहीं पता कि ये शब्दार्थ कंक्रीट पार्सर पर कैसे लागू होते हैं ।
हसन सैयद

@ मैथ्यूएमएम: सही है, जब तक .alias()उपयोग नहीं किया जाता है तब तक एक प्रति बनाई जाती है।
१।

@ चिल्ड्रन लेकिन एक नियम एक ठोस पार्सर नहीं है: डी एक नियम की सामग्री एक अभिव्यक्ति है, एक पार्स पेड़ के बराबर है।
हसन सैयद

1
मैं मूल्यांकन नहीं कर सकता कि # 1 धागा-सुरक्षित होगा या नहीं, लेकिन मैं एक सलाह दे सकता हूं जिसे भूलना आसान है। एक स्थैतिक असाइनमेंट केवल एक बार संकलक द्वारा मूल्यांकन किया जाता है। कोड में थोड़ी सी जाँच की कल्पना करें (यदि (मूल्यांकन किया गया है) तो मूल्यांकन करें () और नहीं ()। पहली बार किसी भी rbl_int4_parser_rule_definition के प्रासंगिक सदस्य ऑब्जेक्ट को कहीं भी बुलाया जाता है, इसका निर्माण उस एक समय में किया जाएगा। यह एक वैश्विक सिंगलटन का उपयोग करने के लिए लगभग बिल्कुल बराबर है। क्या आप उसी समस्या के समाधान के लिए उस प्रकार के एक वैश्विक सिंगलटन का उपयोग कर सकते हैं? (inti। आदेश आदि की उपेक्षा करना) यदि ऐसा है, तो यह थ्रेड-सुरक्षित होना चाहिए।
std''OrgnlDave

जवाबों:


11

मुझे यकीन नहीं है कि मुझे प्रश्न की पूरी सीमा मिल जाएगी, लेकिन यहां कुछ संकेत हैं

  • रेखा ने // THIS is what I need to do.मेरे साथ ठीक संकलित टिप्पणी की (समस्या हल हो गई? मुझे लगता है कि आप वास्तव में एक नियम नहीं बल्कि एक पार्सर असाइन करने का मतलब है?)

  • फंक्शन-लोकल staticकी शुरुआत को नवीनतम मानक (C ++ 11) में सुरक्षित रूप से परिभाषित किया गया है। C ++ 0x थ्रेडिंग के लिए अपने संकलक समर्थन की जाँच करें। (यदि इनिलाइज़र फेंकता है, तो इनिशियलाइज़ेशन स्टेटमेंट का एक तरीका फिर से इनिशियलाइज़ करने की कोशिश करेगा)।

  • नियमों alias()

    जैसा कि http://boost-spirit.com/home/articles/doc-addendum/faq/#aliases में वर्णित है

    आप वास्तव में प्रोटो एक्सप्रेशन को कॉपी-वैल्यू किए बिना नियमों की 'तार्किक प्रतियां' बना सकते हैं। जैसा कि एफएक्यू कहता है, यह मुख्य रूप से आलसी-बाध्यकारी की अनुमति है

  • Nabialek चाल ठीक हो सकता है कि तुम क्या जरूरत है, मूल रूप से यह lazily बाद पार्सिंग के लिए एक पार्सर का चयन करता है

    one = id;
    two = id >> ',' >> id;
    
    keyword.add
        ("one", &one)
        ("two", &two)
        ;
    
    start = *(keyword[_a = _1] >> lazy(*_a));
    

    आपके संदर्भ में, मैं keywordपरिभाषित के रूप में देख सकता था

    qi::symbols<char, qi::rule<Iterator>*> keyword;
    

    सिमेंटिक क्रियाओं से विशेषताओं के साथ सभी कार्य करना। वैकल्पिक रूप से,

    qi::symbols<char, qi::rule<Iterator, std::variant<std::string,int>() >*> keyword;
    
  • नियमों को उसी प्रकार से लाएं (जैसे पिछली पंक्ति में दिखाया गया है, मूल रूप से)

    यह वह हिस्सा है जहां मैं भ्रमित हो रहा हूं: आप कहते हैं कि आप अपने प्रकार की प्रणाली को एकीकृत करना चाहते हैं। मजबूत पेर्सर्स (विशिष्ट विशेषता हस्ताक्षर) की आवश्यकता नहीं हो सकती है।

    typedef boost::variant<std::string,int> unified_type;
    typedef qi::rule<std::string::iterator, unified_type() > unified_rule;
    
    unified_rule rstring = +(qi::char_ - '.');
    unified_rule rint    = qi::int_;
    
    unified_rule combine = rstring | rint;
    
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.