2012-05-22 29 views
5

Trong Boost :: Spirit, làm thế nào tôi có thể kích hoạt một expectation_failure từ một chức năng ràng buộc với Boost::Bind?Làm thế nào để ném một expectation_failure từ một chức năng trong Tăng Thần?

Thông tin cơ bản: Tôi phân tích cú pháp tệp lớn chứa các mục nhập phức tạp. Khi một mục nhập không phù hợp với mục nhập trước tôi muốn thất bại và ném một số expectation_failure (chứa thông tin vị trí phân tích thích hợp). Khi tôi phân tích cú pháp một mục, tôi ràng buộc một hàm quyết định xem mục nhập có không phù hợp với một cái gì đó đã thấy trước đây không.

Tôi đã tạo ra một ví dụ về đồ chơi nhỏ thể hiện quan điểm. Ở đây tôi chỉ đơn giản là muốn ném một expectation_failure khi int là không chia hết cho 10:

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

Ném một expectation_failure sẽ có nghĩa là tôi nhận được một thông báo lỗi như thế này trên một int mà không chia hết cho 10:

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

Bạn có thể tạo quy tắc khác thay vì int_, mã này chỉ khớp với số nguyên khi điều kiện của bạn được thỏa mãn không? Tôi không biết rõ về Thần Khí, nhưng tôi cho rằng có một quy tắc tương tự như r_bool trong AX, kết thúc tốt đẹp một vị ngữ, đó là tình huống khá phổ biến. –

+0

Tôi nghĩ tôi sẽ cần một cái gì đó như thế này, thật không may: http://boost-spirit.com/home/articles/qi-example/creating-your-own-parser-component-for-spirit-qi/ – Frank

+0

Xin lỗi thấy rằng, nó rất thân thiện với người dùng. Đó là lý do tại sao bạn cần AX :-) –

Trả lời

5

Tôi không chắc chắn, nhưng tôi nghĩ rằng u có thể sử dụng trình giữ chỗ _pass trong phoenix để thực thi lỗi phân tích cú pháp. Một cái gì đó như thế này nên làm việc.

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

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

Có, nó hoạt động. Cảm ơn! – Frank

+1

@Frank xin lưu ý rằng, cài đặt _pass thành false sẽ chỉ dừng quy tắc hiện tại nhưng không phải là toàn bộ phân tích cú pháp với tất cả các quy tắc khác (còn gọi là ngữ pháp của bạn). –

0

năm cuối nhưng dù sao:

Nếu bạn hoàn toàn muốn ném một ngoại lệ và muốn on_error để bắt nó, bạn phải ném expectation_exception từ namespace qi vì các lỗi xử lý on_error không bắt gì khác.

Điều này có thể áp dụng cho hành động ngữ nghĩa hoặc triển khai trình phân tích cú pháp tùy chỉnh.

sẽ trông giống như:

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

nơi Exception là gì qi::expactation_exception và khác.

Nếu bạn không có thành phần nào giống như trong hành động ngữ nghĩa, bạn phải cung cấp đối tượng qi::info của riêng mình thay vì component.what(..).

Bạn có thể ném từ mọi nơi trong bối cảnh được bảo vệ bởi on_error.

Các vấn đề liên quan