123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- /*=============================================================================
- Copyright (c) 2002-2003 Martin Wille
- 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)
- =============================================================================*/
- ///////////////////////////////////////////////////////////////////////////////
- // vim:ts=4:sw=4:et
- //
- // Demonstrate regular expression parsers for match based text conversion
- //
- // This sample requires an installed version of the boost regex library
- // (http://www.boost.org) The sample was tested with boost V1.29.0
- //
- // Note: - there is no error handling in this example
- // - this program isn't particularly useful
- //
- // This example shows one way build a kind of filter program.
- // It reads input from std::cin and uses a grammar and actions
- // to print out a modified version of the input.
- //
- // [ Martin Wille, 10/18/2002 ]
- //
- ///////////////////////////////////////////////////////////////////////////////
- #include <string>
- #include <iostream>
- #include <streambuf>
- #include <sstream>
- #include <deque>
- #include <iterator>
- #include <boost/function.hpp>
- #include <boost/spirit/include/classic_core.hpp>
- ///////////////////////////////////////////////////////////////////////////////
- //
- // The following header must be included, if regular expression support is
- // required for Spirit.
- //
- // The BOOST_SPIRIT_NO_REGEX_LIB PP constant should be defined, if you're using the
- // Boost.Regex library from one translation unit only. Otherwise you have to
- // link with the Boost.Regex library as defined in the related documentation
- // (see. http://www.boost.org).
- //
- ///////////////////////////////////////////////////////////////////////////////
- #define BOOST_SPIRIT_NO_REGEX_LIB
- #include <boost/spirit/include/classic_regex.hpp>
- using namespace BOOST_SPIRIT_CLASSIC_NS;
- using namespace std;
- namespace {
- long triple(long val)
- {
- return 3*val;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // actions
- //
- struct emit_constant
- {
- emit_constant(string const &text)
- : msg(text)
- {}
- template<typename Iterator>
- void operator()(Iterator b, Iterator e) const
- {
- cout.rdbuf()->sputn(msg.data(), msg.size());
- }
- private:
- string msg;
- };
- void
- copy_unmodified(char letter)
- {
- cout.rdbuf()->sputc(letter);
- }
- struct emit_modified_subscript
- {
- emit_modified_subscript(boost::function<long (long)> const &f)
- : modifier(f)
- {}
- template<typename Iterator>
- void operator()(Iterator b, Iterator e) const
- {
- string tmp(b+1,e-1);
- long val = strtol(tmp.c_str(),0, 0);
- ostringstream os;
- os << modifier(val);
- tmp = os.str();
- cout.rdbuf()->sputc('[');
- cout.rdbuf()->sputn(tmp.c_str(), tmp.size());
- cout.rdbuf()->sputc(']');
- }
- private:
- boost::function<long (long)> modifier;
- };
- }
- ///////////////////////////////////////////////////////////////////////////////
- // The grammar 'conversion_grammar' serves as a working horse for match based
- // text conversion. It does the following:
- //
- // - converts the word "class" into the word "struct"
- // - multiplies any integer number enclosed in square brackets with 3
- // - any other input is simply copied to the output
- struct conversion_grammar
- : grammar<conversion_grammar>
- {
- template<class ScannerT>
- struct definition
- {
- typedef ScannerT scanner_t;
- definition(conversion_grammar const &)
- {
- static const char expr[] = "\\[\\d+\\]";
- first = (
- /////////////////////////////////////////////////////////////
- // note that "fallback" is the last alternative here !
- top = *(class2struct || subscript || fallback),
- /////////////////////////////////////////////////////////////
- // replace any occurrence of "class" by "struct"
- class2struct = str_p("class") [emit_constant("struct")],
- /////////////////////////////////////////////////////////////
- // if the input maches "[some_number]"
- // "some_number" is multiplied by 3 before printing
- subscript = regex_p(expr) [emit_modified_subscript(&triple)],
- /////////////////////////////////////////////////////////////
- // if nothing else can be done with the input
- // then it will be printed without modifications
- fallback = anychar_p [©_unmodified]
- );
- }
- rule<scanner_t> const & start() { return first; }
- private:
- subrule<0> top;
- subrule<1> class2struct;
- subrule<2> subscript;
- subrule<3> fallback;
- rule<scanner_t> first;
- };
- };
- int
- main()
- {
- // this would print "struct foo {}; foo bar[9];":
- // parse("class foo {}; foo bar[3];", conversion_grammar());
- // Note: the regular expression parser contained in the
- // grammar requires a bidirectional iterator. Therefore,
- // we cannot use sdt::istreambuf_iterator as one would
- // do with other Spirit parsers.
- istreambuf_iterator<char> input_iterator(cin);
- std::deque<char> input(input_iterator, istreambuf_iterator<char>());
- parse(input.begin(), input.end(), conversion_grammar());
- return 0;
- }
|