2011-05-06 15 views
13

मैं सोच रहा था कि Boost.Spirit.Qi में गतिशील रूप से रनटाइम पर नियमों की मनमानी संख्या को गठबंधन करने का कोई तरीका है या नहीं। Boost.Spirit की आंतरिक कार्यप्रणाली अभी भी मेरे लिए एक रहस्य है, लेकिन चूंकि नियमों को वस्तुओं के रूप में लागू किया जाता है, यह संभव लगता है। मेरी प्रेरणा मेरे व्याकरण के कुछ हिस्सों को आसानी से विस्तारित करना है।रनटाइम पर बूस्ट .pirit.Qi नियमों को गतिशील रूप से संयोजित करें (विकल्पों की मनमानी संख्या)

namespace qi = boost::spirit::qi; 
namespace px = boost::phoenix; 

typedef std::string::const_iterator iterator_t; 

template<typename Expr> 
inline bool parse_full(const std::string& input, const Expr& expr) 
{ 
    iterator_t first(input.begin()), last(input.end()); 

    bool result = qi::phrase_parse(first, last, expr, boost::spirit::ascii::space); 

    return first == input.end() && result; 
} 

void no_op() {} 

int main(int argc, char *argv[]) 
{ 
    int attr = -1; 

    // "Static" version - Works fine! 
    /* 
    qi::rule<iterator_t, void(int&)> grammar; 

    qi::rule<iterator_t, void(int&)> ruleA = qi::char_('a')[qi::_r1 = px::val(0)]; 
    qi::rule<iterator_t, void(int&)> ruleB = qi::char_('b')[qi::_r1 = px::val(1)]; 
    qi::rule<iterator_t, void(int&)> ruleC = qi::char_('c')[qi::_r1 = px::val(2)]; 

    grammar = 
     ruleA(qi::_r1) | //[no_op] 
     ruleB(qi::_r1) | //[no_op] 
     ruleC(qi::_r1); //[no_op] 
    */ 

    // "Dynamic" version - Does not compile! :(

    std::vector<qi::rule<iterator_t, void(int&)>> rules; 

    rules.push_back(qi::char_('a')[qi::_r1 = px::val(0)]); 
    rules.push_back(qi::char_('b')[qi::_r1 = px::val(1)]); 
    rules.push_back(qi::char_('c')[qi::_r1 = px::val(2)]); 

    std::vector<qi::rule<iterator_t, void(int&)>>::iterator i(rules.begin()), last(rules.end()); 

    qi::rule<iterator_t, void(int&)> grammar; 

    grammar = (*i)(qi::_r1); 

    for(++i; i!=last; ++i) 
    { 
     grammar = grammar.copy() | (*i)(qi::_r1); 
    } 

    // Tests 

    if(parse_full("a", grammar(px::ref(attr)))) std::cout << attr << std::endl; 
    if(parse_full("b", grammar(px::ref(attr)))) std::cout << attr << std::endl; 
    if(parse_full("c", grammar(px::ref(attr)))) std::cout << attr << std::endl; 

    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 

    return 0; 
} 

विजुअल स्टूडियो 2010 के द्वारा दिए गए त्रुटि है:

निम्नलिखित काल्पनिक उदाहरण पर विचार करें

error C2440: 'initializing' : cannot convert from 'boost::fusion::void_' to 'int &' 

मेरे संदेह है कि इस grammar.copy() को विरासत में मिला विशेषता गुजर नहीं के कारण होता है। दुर्भाग्यवश, मुझे ऐसा करने का एक आसान तरीका नहीं मिला, इसलिए मैंने एक कामकाज का चयन किया। नतीजतन, मेरे पास एक आखिरी संस्करण है (और मैं पहले से ही किसी भी व्यक्ति को धन्यवाद देना चाहूंगा जो अब तक अटक गया है!)। यह एक वास्तव में काम करने के लिए लगता है:

// "Dynamic" version - Kind of works! :-/ 

    std::vector<qi::rule<iterator_t, void(int&)>> rules; 

    rules.push_back(qi::char_('a')[qi::_r1 = px::val(0)]); 
    rules.push_back(qi::char_('b')[qi::_r1 = px::val(1)]); 
    rules.push_back(qi::char_('c')[qi::_r1 = px::val(2)]); 

    std::vector<qi::rule<iterator_t, void(int&)>>::iterator i(rules.begin()), last(rules.end()); 

    qi::rule<iterator_t, int()> temp; 

    temp = (*i)(qi::_val); //[no_op] 

    for(++i; i!=last; ++i) 
    { 
     temp = temp.copy() | (*i)(qi::_val); //[no_op] 
    } 

    qi::rule<iterator_t, void(int&)> grammar; 

    grammar = temp[qi::_r1 = qi::_1]; 

हालांकि, एक बार मैं (जैसे कि "[no_op]" के रूप में) एक सरल अर्थ कार्रवाई देते हैं, व्यवहार वास्तव में अजीब हो जाता है। 0,1,2 पहले प्रिंट करने की बजाय, यह 0,0,2 प्रिंट करता है। तो मैं सोच रहा हूं, क्या मैं पूरा करने की कोशिश कर रहा हूं जिसके परिणामस्वरूप अपरिभाषित व्यवहार है? क्या यह एक बग है? या काफी संभवतः, क्या मैं सिर्फ कुछ (उदाहरण के लिए अर्थपूर्ण क्रियाएं) गलत तरीके से उपयोग कर रहा हूं?

उत्तर

7

हाँ मैं वास्तव में समझने के लिए कि यह कैसे आंतरिक रूप से काम करते हैं यकीन नहीं है, लेकिन आप पाश के लिए अपने में सभी नियमों को कॉपी नहीं है (केवल छोड़ दिया एक) तो यह काम करने के लिए लगता है:

std::vector<qi::rule<iterator_t, void(int&)>> rules; 

rules.push_back(qi::char_('a')[qi::_r1 = px::val(0)]); 
rules.push_back(qi::char_('b')[qi::_r1 = px::val(1)]); 
rules.push_back(qi::char_('c')[qi::_r1 = px::val(2)]); 

std::vector<qi::rule<iterator_t, void(int&)>>::iterator 
i(rules.begin()), last(rules.end()); 

qi::rule<iterator_t, int()> temp; 

for(; i!=last; ++i) 
{ 
qi::rule<iterator_t, int()> tmp = (*i)(qi::_val)[no_op]; 

    temp = temp.copy() | tmp.copy(); 
} 

qi::rule<iterator_t, void(int&)> grammar; 

grammar = temp[qi::_r1 = qi::_1]; 

// Tests 

int intres1; 
int intres2; 
int intres3; 

bool res1 = parse_full("a", grammar(px::ref(intres1))); 
bool res2 = parse_full("b", grammar(px::ref(intres2))); 
bool res3 = parse_full("c", grammar(px::ref(intres3))); 
+0

धन्यवाद! आपका जवाब बहुत ही आशाजनक दिखता है। दुर्भाग्य से, मेरे पास अभी इसका परीक्षण करने का कोई साधन नहीं है। जैसे ही मुझे इसे आजमाने का मौका मिलता है, मैं इसे स्वीकार करूंगा! – kloffy

+0

क्या यह ठीक काम करता है? –

+1

लगभग 2 साल देर से होने के लिए ईमानदारी से माफ़ी। अब मैं इस समाधान का परीक्षण करने के लिए चारों ओर आया हूं और यह बहुत अच्छा काम करता है! – kloffy

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