2011-05-06 2 views
13

런타임시 임의의 수의 규칙을 동적으로 결합하는 Boost.Spirit.Qi 방법이 있는지 궁금합니다. Boost.Spirit의 내부 동작은 여전히 ​​나에게 약간의 수수께끼이지만, 규칙이 객체로 구현 되었기 때문에 실현 가능성이 있습니다. 내 동기는 내 문법의 특정 부분을 쉽게 확장 가능하게 만드는 것입니다.런타임시 Boost.Spirit.Qi 규칙을 동적으로 결합하십시오 (임의의 대체 번호)

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

내 의심이 grammar.copy()에 상속 된 속성을 전달하지 않음으로써 발생한다는 것입니다 : 비주얼 스튜디오 2010에 의해 주어진

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

오류는 다음과 같습니다

는 다음과 같은 인위적인 예를 생각해 보자. 불행히도이 작업을 수행하는 쉬운 방법을 찾을 수 없었으므로 해결 방법을 선택했습니다. 결과적으로, 나는 하나의 마지막 버전을 가지고있다. (그리고 나는 지금까지 주위에 고집 한 누구에게나 감사하고 싶다.). 행동이 정말 이상한되고,

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

그러나, 한 번 I (예 : "[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

관련 문제