tree_to_xml.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*=============================================================================
  2. Copyright (c) 2001-2007 Hartmut Kaiser
  3. http://spirit.sourceforge.net/
  4. Use, modification and distribution is subject to the Boost Software
  5. License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #include <boost/detail/lightweight_test.hpp>
  9. #include <boost/preprocessor/cat.hpp>
  10. #include <boost/spirit/include/classic_core.hpp>
  11. #include <boost/spirit/include/classic_ast.hpp>
  12. #include <boost/spirit/include/classic_tree_to_xml.hpp>
  13. #ifdef _MSC_VER
  14. # pragma warning(push)
  15. # pragma warning(disable: 4702) // unreachable code
  16. #endif
  17. #include <boost/iostreams/stream.hpp>
  18. #ifdef _MSC_VER
  19. # pragma warning(pop)
  20. #endif
  21. #include <iostream>
  22. #include <fstream>
  23. #include <string>
  24. using namespace BOOST_SPIRIT_CLASSIC_NS;
  25. ///////////////////////////////////////////////////////////////////////////////
  26. struct calculator : public grammar<calculator>
  27. {
  28. static const int integerID = 1;
  29. static const int factorID = 2;
  30. static const int termID = 3;
  31. static const int expressionID = 4;
  32. template <typename ScannerT>
  33. struct definition
  34. {
  35. definition(calculator const& /*self*/)
  36. {
  37. // Start grammar definition
  38. integer = leaf_node_d[ lexeme_d[
  39. (!ch_p('-') >> +digit_p)
  40. ] ];
  41. factor = integer
  42. | inner_node_d[ch_p('(') >> expression >> ch_p(')')]
  43. | (root_node_d[ch_p('-')] >> factor);
  44. term = factor >>
  45. *( (root_node_d[ch_p('*')] >> factor)
  46. | (root_node_d[ch_p('/')] >> factor)
  47. );
  48. expression = term >>
  49. *( (root_node_d[ch_p('+')] >> term)
  50. | (root_node_d[ch_p('-')] >> term)
  51. );
  52. // End grammar definition
  53. // turn on the debugging info.
  54. BOOST_SPIRIT_DEBUG_RULE(integer);
  55. BOOST_SPIRIT_DEBUG_RULE(factor);
  56. BOOST_SPIRIT_DEBUG_RULE(term);
  57. BOOST_SPIRIT_DEBUG_RULE(expression);
  58. }
  59. rule<ScannerT, parser_context<>, parser_tag<expressionID> > expression;
  60. rule<ScannerT, parser_context<>, parser_tag<termID> > term;
  61. rule<ScannerT, parser_context<>, parser_tag<factorID> > factor;
  62. rule<ScannerT, parser_context<>, parser_tag<integerID> > integer;
  63. rule<ScannerT, parser_context<>, parser_tag<expressionID> > const&
  64. start() const { return expression; }
  65. };
  66. };
  67. ///////////////////////////////////////////////////////////////////////////////
  68. /// this is a Boost.IoStreams source device usable to create a istream on
  69. /// top of a random access container (i.e. vector<>)
  70. template<typename Container>
  71. class container_device
  72. {
  73. public:
  74. typedef typename Container::value_type char_type;
  75. typedef boost::iostreams::sink_tag category;
  76. container_device(Container& container)
  77. : container_(container), pos_(0)
  78. {}
  79. /// Write up to n characters to the underlying data sink into the
  80. /// buffer s, returning the number of characters written
  81. std::streamsize write(const char_type* s, std::streamsize n)
  82. {
  83. std::streamsize result = 0;
  84. if (pos_ != container_.size()) {
  85. std::streamsize amt =
  86. static_cast<std::streamsize>(container_.size() - pos_);
  87. result = (std::min)(n, amt);
  88. std::copy(s, s + result, container_.begin() + pos_);
  89. pos_ += static_cast<size_type>(result);
  90. }
  91. if (result < n) {
  92. container_.insert(container_.end(), s, s + n);
  93. pos_ = container_.size();
  94. }
  95. return n;
  96. }
  97. Container& container() { return container_; }
  98. private:
  99. typedef typename Container::size_type size_type;
  100. Container& container_;
  101. size_type pos_;
  102. };
  103. ///////////////////////////////////////////////////////////////////////////////
  104. #define EXPECTED_XML_OUTPUT "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n\
  105. <!DOCTYPE parsetree SYSTEM \"parsetree.dtd\">\n\
  106. <!-- 1+2 -->\n\
  107. <parsetree version=\"1.0\">\n\
  108. <parsenode>\n\
  109. <value>+</value>\n\
  110. <parsenode>\n\
  111. <value>1</value>\n\
  112. </parsenode>\n\
  113. <parsenode>\n\
  114. <value>2</value>\n\
  115. </parsenode>\n\
  116. </parsenode>\n\
  117. </parsetree>\n"
  118. #define EXPECTED_XML_OUTPUT_WIDE BOOST_PP_CAT(L, EXPECTED_XML_OUTPUT)
  119. bool test(wchar_t const *text)
  120. {
  121. typedef std::basic_string<wchar_t>::iterator iterator_t;
  122. std::basic_string<wchar_t> input(text);
  123. calculator calc;
  124. tree_parse_info<iterator_t> ast_info =
  125. ast_parse(iterator_t(input.begin()), iterator_t(input.end()),
  126. calc >> end_p, space_p);
  127. std::basic_string<wchar_t> out;
  128. {
  129. typedef container_device<std::basic_string<wchar_t> > device_type;
  130. boost::iostreams::stream<device_type> outsink(out);
  131. basic_tree_to_xml<wchar_t>(outsink, ast_info.trees, input);
  132. }
  133. return out == EXPECTED_XML_OUTPUT_WIDE;
  134. }
  135. bool test(char const *text)
  136. {
  137. typedef std::string::iterator iterator_t;
  138. std::string input(text);
  139. calculator calc;
  140. tree_parse_info<iterator_t> ast_info =
  141. ast_parse(iterator_t(input.begin()), iterator_t(input.end()),
  142. calc >> end_p, space_p);
  143. std::string out;
  144. {
  145. typedef container_device<std::string> device_type;
  146. boost::iostreams::stream<device_type> outsink(out);
  147. basic_tree_to_xml<char>(outsink, ast_info.trees, input);
  148. }
  149. return out == EXPECTED_XML_OUTPUT;
  150. }
  151. int main()
  152. {
  153. BOOST_TEST(test("1+2"));
  154. if (std::has_facet<std::ctype<wchar_t> >(std::locale()))
  155. {
  156. BOOST_TEST(test(L"1+2"));
  157. }
  158. return boost::report_errors();
  159. }