2014-06-16 54 views
3

我試圖解析terminfo定義文本文件。我是Boost.Spirit的新手。我從簡單的語法開始,只分析註釋行,空行和終端定義。正如語法中的代碼註釋所示,對definition取消註釋[_val = _1]會中斷編譯。爲什麼?我可以修復它嗎?Boost.Spirit語法問題

如果我忽略了實際的terminfo文件,我希望下面的代碼來解析這種文字:

# comment line 

first definition line 
    second 
    third line 

# another comment line 

代碼:

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/qi_eol.hpp> 
#include <boost/spirit/include/qi_eoi.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/spirit/include/phoenix_object.hpp> 
#include <vector> 
#include <iostream> 
#include <string> 

namespace termcxx 
{ 

namespace parser 
{ 

namespace qi = boost::spirit::qi; 
namespace ascii = boost::spirit::ascii; 
namespace px = boost::phoenix; 

//using qi::double_; 
using ascii::space; 
//using px::ref; 
using px::construct; 

//using qi::eps; 
//using qi::lit; 
using qi::_val; 
using qi::_1; 
using ascii::char_; 
using qi::eol; 
using qi::eoi; 


struct context 
{ 
    int dummy; 

    context() = default; 
    context (context const &) = default; 
    context (std::vector<char> a) 
    { } 
    context (std::vector<char> a, std::vector<char> b) 
    { } 
}; 

} } 


BOOST_FUSION_ADAPT_STRUCT(
    termcxx::parser::context, 
    (int, dummy)) 


namespace termcxx 
{ 

namespace parser 
{ 

template <typename Iterator> 
struct parser 
    : qi::grammar<Iterator, context()> 
{ 
    qi::rule<Iterator, std::vector<char> > comment_line 
    = (*space >> '#' >> *(char_ - eol) >> (eol | eoi))[_val = _1] 
     ; 

    qi::rule<Iterator, std::vector<char> > empty_line 
    = (*space >> (eol | eoi))[_val = _1] 
     ; 

    qi::rule<Iterator, std::vector<char> > def_first_line 
    = (+(char_ - eol) >> (eol | eoi))[_val = _1] 
     ; 

    qi::rule<Iterator, std::vector<char> > def_subsequent_line 
    = (+space >> +(char_ - eol) >> (eol | eoi))[_val = _1] 
     ; 

    qi::rule<Iterator, std::vector<char> > definition 
    = (def_first_line >> *def_subsequent_line)//[_val = _1] // Uncommenting the [_val = _1] breaks compilation. Why? 
     ; 

    qi::rule<Iterator, context()> start 
    = (*(comment_line 
      | empty_line 
      | definition))[_val = construct<context>()] 
     ; 

    parser() 
     : parser::base_type(start) 
    { } 
}; 

template struct parser<std::string::iterator>; 

} // namespace parser 

} // namespace termcxx 

回答

5

你爲什麼要堅持指定[_val=_1]?這是多餘的,因爲默認屬性傳播會這樣做。其實它很痛,看下面

接下來,(def_first_line >> *def_subsequent_line)的屬性類型(顯然)與std::vector<char>不兼容。也許你可以

  • 只使用默認屬性傳播(其中有足夠的智慧來只是不斷追加
  • 使用raw[],以獲得完整匹配的輸入
  • 定義BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT(我不知道這被很好地支持)

此外,

更新

一些更多的問題:

  • 您已經拼寫了大多數規則的屬性類型(缺少()):

    qi::rule<Iterator, std::string()> comment_line; 
    qi::rule<Iterator, std::string()> empty_line; 
    qi::rule<Iterator, std::string()> def_first_line; 
    qi::rule<Iterator, std::string()> def_subsequent_line; 
    qi::rule<Iterator, std::string()> definition; 
    
  • empty_lineeoi匹配導致無限循環在輸入的端

  • 使用char_還接受空間(使用代替:)

    def_first_line  = graph >> +(char_ - eol)   >> (eol|eoi); 
    
  • 使用qi::space也吃線端!使用qi::blank代替

  • 青睞reability:與精神工作時

    empty_line   = *blank >> eol; 
        comment_line  = *blank >> '#' >> *(char_ - eol) >> (eol|eoi); 
        def_first_line  = graph >> +(char_ - eol)   >> (eol|eoi); 
        def_subsequent_line = +blank >> +(char_ - eol)  >> (eol|eoi); 
    
        definition   = (def_first_line >> *def_subsequent_line); 
    
        start    = ( 
              *(comment_line | empty_line | definition) 
             ) [ _val = px::construct<context>() ] 
              ; 
    

    這個簡單的習慣,將節省您的時間和工作的時間和你的理智。

  • 您可以簡化有點不包括

這裏有一個固定起來Live On Coliru版本輸出:

<start> 
    <try># comment line\n\nfirs</try> 
    <comment_line> 
    <try># comment line\n\nfirs</try> 
    <success>\nfirst definition li</success> 
    <attributes>[[ , c, o, m, m, e, n, t, , l, i, n, e]]</attributes> 
    </comment_line> 
    <comment_line> 
    <try>\nfirst definition li</try> 
    <fail/> 
    </comment_line> 
    <empty_line> 
    <try>\nfirst definition li</try> 
    <success>first definition lin</success> 
    <attributes>[[]]</attributes> 
    </empty_line> 
    <comment_line> 
    <try>first definition lin</try> 
    <fail/> 
    </comment_line> 
    <empty_line> 
    <try>first definition lin</try> 
    <fail/> 
    </empty_line> 
    <definition> 
    <try>first definition lin</try> 
    <def_first_line> 
     <try>first definition lin</try> 
     <success> second \n third li</success> 
     <attributes>[[f, i, r, s, t, , d, e, f, i, n, i, t, i, o, n, , l, i, n, e]]</attributes> 
    </def_first_line> 
    <def_subsequent_line> 
     <try> second \n third li</try> 
     <success> third line\n\n# anot</success> 
     <attributes>[[f, i, r, s, t, , d, e, f, i, n, i, t, i, o, n, , l, i, n, e, , , s, e, c, o, n, d, ]]</attributes> 
    </def_subsequent_line> 
    <def_subsequent_line> 
     <try> third line\n\n# anot</try> 
     <success>\n# another comment l</success> 
     <attributes>[[f, i, r, s, t, , d, e, f, i, n, i, t, i, o, n, , l, i, n, e, , , s, e, c, o, n, d, , , , t, h, i, r, d, , l, i, n, e]]</attributes> 
    </def_subsequent_line> 
    <def_subsequent_line> 
     <try>\n# another comment l</try> 
     <fail/> 
    </def_subsequent_line> 
    <success>\n# another comment l</success> 
    <attributes>[[f, i, r, s, t, , d, e, f, i, n, i, t, i, o, n, , l, i, n, e, , , s, e, c, o, n, d, , , , t, h, i, r, d, , l, i, n, e]]</attributes> 
    </definition> 
    <comment_line> 
    <try>\n# another comment l</try> 
    <fail/> 
    </comment_line> 
    <empty_line> 
    <try>\n# another comment l</try> 
    <success># another comment li</success> 
    <attributes>[[]]</attributes> 
    </empty_line> 
    <comment_line> 
    <try># another comment li</try> 
    <success></success> 
    <attributes>[[ , a, n, o, t, h, e, r, , c, o, m, m, e, n, t, , l, i, n, e, !]]</attributes> 
    </comment_line> 
    <comment_line> 
    <try></try> 
    <fail/> 
    </comment_line> 
    <empty_line> 
    <try></try> 
    <fail/> 
    </empty_line> 
    <definition> 
    <try></try> 
    <def_first_line> 
     <try></try> 
     <fail/> 
    </def_first_line> 
    <fail/> 
    </definition> 
    <success></success> 
    <attributes>[]</attributes> 
</start> 
Success 

的完整代碼以供參考:

#define BOOST_SPIRIT_DEBUG 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 

#include <vector> 
#include <iostream> 
#include <string> 

namespace qi = boost::spirit::qi; 

namespace termcxx { namespace parser { 

    namespace ascii = boost::spirit::ascii; 
    namespace px = boost::phoenix; 

    //using qi::double_; 
    using ascii::blank; 
    //using px::ref; 
    using px::construct; 

    //using qi::eps; 
    //using qi::lit; 
    using qi::_val; 
    using qi::_1; 
    using ascii::char_; 
    using ascii::graph; 
    using qi::eol; 
    using qi::eoi; 

    struct context 
    { 
     int dummy; 

     context() = default; 
     context (context const &) = default; 
     context (std::vector<char> a) { } 
     context (std::vector<char> a, std::vector<char> b) { } 
    }; 

} } 

BOOST_FUSION_ADAPT_STRUCT(termcxx::parser::context, (int, dummy)) 

namespace termcxx { namespace parser { 

    template <typename Iterator> 
    struct parser : qi::grammar<Iterator, context()> 
    { 
     parser() : parser::base_type(start) 
     { 
      empty_line   = *blank >> eol; 
      comment_line  = *blank >> '#' >> *(char_ - eol) >> (eol|eoi); 
      def_first_line  = graph >> +(char_ - eol)   >> (eol|eoi); 
      def_subsequent_line = +blank >> +(char_ - eol)  >> (eol|eoi); 

      definition   = (def_first_line >> *def_subsequent_line); 

      start    = ( 
            *(comment_line | empty_line | definition) 
           ) [ _val = px::construct<context>() ] 
            ; 

      BOOST_SPIRIT_DEBUG_NODES((start)(def_first_line)(def_subsequent_line)(definition)(empty_line)(comment_line)) 
     } 

     private: 
     qi::rule<Iterator, context()> start; 
     qi::rule<Iterator, std::string()> comment_line; 
     qi::rule<Iterator, std::string()> empty_line; 
     qi::rule<Iterator, std::string()> def_first_line; 
     qi::rule<Iterator, std::string()> def_subsequent_line; 
     qi::rule<Iterator, std::string()> definition; 
    }; 

} } 

int main() 
{ 
    using It = boost::spirit::istream_iterator; 
    termcxx::parser::parser<It> g; 

    It f(std::cin >> std::noskipws), l; 
    termcxx::parser::context data; 
    if (qi::parse(f,l,g,data)) 
     std::cout << "Success\n"; 
    else 
     std::cout << "Failure\n"; 

    if (f != l) 
     std::cout << "Remaining input: '" << std::string(f,l) << "'\n"; 
} 
+0

我發現了更多的問題,並且讓它「工作」(顯然還沒有完成)。看到我的新筆記unde ** Update **和[live demo](http://coliru.stacked-crooked.com/a/f7e191180d6137bb) – sehe

2

讓我們看看到底發生了什麼,在這條線:

qi::rule<Iterator, std::vector<char> > definition 
    = (def_first_line >> *def_subsequent_line)[_val = _1]; 
     ; 
  1. def_first_line是RU樂。它的屬性是 std::vector<char>
  2. def_subsequent_line是另一個規則。再次 其屬性是std::vector<char>
  3. * def_subsequent_line是通過將kleene運算符*應用於def_subsequent_line而獲得的解析器。它的隱含屬性是vector< std::vector<char> >
  4. (def_first_line >> *def_subsequent_line)。這是另一個解析器。由於精神複合屬性規則,其隱含屬性又是vector< std::vector<char> >

所以基本上,該行應爲:

qi::rule<Iterator, std::vector<std::vector<char> > > definition 
    = (def_first_line >> *def_subsequent_line)[_val = _1]; 
     ; 

這是有道理的,不是嗎?你想要分開的每一行,而不是所有的字符在同一個向量中。

現在,旁註:

  • [_val = _1]是不是真的有必要。您應該使用運算符%=在語法的構造函數中初始化您的規則,該運算符負責隱式屬性。
  • 假設您不需要訪問評論,您應該編寫一個skipper規則,該規則可以自動處理間距和註釋,然後使用phrase_parse的規則。
  • 您可以使用std::string代替vector<char>,靈魂足夠聰明地理解字符序列是一個字符串。
  • 查看複合屬性規則的here
+0

哇。很多時機(我不太確定你的水晶球今天是否已經很好的校準) – sehe