2013-12-12 70 views
3

我贏得解析「text {<>}」之類的結構。例如,Spirit文檔內容類似AST。 對於解析字符串,這樣解析boost :: spirit遞歸結構

<tag1>text1<tag2>text2</tag1></tag2> 

此代碼的工作:

templ  = (tree | text)  [_val = _1]; 

    start_tag = '<' 
      >> !lit('/') 
      >> lexeme[+(char_- '>') [_val += _1]] 
      >>'>'; 

    end_tag = "</" 
      >> string(_r1) 
      >> '>'; 

    tree = start_tag   [at_c<1>(_val) = _1] 
      >> *templ   [push_back(at_c<0>(_val), _1) ] 
      >> end_tag(at_c<1>(_val)) 
      ; 

爲了解析字符串這樣

<tag<tag>some_text> 

此代碼不能工作:

templ  = (tree | text)  [_val = _1]; 


    tree = '<' 
      >> *templ   [push_back(at_c<0>(_val), _1) ] 
      >> '>' 
      ; 

TEMPL是平價用recursive_wrapper裏面唱結構:

namespace client { 

    struct tmp; 

    typedef boost::variant < 
     boost::recursive_wrapper<tmp>, 
     std::string 
    > tmp_node; 

    struct tmp { 
    std::vector<tmp_node> content; 
    std::string text; 
    }; 
} 

BOOST_FUSION_ADAPT_STRUCT(
    tmp_view::tmp, 
    (std::vector<tmp_view::tmp_node>, content) 
    (std::string,text) 
) 

誰能解釋它爲什麼會發生?也許誰知道類似的解析器寫在boost :: spirit上?

+0

問題是什麼?我看到兩個無效的XML片段和兩個相對不相關的語法,這兩個語法顯然都不應該解析無效的XML。我用Spirit編寫了很多解析器。也許他們是相似的。但是你忘了提及「發生了什麼」(所以我們不能說「爲什麼會發生」),而且你也忘了說你想要達到的目標。所以_who知道_有類似的解析器... – sehe

+0

我會忘記一個文本規則。在第二種情況下(工作)它必須是「text = lexeme [+(char_ - '<' - '>')[_val + = _1]];」 – crastinus

回答

2

只是猜測,你實際上並沒有想在所有的解析XML,而是某種分層文本混合內容的標記語言,我會做

 simple = +~qi::char_("><"); 
     nested = '<' >> *soup >> '>'; 
     soup = nested|simple; 

隨着定義爲AST /規則

typedef boost::make_recursive_variant< 
     boost::variant<std::string, std::vector<boost::recursive_variant_> > 
    >::type tag_soup; 

qi::rule<It, std::string()>   simple; 
qi::rule<It, std::vector<tag_soup>()> nested; 
qi::rule<It, tag_soup()>    soup; 

看到它Live On Coliru

//// #define BOOST_SPIRIT_DEBUG 
#include <boost/spirit/include/qi.hpp> 
#include <boost/variant/recursive_variant.hpp> 

#include <iostream> 
#include <fstream> 

namespace client 
{ 
    typedef boost::make_recursive_variant< 
      boost::variant<std::string, std::vector<boost::recursive_variant_> > 
     >::type tag_soup; 

    namespace qi = boost::spirit::qi; 

    template <typename It> 
    struct parser : qi::grammar<It, tag_soup()> 
    { 
     parser() : parser::base_type(soup) 
     { 
      simple = +~qi::char_("><"); 
      nested = '<' >> *soup >> '>'; 
      soup = nested|simple; 

      BOOST_SPIRIT_DEBUG_NODES((simple)(nested)(soup)) 
     } 
     private: 
     qi::rule<It, std::string()>   simple; 
     qi::rule<It, std::vector<tag_soup>()> nested; 
     qi::rule<It, tag_soup()>    soup; 
    }; 
} 

namespace boost { // leverage ADL on variant<> 
    static std::ostream& operator<<(std::ostream& os, std::vector<client::tag_soup> const& soup) 
    { 
     os << "<"; 
     std::copy(soup.begin(), soup.end(), std::ostream_iterator<client::tag_soup>(os)); 
     return os << ">"; 
    } 
} 

int main(int argc, char **argv) 
{ 
    if (argc < 2) { 
     std::cerr << "Error: No input file provided.\n"; 
     return 1; 
    } 

    std::ifstream in(argv[1]); 
    std::string const storage(std::istreambuf_iterator<char>(in), {}); // We will read the contents here. 

    if (!(in || in.eof())) { 
     std::cerr << "Error: Could not read from input file\n"; 
     return 1; 
    } 

    static const client::parser<std::string::const_iterator> p; 

    client::tag_soup ast; // Our tree 
    bool ok = parse(storage.begin(), storage.end(), p, ast); 

    if (ok) std::cout << "Parsing succeeded\nData: " << ast << "\n"; 
    else std::cout << "Parsing failed\n"; 

    return ok? 0 : 1; 
} 

如果您定義了BOOST_SPIRIT_DEBUG,您將得到解析過程的詳細輸出。

對於輸入

<some text with nested <tags <etc...> >more text> 

打印

Parsing succeeded 
Data: <some text with nested <tags <etc...> >more text> 

注意,輸出從所述變體,而不是原始文本打印。

+0

我會試着用DEBUG,謝謝。 – crastinus

+0

我放棄瞭解析器。如何使用多個標籤類型('<','>')。例如「 text2 <>}>」。如何使用close標籤('>','}')解析器知道什麼標籤打開表達式(在使用引用的mini_xml示例中)。 – crastinus

+0

@crastinus你仍然需要告訴我們你想達到的目標。即使沒有使用Spirit,我也可以「解析」那些標籤。 ('cat input.txt>/dev/null',也就是說,如果沒有需要/需要的行爲)。 – sehe