2013-12-12 3 views
3

Я выиграл, чтобы разобрать структуру как «текст {<>}». Содержание документации для духа похоже на пример 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 является паритет с внутренней рекурсивной структурой:

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. Я написал много парсеров в Духе. Возможно, они были похожи. Но вы забыли упомянуть «что случилось» (поэтому мы не можем сказать «почему это случилось»), и вы также забыли сказать, чего вы пытаетесь достичь. Так что _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 tag ('>', '}') парсер знает, какое выражение для открытого тега (в примере mini_xml, используя ссылку). – crastinus

+0

@crastinus Вам все еще нужно рассказать нам, чего вы пытаетесь достичь. Я могу «разобрать» теги просто отлично, даже не используя Spirit. ('cat input.txt>/dev/null', то есть, если нет желаемого/требуемого поведения). – sehe