2012-05-22 15 views
5

Boost :: Spirit uygulamasında, 'u Boost::Bind ile bağlı bir işlevden nasıl tetikleyebilirim?Boost Spirit'de bir işlevden beklenti_failesi nasıl atılır?

Arka plan: Karmaşık girdiler içeren büyük bir dosyayı ayrıştırıyorum. Bir giriş bir önceki girişle tutarsız olduğunda, başarısız olmak ve bir expectation_failure (uygun ayrıştırma konum bilgisi içeren) atmak istiyorum. Bir girişi ayrıştırdığımda, girişin daha önce görülen bir şeyle tutarsız olup olmadığına karar veren bir işlevi bağlarım.

Bu noktayı gösteren küçük bir oyuncak örneği hazırladım.

: Bir expectation_failure Fırlatma

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

Ben 10 ile bölünebilir olmayan bir int üzerinde böyle bir hata mesajı almak anlamına gelir: int değil bölünebilir 10 tarafından olduğunda İşte ben sadece bir expectation_failure atmak istiyorum

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

Int_ yerine başka bir kural oluşturabilir, tamsayı yalnızca durumunuz memnun olduğunda eşleşir mi? Ruh'u iyi bilmiyorum, ama AX'de r_bool'a benzer bir kural olduğunu varsayardım, bu da bir yüklemi tamamlar, oldukça yaygın bir durumdur. –

+0

Sanırım böyle bir şeye ihtiyacım var, maalesef: http://boost-spirit.com/home/articles/qi-example/creating-your-own-parser-component-for-spirit-qi/ – Frank

+0

Üzgünüz bakın, bu çok kullanıcı düşmanca. İşte bu yüzden AX :-) –

cevap

5

Emin değilim, ama ayrıştırmayı zorlamak için _pass yer tutucuyu phoenix'de kullanabileceğimi düşünüyorum. Bu gibi bir şey, çalışmalıdır. Geç ama yine

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

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

'a ihtiyacınız var, işe yarıyor. Teşekkürler! – Frank

+1

@Frank, _pass değerini false olarak ayarlamanın yalnızca geçerli kuralı durduracaktır, ancak ayrıştırıcıyı tüm diğer kurallarla (dilbilgisi olarak) bütünleştirmeyeceğini lütfen unutmayın. –

0

Yıl: kesinlikle bir istisna istiyor ve on_error yakalamak istiyorsanız

, hata işleyicisi on_error yakalamak şey yapmaz çünkü qi ad alanından expectation_exception atmak zorunda Başka.

Bu, semantik eylem veya özel ayrıştırıcı uygulaması için geçerli olabilir.

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

Exception başka bir qi::expactation_exception ve hiçbir şey olduğu gibi:

olmazdı.

Elinizdeki bir bileşenin semantik bir eylemdeki gibi olmaması durumunda, component.what(..) yerine kendi qi::info nesnesini sağlamanız gerekir.

on_error tarafından korunan bir içeriğin her yerinden atlayabilirsiniz.

İlgili konular