2013-01-10 28 views
2

我寫了一個簡單的解析器,精神類似於json(但更簡單,更專業化)。通過遵循here的建議,我嘗試通過跟蹤錯誤位置來實現錯誤處理。具體來說,我的解析功能如下如何使用靈魂解析器獲取錯誤位置

bool parse_properties(std::istream& is, const std::string &filename, PropertyList &pset) 
{ 
    namespace qi = boost::spirit::qi; 
    namespace ascii = boost::spirit::ascii; 
    namespace classic = boost::spirit::classic; 

    typedef std::istreambuf_iterator<char> base_iterator_type; 
    base_iterator_type in_begin(is); 

    // convert input iterator to forward iterator, usable by spirit parser 
    typedef boost::spirit::multi_pass<base_iterator_type> forward_iterator_type; 
    forward_iterator_type fwd_begin = boost::spirit::make_default_multi_pass(in_begin); 
    forward_iterator_type fwd_end; 

    // wrap forward iterator with position iterator, to record the position 
    typedef classic::position_iterator2<forward_iterator_type> pos_iterator_type; 
    pos_iterator_type position_begin(fwd_begin, fwd_end, filename); 
    pos_iterator_type position_end; 

    qi::rule<pos_iterator_type> skipper = ascii::space | 
    '#' >> *(ascii::char_ - qi::eol) >> qi::eol; 

    property_set_grammar<pos_iterator_type, qi::rule<pos_iterator_type> > g; 
    bool r = false; 
    try { 
     r = phrase_parse(position_begin, 
         position_end, 
      g, skipper, pset); 
    } 
    catch(const qi::expectation_failure<pos_iterator_type>& e) { 
     const classic::file_position_base<std::string>& pos = e.first.get_position(); 
     std::stringstream msg; 
     msg << 
      "parse error at file " << pos.file << 
      " line " << pos.line << " column " << pos.column << std::endl << 
      "'" << e.first.get_currentline() << "'" << std::endl << 
      std::setw(pos.column) << " " << "^- here"; 
     throw std::runtime_error(msg.str()); 
    } 

    return r; 
} 

不幸的是,它不起作用。函數phrase_parse總是立即返回false,這既適用於正確的文件,也適用於不正確的文件,並且永遠不會引發任何異常。

但是,當我修改上述代碼以使用簡單的forward_iterator而不是classic::position_iterator2時,它工作正常,但它當然不會跟蹤錯誤位置。非常奇怪的是,here中的原始示例正常工作。所以也許這個問題與我的語法有關。這裏是:

template <typename Iterator, typename Skipper> 
struct property_set_grammar : qi::grammar<Iterator, PropertyList(), 
              Skipper> 
{ 
    qi::rule<Iterator, Property(), Skipper> prop; 
    qi::rule<Iterator, std::string(), Skipper> name; 
    qi::rule<Iterator, std::string(), Skipper> type; 
    qi::rule<Iterator, std::string(), Skipper> value; 
    qi::rule<Iterator, std::string(), Skipper> value_simple; 
    qi::rule<Iterator, std::string(), Skipper> value_quoted; 
    qi::rule<Iterator, PropertyList(), Skipper> plist; 

    property_set_grammar() : 
     property_set_grammar::base_type(plist, "Set of Properties") { 
     using qi::lit; 
     using qi::alpha; 
     using qi::alnum; 
     using qi::lexeme; 
     using qi::char_; 

     name = lexeme[alpha >> *alnum]; 
     type = lexeme[alpha >> *alnum]; 
     value_simple = lexeme[*(alnum - lit('"'))]; 
     value_quoted = lit('"') > lexeme[*(char_ - lit('"'))] > lit('"'); 
     value = (value_quoted | value_simple); 

     prop = name >> '=' > value > ';'; 
     plist = type >> '(' > name > ')' > '{' >> *(prop | plist) > '}' > ';'; 
    } 
}; 

我使用g ++(Ubuntu/Linaro 4.7.2-2ubuntu1)4.7.2和版本1.50的boost庫。

我忽略了什麼愚蠢的東西嗎?如果需要,我可以提供完整的代碼(只有幾個文件)。

回答

2

似乎boost :: spirit :: position_iterator被竊聽了。

您可以按照答案here中的建議編輯標題position_iterator

或者你可以實現你自己的position_iterator,我通過基本上覆制並粘貼boost::spirit::position_iterator的原始代碼,然後刪除一些不需要的東西。

此外,從istream解析時,請務必將noskipws MANIP:

//is >> std::noskipws; 

編輯:沒有必要與istreambuf_iterator

+0

非常感謝!我希望有人能儘快修復這個bug。 – knulp