/*============================================================================= Copyright (c) 2001-2007 Hartmut Kaiser http://spirit.sourceforge.net/ Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #include #include #include #include #include #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4702) // unreachable code #endif #include #ifdef _MSC_VER # pragma warning(pop) #endif #include #include #include using namespace BOOST_SPIRIT_CLASSIC_NS; /////////////////////////////////////////////////////////////////////////////// struct calculator : public grammar { static const int integerID = 1; static const int factorID = 2; static const int termID = 3; static const int expressionID = 4; template struct definition { definition(calculator const& /*self*/) { // Start grammar definition integer = leaf_node_d[ lexeme_d[ (!ch_p('-') >> +digit_p) ] ]; factor = integer | inner_node_d[ch_p('(') >> expression >> ch_p(')')] | (root_node_d[ch_p('-')] >> factor); term = factor >> *( (root_node_d[ch_p('*')] >> factor) | (root_node_d[ch_p('/')] >> factor) ); expression = term >> *( (root_node_d[ch_p('+')] >> term) | (root_node_d[ch_p('-')] >> term) ); // End grammar definition // turn on the debugging info. BOOST_SPIRIT_DEBUG_RULE(integer); BOOST_SPIRIT_DEBUG_RULE(factor); BOOST_SPIRIT_DEBUG_RULE(term); BOOST_SPIRIT_DEBUG_RULE(expression); } rule, parser_tag > expression; rule, parser_tag > term; rule, parser_tag > factor; rule, parser_tag > integer; rule, parser_tag > const& start() const { return expression; } }; }; /////////////////////////////////////////////////////////////////////////////// /// this is a Boost.IoStreams source device usable to create a istream on /// top of a random access container (i.e. vector<>) template class container_device { public: typedef typename Container::value_type char_type; typedef boost::iostreams::sink_tag category; container_device(Container& container) : container_(container), pos_(0) {} /// Write up to n characters to the underlying data sink into the /// buffer s, returning the number of characters written std::streamsize write(const char_type* s, std::streamsize n) { std::streamsize result = 0; if (pos_ != container_.size()) { std::streamsize amt = static_cast(container_.size() - pos_); result = (std::min)(n, amt); std::copy(s, s + result, container_.begin() + pos_); pos_ += static_cast(result); } if (result < n) { container_.insert(container_.end(), s, s + n); pos_ = container_.size(); } return n; } Container& container() { return container_; } private: typedef typename Container::size_type size_type; Container& container_; size_type pos_; }; /////////////////////////////////////////////////////////////////////////////// #define EXPECTED_XML_OUTPUT "\n\ \n\ \n\ \n\ \n\ +\n\ \n\ 1\n\ \n\ \n\ 2\n\ \n\ \n\ \n" #define EXPECTED_XML_OUTPUT_WIDE BOOST_PP_CAT(L, EXPECTED_XML_OUTPUT) bool test(wchar_t const *text) { typedef std::basic_string::iterator iterator_t; std::basic_string input(text); calculator calc; tree_parse_info ast_info = ast_parse(iterator_t(input.begin()), iterator_t(input.end()), calc >> end_p, space_p); std::basic_string out; { typedef container_device > device_type; boost::iostreams::stream outsink(out); basic_tree_to_xml(outsink, ast_info.trees, input); } return out == EXPECTED_XML_OUTPUT_WIDE; } bool test(char const *text) { typedef std::string::iterator iterator_t; std::string input(text); calculator calc; tree_parse_info ast_info = ast_parse(iterator_t(input.begin()), iterator_t(input.end()), calc >> end_p, space_p); std::string out; { typedef container_device device_type; boost::iostreams::stream outsink(out); basic_tree_to_xml(outsink, ast_info.trees, input); } return out == EXPECTED_XML_OUTPUT; } int main() { BOOST_TEST(test("1+2")); if (std::has_facet >(std::locale())) { BOOST_TEST(test(L"1+2")); } return boost::report_errors(); }