178 lines
5.6 KiB
C++
178 lines
5.6 KiB
C++
/*=============================================================================
|
|
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;
|
|
}
|
|
|