2010-03-11 42 views
6

我有一個記錄分析器,它會拋出幾個異常中的一個來指示哪個規則失敗。使用boost :: spirit,我如何要求記錄的一部分在自己的行上?

前面的問題:

#include <iostream> 
#include <sstream> 
#include <stdexcept> 
#include <string> 

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/spirit/include/classic_position_iterator.hpp> 

using namespace boost::spirit; 
using namespace boost::spirit::ascii; 
using namespace boost::spirit::qi; 
using namespace boost::spirit::qi::labels; 

using boost::phoenix::function; 
using boost::phoenix::ref; 
using boost::spirit::qi::eol; 
using boost::spirit::qi::fail; 
using boost::spirit::qi::lit; 
using boost::spirit::qi::on_error; 

using BOOST_SPIRIT_CLASSIC_NS::file_position; 
using BOOST_SPIRIT_CLASSIC_NS::position_iterator; 

我們使用Spirit.Classicposition_iterator,所以下面流插入操作更是得心應手。

std::ostream& 
operator<<(std::ostream& o, const file_position &fp) 
{ 
    o << fp.file << ": " << fp.line << ',' << fp.column; 
    return o; 
} 

模板err_t因素出樣板扔不同形式解析失敗有關的例外情況。

template <typename Exception> 
struct err_t { 
    template <typename, typename, typename> 
    struct result { typedef void type; }; 

    template <typename Iterator> 
    void operator() (info const &what, Iterator errPos, Iterator last) const 
    { 
    std::stringstream ss; 
    ss << errPos.get_position() 
     << ": expecting " << what 
     << " near '" << std::string(errPos, last) << "'\n"; 
    throw Exception(ss.str()); 
    } 
}; 

與他們err_t包裝一起使用的例外:

class MissingA : public std::runtime_error { 
    public: MissingA(const std::string &s) : std::runtime_error(s) {} 
}; 

class MissingB : public std::runtime_error { 
    public: MissingB(const std::string &s) : std::runtime_error(s) {} 
}; 

class MissingC : public std::runtime_error { 
    public: MissingC(const std::string &s) : std::runtime_error(s) {} 
}; 

function<err_t<MissingA> > const missingA = err_t<MissingA>(); 
function<err_t<MissingB> > const missingB = err_t<MissingB>(); 
function<err_t<MissingC> > const missingC = err_t<MissingC>(); 
function<err_t<std::runtime_error> > const other_error = 
    err_t<std::runtime_error>(); 

語法看起來簡單的序列。如果沒有eps,在start規則失敗,而不是a上的空白輸入。

template <typename Iterator, typename Skipper> 
struct my_grammar 
    : grammar<Iterator, Skipper> 
{ 
    my_grammar(int &result) 
    : my_grammar::base_type(start) 
    , result(result) 
    { 
    a = eps > lit("Header A") > eol; 
    b = eps > lit("Header B") > eol; 
    c = eps > lit("C:") > int_[ref(result) = _1] > eol; 
    start = a > b > c; 

    a.name("A"); 
    b.name("B"); 
    c.name("C"); 

    on_error<fail>(start, other_error(_4, _3, _2)); 
    on_error<fail>(a, missingA(_4, _3, _2)); 
    on_error<fail>(b, missingB(_4, _3, _2)); 
    on_error<fail>(c, missingC(_4, _3, _2)); 
    } 

    rule<Iterator, Skipper> start; 
    rule<Iterator, Skipper> a; 
    rule<Iterator, Skipper> b; 
    rule<Iterator, Skipper> c; 
    int &result; 
}; 

my_parse,我們傾流的內容爲std::string,並使用position_iterator跟蹤解析的位置。

int 
my_parse(const std::string &path, std::istream &is) 
{ 
    std::string buf; 
    is.unsetf(std::ios::skipws); 
    std::copy(std::istream_iterator<char>(is), 
      std::istream_iterator<char>(), 
      std::back_inserter(buf)); 

    typedef position_iterator<std::string::const_iterator> itertype; 
    typedef my_grammar<itertype, boost::spirit::ascii::space_type> grammar; 
    itertype it(buf.begin(), buf.end(), path); 
    itertype end; 

    int result; 
    grammar g(result); 

    bool r = phrase_parse(it, end, g, boost::spirit::ascii::space); 
    if (r && it == end) { 
    std::cerr << "success!\n"; 
    return result; 
    } 
    else { 
    file_position fpos = it.get_position(); 
    std::cerr << "parse failed at " << fpos << '\n'; 
    return -9999; 
    } 
} 

最後,主程序

int main() 
{ 
    std::stringstream ss; 
    ss << "Header A\n" 
    << "Header B\n" 
    << "C: 3\n"; 

    int val = my_parse("path", ss); 
    std::cout << "val = " << val << '\n'; 

    return 0; 
} 

上面的代碼拋出MissingA

terminate called after throwing an instance of 'MissingA' 
    what(): path: 2,1: expecting near 'Header B 
C: 3 
'

我想船長可能已經消耗的換行符,但試圖lexeme[eol],而不是產生相同的結果。

我必須失去了一些東西明顯,因爲這似乎是最微不足道的排序解析器寫的之一。我究竟做錯了什麼?

回答

7

是的,船長吃掉換行符。 lexeme[eol]也沒有幫助,因爲在切換到無船長模式之前,lexeme指令調用船長(有關更多詳細信息,請參閱here)。

爲了避免跳過換行符,既可以使用不同的船長類型,或包裹eol部件成no_skip[eol],這是語義上等價於lexeme[],只是它不調用船長。但請注意,最近只有no_skip[]已被添加,因此僅在下一個版本中才可用(Boost V1.43)。但它已經在Boost SVN中了(初始文檔見here)。

相關問題