2011-05-06 17 views
13

Boost.Spirit.Qi uygulamasının çalışma zamanında rasgele sayıdaki kuralları dinamik olarak birleştirip birleştirmediğini merak ediyordum. Boost.Spirit'in iç işleyişi hala benim için bir gizem. Ama kurallar objeler olarak uygulandığından uygulanabilir görünüyor. Benim motivasyonum, gramerimin bazı bölümlerini kolayca genişletilebilir yapmaktır.Çalışma zamanında Boost.Spirit.Qi kurallarını dinamik olarak birleştirin (isteğe bağlı seçenek sayısı)

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

Benim şüphe bu grammar.copy() için miras niteliği geçmediğine neden olmasıdır: Visual Studio 2010 tarafından verilen

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; 
} 

hatadır:

aşağıdaki yapmacık örneği ele alalım. Ne yazık ki, bunu yapmanın kolay bir yolunu bulamadım, bu yüzden bir geçici çözüm seçtim. Sonuç olarak, son bir versiyonum var (ve şimdiye kadar sıkışmış olan herkese şimdiden teşekkür etmek istiyorum!). davranış gerçekten garip olur,

// "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]; 

Ancak, bir kez (örneğin, "[no_op]" gibi) basit bir semantik eylemi takmak: Bu aslında çalışıyor gibi görünüyor. Daha önce olduğu gibi 0,1,2 basmak yerine, 0,0,2 basıyor. Bu yüzden merak ediyorum, tanımlanamayan davranışlarla sonuçlanmaya çalıştığım şey nedir? Bu bir hata mı? Ya da büyük olasılıkla, sadece bir şey (örneğin, semantik eylemler?) Yanlış yol kullanıyor muyum?

cevap

7

Evet Gerçekten içten nasıl çalıştığını anlamak için emin değilim ama döngü Gözlerinde farklı (sadece sol bir) tüm kuralları kopyalamak kalmamak bu iş gibi görünüyor:

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

teşekkür ederiz! Cevabınız çok umut verici görünüyor. Maalesef, şu anda test etme imkanım yok. Bunu denemek için bir şans elde eder etmez kabul edeceğim! – kloffy

+0

Bu düzeltme çalışması mı? –

+1

Neredeyse iki yıl geç kaldığım için samimi özür dilerim. Şimdi bu çözümü test etmek için geldim ve harika çalışıyor! – kloffy