blob: 98fabaa3d39d02939307609640c558df668310a8 [file] [log] [blame]
/*=============================================================================
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 occurrance 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 [&copy_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;
}