2012-05-22 1 views
5

Boost :: Spirit에서 Boost::Bind으로 바인드 된 함수에서 expectation_failure을 어떻게 트리거 할 수 있습니까?부스트 스피릿의 함수에서 expectation_failure를 던지려면?

배경 : 복잡한 항목이 포함 된 큰 파일을 구문 분석합니다. 항목이 이전 항목과 일치하지 않을 때 나는 실패하고 expectation_failure (적절한 구문 분석 위치 정보 포함)을 던지고 싶습니다. 항목을 구문 분석 할 때 항목이 이전에 본 것과 일치하지 않는지 결정하는 함수를 바인딩합니다.

나는 그 요점을 보여주는 작은 장난감 예제를 만들었습니다.

: expectation_failure을 던지는

#include <iostream> 
#include <iomanip> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/bind.hpp> 
#include <boost/spirit/include/classic_position_iterator.hpp> 
namespace qi = boost::spirit::qi; 
namespace classic = boost::spirit::classic; 

void checkNum(int const& i) { 
    if (i % 10 != 0) // >> How to throw proper expectation_failure? << 
    std::cerr << "ERROR: Number check failed" << std::endl; 
} 

template <typename Iterator, typename Skipper> 
struct MyGrammar : qi::grammar<Iterator, int(), Skipper> { 
    MyGrammar() : MyGrammar::base_type(start) { 
    start %= qi::eps > qi::int_[boost::bind(&checkNum, _1)]; 
    } 
    qi::rule<Iterator, int(), Skipper> start; 
}; 

template<class PosIter> 
std::string errorMsg(PosIter const& iter) { 
    const classic::file_position_base<std::string>& pos = iter.get_position(); 
    std::stringstream msg; 
    msg << "parse error at file " << pos.file 
     << " line " << pos.line << " column " << pos.column << std::endl 
     << "'" << iter.get_currentline() << "'" << std::endl 
     << std::setw(pos.column) << " " << "^- here"; 
    return msg.str(); 
} 

int main() { 
    std::string in = "11"; 
    typedef std::string::const_iterator Iter; 
    typedef classic::position_iterator2<Iter> PosIter; 
    MyGrammar<PosIter, qi::space_type> grm; 
    int i; 
    PosIter it(in.begin(), in.end(), "<string>"); 
    PosIter end; 
    try { 
    qi::phrase_parse(it, end, grm, qi::space, i); 
    if (it != end) 
     throw std::runtime_error(errorMsg(it)); 
    } catch(const qi::expectation_failure<PosIter>& e) { 
    throw std::runtime_error(errorMsg(e.first)); 
    } 
    return 0; 
} 

나는 10로 나누어 아닌 INT에서이 같은 오류 메시지가 있음을 의미 다음 int는 나눌 수없는 10 때 저는 여기에 단순히 expectation_failure을 던져 싶어

parse error at file <string> line 1 column 2 
'11' 
    ^- here 
+0

조건이 충족 될 때만 정수와 일치하는 int_ 대신 다른 규칙을 만들 수 있습니까? 나는 Spirit을 잘 모릅니다. 그러나 AX에 r_bool과 비슷한 규칙이 있다고 가정합니다.이 규칙은 술어를 감싸고 있습니다. 이것은 매우 일반적인 상황입니다. –

+0

불행히도 이런 것이 필요할 것 같아요 : http://boost-spirit.com/home/articles/qi-example/creating-your-own-parser-component-for-spirit-qi/ – Frank

+0

죄송합니다 그것은 매우 사용자 친화적이지 않은 것을 보아라. 그래서 AX가 필요합니다 :-) –

답변

5

확실치 않지만, phoenix에서 _pass 자리 표시자를 사용하여 구문 분석에 실패 할 수 있다고 생각합니다. 이 같은 것 해야합니다. 늦었지만 어쨌든

bool myfunc(int i) {return i%10 == 0;} 

... 
_int [ _pass = phoenix::bind(myfunc,_1)] 
+0

예, 작동합니다. 감사! – Frank

+1

@Frank _pass를 false로 설정하면 현재 규칙 만 중지되지만 다른 모든 규칙 (일명 문법)은 파서가 전체적으로 중지되지 않습니다. –

0

년 : 당신이 절대적으로 예외를 던질 원하고 on_error 그것을 잡으려고합니다

, 당신은 오류 처리기 on_error는 캐치 아무것도하지 않는 때문에 qi 네임 스페이스에서 expectation_exception을 던져해야 그밖에.

이것은 의미 론적 작업 또는 사용자 지정 파서 구현에 적용될 수 있습니다.

boost::throw_exception(Exception(first, last, component.what(context))); 

Exception는 그 밖에 qi::expactation_exception 아무것도없는 곳에 : 같은

보일 것인가.

의미 론적 동작처럼 손에있는 구성 요소가없는 경우 component.what(..) 대신 자신의 qi::info 개체를 제공해야합니다.

on_error이 지키고있는 컨텍스트 내의 모든 곳에서 던질 수 있습니다.

관련 문제