2013-12-12 6 views
3

"text {<>}"과 같은 구조를 구문 분석 할 수있었습니다. 성령의 문서 내용은 비슷합니다. AST보기. 이boost :: spirit의 재귀 구조 구문 분석

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

같은 코드가 작동 문자열을 구문 분석이

<tag<tag>some_text> 

같은 문자열을 구문 분석을 위해

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)) 
      ; 

를이 코드는 작동하지 :

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을 구문 분석해서는 안된다는 사실을 알았습니다. 나는 성령으로 많은 파서를 썼다. 아마 그들은 비슷했다. 그러나 "무슨 일이 일어 났는지"는 언급하는 것을 잊었습니다 (그래서 우리는 "왜 그런 일이 일어 났는지"를 말할 수 없습니다). 그리고 당신은 또한 당신이 달성하고자하는 것을 말하는 것을 잊었습니다. 그래서 아는 사람들은 비슷한 파서가 있습니다 ... – sehe

+0

나는 텍스트 규칙을 잊어 버릴 것입니다. 두 번째 경우 (작동 중)에는 "text = lexeme [+ (char_ - '<' - '>') [_val + = _1]];" – crastinus

답변

2

그냥 당신이 실제로 전혀 XML을 구문 분석하고 싶지 않았다, 오히려 계층 적 텍스트 혼합 콘텐츠를 마크 업 언어의 일종, 나는으로 정의 된 AST/규칙에

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

을 할 거라고 추측

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

나는 파서를 debuged. 두 개 이상의 태그 유형 ('<','>')을 사용한 방법입니다. (예 : " text2 <>}>" 어떻게 닫힌 태그 ('>', '}')가있는 곳에서 파서는 어떤 태그 열기 표현식 (참조를 사용하여 mini_xml 예제에서)을 알고 있습니다. – crastinus

+0

@crastinus 당신은 여전히 ​​당신이 달성하고자하는 것을 알려줄 필요가 있습니다. 스피릿을 사용하지 않고도 태그를 "파싱"할 수 있습니다. ('cat input.txt>/dev/null' 즉 원하는 행동이나 요구되는 행동이 없다면). – sehe