mirror of
https://github.com/boostorg/wave.git
synced 2026-02-23 04:02:12 +00:00
Added Wave review candidate to repository.
[SVN r1909]
This commit is contained in:
27
tool/build/Jamfile
Normal file
27
tool/build/Jamfile
Normal file
@@ -0,0 +1,27 @@
|
||||
# Wave: A Standard compliant C++ preprocessor
|
||||
#
|
||||
# Boost Wave Library Build Jamfile
|
||||
#
|
||||
# Copyright (c) 2001-2004 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)
|
||||
|
||||
subproject tools/wave/build ;
|
||||
|
||||
exe wave
|
||||
: ../cpp.cpp
|
||||
<lib>../../../libs/wave/build/boost_wave
|
||||
<lib>../../../libs/program_options/build/boost_program_options
|
||||
<lib>../../../libs/filesystem/build/boost_filesystem
|
||||
:
|
||||
<sysinclude>$(BOOST_ROOT)
|
||||
<vc7.1><*><rtti>off # workaround for compiler bug
|
||||
:
|
||||
release
|
||||
<runtime-link>static
|
||||
<threading>single
|
||||
;
|
||||
|
||||
24
tool/build/Jamfile.v2
Normal file
24
tool/build/Jamfile.v2
Normal file
@@ -0,0 +1,24 @@
|
||||
# Wave: A Standard compliant C++ preprocessor
|
||||
#
|
||||
# Boost Wave Library Build Jamfile
|
||||
#
|
||||
# Copyright (c) 2001-2004 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)
|
||||
|
||||
exe wave
|
||||
: ../cpp.cpp
|
||||
../../../libs/wave/build//boost_wave
|
||||
../../../libs/program_options/build//boost_program_options
|
||||
../../../libs/filesystem/build//boost_filesystem
|
||||
:
|
||||
<vc7.1><*><rtti>off # workaround for compiler bug
|
||||
:
|
||||
release
|
||||
<runtime-link>static
|
||||
<threading>single
|
||||
;
|
||||
|
||||
654
tool/cpp.cpp
Normal file
654
tool/cpp.cpp
Normal file
@@ -0,0 +1,654 @@
|
||||
/*=============================================================================
|
||||
Wave: A Standard compliant C++ preprocessor library
|
||||
|
||||
Copyright (c) 2001-2004 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 "cpp.hpp" // global configuration
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This sample requires the program_options library written by Vladimir Prus,
|
||||
// which is already accepted into Boost, but not included with the
|
||||
// distribution yet.
|
||||
// It is available here: http://boost-sandbox.sourceforge.net/program_options.
|
||||
//
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/timer.hpp>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Include Wave itself
|
||||
#include <boost/wave.hpp>
|
||||
|
||||
// Include the lexer related stuff
|
||||
#include <boost/wave/token_ids.hpp> // token Id's
|
||||
#include <boost/wave/cpplexer/cpp_lex_token.hpp> // token type
|
||||
#include <boost/wave/cpplexer/cpp_lex_iterator.hpp> // lexer type
|
||||
|
||||
#include "trace_macro_expansion.hpp"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// include lexer specifics, import lexer names
|
||||
//
|
||||
#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0
|
||||
#include <boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp>
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// include the grammar definitions, if these shouldn't be compiled separately
|
||||
// (ATTENTION: _very_ large compilation times!)
|
||||
//
|
||||
#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION == 0
|
||||
#include <boost/wave/grammars/cpp_intlit_grammar.hpp>
|
||||
#include <boost/wave/grammars/cpp_chlit_grammar.hpp>
|
||||
#include <boost/wave/grammars/cpp_grammar.hpp>
|
||||
#include <boost/wave/grammars/cpp_expression_grammar.hpp>
|
||||
#include <boost/wave/grammars/cpp_predef_macros_grammar.hpp>
|
||||
#include <boost/wave/grammars/cpp_defined_grammar.hpp>
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// import required names
|
||||
using namespace boost::spirit;
|
||||
|
||||
using std::string;
|
||||
using std::pair;
|
||||
using std::vector;
|
||||
using std::getline;
|
||||
using std::ifstream;
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::ostream;
|
||||
using std::istreambuf_iterator;
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// print the current version
|
||||
int print_version()
|
||||
{
|
||||
typedef boost::wave::cpplexer::lex_iterator<
|
||||
boost::wave::cpplexer::lex_token<> >
|
||||
lex_iterator_t;
|
||||
typedef boost::wave::context<
|
||||
std::string::iterator, lex_iterator_t,
|
||||
boost::wave::iteration_context_policies::load_file_to_string,
|
||||
trace_macro_expansion>
|
||||
context_t;
|
||||
|
||||
string version (context_t::get_version_string());
|
||||
cout
|
||||
<< version.substr(1, version.size()-2) // strip quotes
|
||||
<< " (" << CPP_VERSION_DATE << ")" // add date
|
||||
<< endl;
|
||||
return 0; // exit app
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// print the copyright statement
|
||||
int print_copyright()
|
||||
{
|
||||
char const *copyright[] = {
|
||||
"",
|
||||
"Wave: A Standard conformant C++ preprocessor",
|
||||
"Copyright (c) 2001-2004 Hartmut Kaiser",
|
||||
"It is hosted by 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)",
|
||||
0
|
||||
};
|
||||
|
||||
for (int i = 0; 0 != copyright[i]; ++i)
|
||||
cout << copyright[i] << endl;
|
||||
|
||||
return 0; // exit app
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace cmd_line_util {
|
||||
|
||||
// Additional command line parser which interprets '@something' as an
|
||||
// option "config-file" with the value "something".
|
||||
pair<string, string> at_option_parser(string const&s)
|
||||
{
|
||||
if ('@' == s[0])
|
||||
return std::make_pair(string("config-file"), s.substr(1));
|
||||
else
|
||||
return pair<string, string>();
|
||||
}
|
||||
|
||||
// class, which keeps include file information from the command line
|
||||
class include_paths {
|
||||
public:
|
||||
include_paths() : seen_separator(false) {}
|
||||
|
||||
vector<string> paths; // stores user paths
|
||||
vector<string> syspaths; // stores system paths
|
||||
bool seen_separator; // command line contains a '-I-' option
|
||||
|
||||
// Function which validates additional tokens from command line.
|
||||
static void
|
||||
validate(boost::any &v, vector<string> const &tokens)
|
||||
{
|
||||
if (v.empty())
|
||||
v = boost::any(include_paths());
|
||||
|
||||
include_paths *p = boost::any_cast<include_paths>(&v);
|
||||
|
||||
BOOST_SPIRIT_ASSERT(p);
|
||||
// Assume only one path per '-I' occurrence.
|
||||
string t = tokens[0];
|
||||
if (t == "-") {
|
||||
// found -I- option, so switch behaviour
|
||||
p->seen_separator = true;
|
||||
}
|
||||
else if (p->seen_separator) {
|
||||
// store this path as a system path
|
||||
p->syspaths.push_back(t);
|
||||
}
|
||||
else {
|
||||
// store this path as an user path
|
||||
p->paths.push_back(t);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Workaround for a problem in the program_options library: all options
|
||||
// stored in a variables_map, which have an assigned validator function
|
||||
// need an extraction operator.
|
||||
std::istream& operator>>(std::istream& is, include_paths& p)
|
||||
{
|
||||
return is;
|
||||
}
|
||||
|
||||
// Read all options from a given config file, parse and add them to the
|
||||
// given variables_map
|
||||
void read_config_file_options(string const &filename,
|
||||
po::options_description const &desc, po::variables_map &vm,
|
||||
bool may_fail = false)
|
||||
{
|
||||
ifstream ifs(filename.c_str());
|
||||
|
||||
if (!ifs.is_open()) {
|
||||
if (!may_fail) {
|
||||
cerr << filename
|
||||
<< ": command line warning: config file not found"
|
||||
<< endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
vector<string> options;
|
||||
string line;
|
||||
|
||||
while (std::getline(ifs, line)) {
|
||||
// skip empty lines
|
||||
string::size_type pos = line.find_first_not_of(" \t");
|
||||
if (pos == string::npos)
|
||||
continue;
|
||||
|
||||
// skip comment lines
|
||||
if ('#' != line[pos])
|
||||
options.push_back(line);
|
||||
}
|
||||
|
||||
if (options.size() > 0) {
|
||||
po::options_and_arguments oa = po::parse_command_line(options, desc);
|
||||
|
||||
po::store(oa, vm, desc);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace {
|
||||
|
||||
class auto_stop_watch : public stop_watch
|
||||
{
|
||||
public:
|
||||
auto_stop_watch(bool print_time_, std::ostream &outstrm_)
|
||||
: print_time(print_time_), outstrm(outstrm_)
|
||||
{
|
||||
}
|
||||
|
||||
~auto_stop_watch()
|
||||
{
|
||||
if (print_time) {
|
||||
outstrm << "Elapsed time: "
|
||||
<< this->format_elapsed_time()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool print_time;
|
||||
std::ostream &outstrm;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
} // anonymous namespace
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// do the actual preprocessing
|
||||
int do_actual_work (po::options_and_arguments const opts,
|
||||
po::variables_map const &vm)
|
||||
{
|
||||
// current file position is saved for exception handling
|
||||
boost::wave::util::file_position_t current_position;
|
||||
|
||||
try {
|
||||
// process the given file
|
||||
string file_name(opts.arguments().front());
|
||||
ifstream instream(file_name.c_str());
|
||||
string instring;
|
||||
|
||||
if (!instream.is_open()) {
|
||||
cerr << "wave: could not open input file: " << file_name << endl;
|
||||
return -1;
|
||||
}
|
||||
instream.unsetf(std::ios::skipws);
|
||||
|
||||
#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
|
||||
// this is known to be very slow for large files on some systems
|
||||
copy (istream_iterator<char>(instream),
|
||||
istream_iterator<char>(),
|
||||
inserter(instring, instring.end()));
|
||||
#else
|
||||
instring = string(istreambuf_iterator<char>(instream.rdbuf()),
|
||||
istreambuf_iterator<char>());
|
||||
#endif
|
||||
|
||||
// This sample uses the lex_iterator and lex_token types predefined with
|
||||
// the Wave library, but it is possible to use your own types.
|
||||
typedef boost::wave::cpplexer::lex_iterator<
|
||||
boost::wave::cpplexer::lex_token<> >
|
||||
lex_iterator_t;
|
||||
typedef boost::wave::context<
|
||||
std::string::iterator, lex_iterator_t,
|
||||
boost::wave::iteration_context_policies::load_file_to_string,
|
||||
trace_macro_expansion>
|
||||
context_t;
|
||||
|
||||
// The C++ preprocessor iterators shouldn't be constructed directly. They
|
||||
// are to be generated through a boost::wave::context<> object. This
|
||||
// boost::wave::context object is additionally to be used to initialize and
|
||||
// define different parameters of the actual preprocessing.
|
||||
// The preprocessing of the input stream is done on the fly behind the
|
||||
// scenes during iteration over the context_t::iterator_t stream.
|
||||
std::ofstream traceout;
|
||||
boost::wave::trace_policies::trace_flags enable_trace =
|
||||
boost::wave::trace_policies::trace_nothing;
|
||||
|
||||
if (vm.count("traceto")) {
|
||||
// try to open the file, where to put the trace output
|
||||
string trace_file (vm["traceto"].as<string>());
|
||||
|
||||
if (trace_file != "-") {
|
||||
traceout.open(trace_file.c_str());
|
||||
if (!traceout.is_open()) {
|
||||
cerr << "wave: could not open trace file: " << trace_file
|
||||
<< endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
enable_trace = boost::wave::trace_policies::trace_macros;
|
||||
}
|
||||
if ((enable_trace & boost::wave::trace_policies::trace_macros) &&
|
||||
!traceout.is_open())
|
||||
{
|
||||
// by default trace to std::cerr
|
||||
traceout.copyfmt(cerr);
|
||||
traceout.clear(cerr.rdstate());
|
||||
static_cast<std::basic_ios<char> &>(traceout).rdbuf(cerr.rdbuf());
|
||||
}
|
||||
|
||||
context_t ctx (instring.begin(), instring.end(), file_name.c_str(),
|
||||
trace_macro_expansion(traceout, enable_trace));
|
||||
|
||||
#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
|
||||
// enable C99 mode, if appropriate (implies variadics)
|
||||
if (vm.count("c99")) {
|
||||
#if BOOST_WAVE_ENABLE_CPP0X_EXTENSIONS != 0
|
||||
if (vm.count("c++0x")) {
|
||||
cerr <<
|
||||
"wave: the C99 and C++0x modes are mutually exclusive, "
|
||||
"working in C99 mode." << endl;
|
||||
}
|
||||
#endif
|
||||
ctx.set_language(boost::wave::support_c99);
|
||||
}
|
||||
#if BOOST_WAVE_ENABLE_CPP0X_EXTENSIONS != 0
|
||||
// enable experimental C++0x mode (implies variadics)
|
||||
else if (vm.count("c++0x")) {
|
||||
ctx.set_language(boost::wave::support_cpp0x);
|
||||
}
|
||||
#endif
|
||||
else if (vm.count("variadics")) {
|
||||
// enable variadics and placemarkers, if appropriate
|
||||
ctx.set_language(boost::wave::enable_variadics(ctx.get_language()));
|
||||
}
|
||||
#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
|
||||
|
||||
// add include directories to the system include search paths
|
||||
if (vm.count("sysinclude")) {
|
||||
vector<string> syspaths = vm["sysinclude"].as<vector<string> >();
|
||||
|
||||
vector<string>::const_iterator end = syspaths.end();
|
||||
for (vector<string>::const_iterator cit = syspaths.begin();
|
||||
cit != end; ++cit)
|
||||
{
|
||||
ctx.add_sysinclude_path((*cit).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// add include directories to the include search paths
|
||||
if (vm.count("include")) {
|
||||
cmd_line_util::include_paths const &ip =
|
||||
vm["include"].as<cmd_line_util::include_paths>();
|
||||
vector<string>::const_iterator end = ip.paths.end();
|
||||
|
||||
for (vector<string>::const_iterator cit = ip.paths.begin();
|
||||
cit != end; ++cit)
|
||||
{
|
||||
ctx.add_include_path((*cit).c_str());
|
||||
}
|
||||
|
||||
// if on the command line was given -I- , this has to be propagated
|
||||
if (ip.seen_separator)
|
||||
ctx.set_sysinclude_delimiter();
|
||||
|
||||
// add system include directories to the include path
|
||||
vector<string>::const_iterator sysend = ip.syspaths.end();
|
||||
for (vector<string>::const_iterator syscit = ip.syspaths.begin();
|
||||
syscit != sysend; ++syscit)
|
||||
{
|
||||
ctx.add_sysinclude_path((*syscit).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// add additional defined macros
|
||||
if (vm.count("define")) {
|
||||
vector<string> macros = vm["define"].as<vector<string> >();
|
||||
vector<string>::const_iterator end = macros.end();
|
||||
for (vector<string>::const_iterator cit = macros.begin();
|
||||
cit != end; ++cit)
|
||||
{
|
||||
ctx.add_macro_definition(*cit);
|
||||
}
|
||||
}
|
||||
|
||||
// add additional predefined macros
|
||||
if (vm.count("predefine")) {
|
||||
vector<string> predefmacros = vm["predefine"].as<vector<string> >();
|
||||
vector<string>::const_iterator end = predefmacros.end();
|
||||
for (vector<string>::const_iterator cit = predefmacros.begin();
|
||||
cit != end; ++cit)
|
||||
{
|
||||
ctx.add_macro_definition(*cit, true);
|
||||
}
|
||||
}
|
||||
|
||||
// undefine specified macros
|
||||
if (vm.count("undefine")) {
|
||||
vector<string> undefmacros = vm["undefine"].as<vector<string> >();
|
||||
vector<string>::const_iterator end = undefmacros.end();
|
||||
for (vector<string>::const_iterator cit = undefmacros.begin();
|
||||
cit != end; ++cit)
|
||||
{
|
||||
ctx.remove_macro_definition((*cit).c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
// maximal include nesting depth
|
||||
if (vm.count("nesting")) {
|
||||
int max_depth = vm["nesting"].as<int>();
|
||||
if (max_depth < 1 || max_depth > 100000) {
|
||||
cerr << "wave: bogus maximal include nesting depth: "
|
||||
<< max_depth << endl;
|
||||
return -1;
|
||||
}
|
||||
ctx.set_max_include_nesting_depth(max_depth);
|
||||
}
|
||||
|
||||
// open the output file
|
||||
std::ofstream output;
|
||||
|
||||
if (vm.count("output")) {
|
||||
// try to open the file, where to put the preprocessed output
|
||||
string out_file (vm["output"].as<string>());
|
||||
|
||||
output.open(out_file.c_str());
|
||||
if (!output.is_open()) {
|
||||
cerr << "wave: could not open output file: " << out_file << endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// output the preprocessed result to std::cout
|
||||
output.copyfmt(cout);
|
||||
output.clear(cout.rdstate());
|
||||
static_cast<std::basic_ios<char> &>(output).rdbuf(cout.rdbuf());
|
||||
}
|
||||
|
||||
// analyze the input file
|
||||
context_t::iterator_t first = ctx.begin();
|
||||
context_t::iterator_t last = ctx.end();
|
||||
|
||||
// preprocess the required include files
|
||||
if (vm.count("forceinclude")) {
|
||||
// add the filenames to force as include files in _reverse_ order
|
||||
// the second parameter 'is_last' for the force_include function should
|
||||
// be set to true for the last (first given) file.
|
||||
vector<string> force = vm["forceinclude"].as<vector<string> >();
|
||||
vector<string>::const_reverse_iterator rend = force.rend();
|
||||
for (vector<string>::const_reverse_iterator cit = force.rbegin();
|
||||
cit != rend; /**/)
|
||||
{
|
||||
string filename(*cit);
|
||||
first.force_include(filename.c_str(), ++cit == rend);
|
||||
}
|
||||
}
|
||||
|
||||
// loop over all generated tokens outputing the generated text
|
||||
auto_stop_watch elapsed_time(vm.count("timer") > 0, cerr);
|
||||
|
||||
while (first != last) {
|
||||
// print out the string representation of this token (skip comments)
|
||||
using namespace boost::wave;
|
||||
|
||||
// store the last known good token position
|
||||
current_position = (*first).get_position();
|
||||
|
||||
token_id id = token_id(*first);
|
||||
|
||||
if (T_CPPCOMMENT == id || T_NEWLINE == id) {
|
||||
// C++ comment tokens contain the trailing newline
|
||||
output << endl;
|
||||
}
|
||||
else if (id != T_CCOMMENT) {
|
||||
// print out the current token value
|
||||
output << (*first).get_value();
|
||||
}
|
||||
++first; // advance to the next token
|
||||
}
|
||||
}
|
||||
catch (boost::wave::cpp_exception &e) {
|
||||
// some preprocessing error
|
||||
cerr
|
||||
<< e.file_name() << "(" << e.line_no() << "): "
|
||||
<< e.description() << endl;
|
||||
return 1;
|
||||
}
|
||||
catch (boost::wave::cpplexer::lexing_exception &e) {
|
||||
// some lexing error
|
||||
cerr
|
||||
<< e.file_name() << "(" << e.line_no() << "): "
|
||||
<< e.description() << endl;
|
||||
return 2;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
// use last recognized token to retrieve the error position
|
||||
cerr
|
||||
<< current_position.get_file()
|
||||
<< "(" << current_position.get_line() << "): "
|
||||
<< "exception caught: " << e.what()
|
||||
<< endl;
|
||||
return 3;
|
||||
}
|
||||
catch (...) {
|
||||
// use last recognized token to retrieve the error position
|
||||
cerr
|
||||
<< current_position.get_file()
|
||||
<< "(" << current_position.get_line() << "): "
|
||||
<< "unexpected exception caught." << endl;
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// main entry point
|
||||
int
|
||||
main (int argc, char const *argv[])
|
||||
{
|
||||
try {
|
||||
// analyze the command line options and arguments
|
||||
vector<string> cfg_files;
|
||||
|
||||
// declare the options allowed from the command line only
|
||||
po::options_description desc_cmdline ("Options allowed on the command line only");
|
||||
|
||||
desc_cmdline.add_options()
|
||||
("help,h", "", "print out program usage (this message)")
|
||||
("version,v", "", "print the version number")
|
||||
("copyright,c", "", "print out the copyright statement")
|
||||
("config-file", po::parameter("filepath", &cfg_files),
|
||||
"specify a config file (alternatively: @filepath)")
|
||||
;
|
||||
|
||||
// declare the options allowed on command line and in config files
|
||||
po::options_description desc_generic ("Options allowed additionally in a config file");
|
||||
|
||||
desc_generic.add_options()
|
||||
("output,o", "path", "specify a file to use for output instead of stdout")
|
||||
("include,I", "path", "specify an additional include directory").
|
||||
validator(&cmd_line_util::include_paths::validate)
|
||||
("sysinclude,S", po::parameter<vector<string> >("syspath"),
|
||||
"specify an additional system include directory")
|
||||
("forceinclude,F", po::parameter<vector<string> >("file"),
|
||||
"force inclusion of the given file")
|
||||
("define,D", po::parameter<vector<string> >("macro[=[value]]"),
|
||||
"specify a macro to define")
|
||||
("predefine,P", po::parameter<vector<string> >("macro[=[value]]"),
|
||||
"specify a macro to predefine")
|
||||
("undefine,U", po::parameter<vector<string> >("macro"),
|
||||
"specify a macro to undefine")
|
||||
("nesting,n", po::parameter<int>("depth"),
|
||||
"specify a new maximal include nesting depth")
|
||||
;
|
||||
|
||||
po::options_description desc_ext ("Extended options (allowed everywhere)");
|
||||
|
||||
desc_ext.add_options()
|
||||
("traceto,t", "path", "output trace info to a file [path] or to stderr [-]")
|
||||
("timer", "", "output overall elapsed computing time to stderr")
|
||||
#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
|
||||
("variadics", "", "enable certain C99 extensions in C++ mode")
|
||||
("c99", "", "enable C99 mode (implies --variadics)")
|
||||
#endif
|
||||
#if BOOST_WAVE_ENABLE_CPP0X_EXTENSIONS != 0
|
||||
("c++0x", "", "enable C++0x support (implies --variadics)")
|
||||
#endif
|
||||
;
|
||||
|
||||
// combine the options for the different usage schemes
|
||||
po::options_description desc_overall_cmdline;
|
||||
|
||||
desc_overall_cmdline.add(desc_cmdline);
|
||||
desc_overall_cmdline.add(desc_generic);
|
||||
desc_overall_cmdline.add(desc_ext);
|
||||
|
||||
po::options_description desc_overall_cfgfile;
|
||||
|
||||
desc_overall_cfgfile.add(desc_generic);
|
||||
desc_overall_cfgfile.add(desc_ext);
|
||||
|
||||
// parse command line and store results
|
||||
po::options_and_arguments opts = po::parse_command_line(argc, argv,
|
||||
desc_overall_cmdline, 0, cmd_line_util::at_option_parser);
|
||||
po::variables_map vm;
|
||||
|
||||
po::store(opts, vm, desc_overall_cmdline);
|
||||
|
||||
// Try to find a wave.cfg in the same directory as the executable was
|
||||
// started from. If this exists, treat it as a wave config file
|
||||
fs::path filename(argv[0], fs::native);
|
||||
|
||||
filename = filename.branch_path() / "wave.cfg";
|
||||
cmd_line_util::read_config_file_options(filename.string(),
|
||||
desc_overall_cfgfile, vm, true);
|
||||
|
||||
// if there is specified at least one config file, parse it and add the
|
||||
// options to the main variables_map
|
||||
if (vm.count("config-file")) {
|
||||
vector<string>::const_iterator end = cfg_files.end();
|
||||
for (vector<string>::const_iterator cit = cfg_files.begin();
|
||||
cit != end; ++cit)
|
||||
{
|
||||
// parse a single config file and store the results
|
||||
cmd_line_util::read_config_file_options(*cit,
|
||||
desc_overall_cfgfile, vm);
|
||||
}
|
||||
}
|
||||
|
||||
// ... act as required
|
||||
if (vm.count("help")) {
|
||||
po::options_description desc_help (
|
||||
"Usage: wave [options] [@config-file(s)] file");
|
||||
|
||||
desc_help.add(desc_cmdline);
|
||||
desc_help.add(desc_generic);
|
||||
desc_help.add(desc_ext);
|
||||
cout << desc_help << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (vm.count("version")) {
|
||||
return print_version();
|
||||
}
|
||||
|
||||
if (vm.count("copyright")) {
|
||||
return print_copyright();
|
||||
}
|
||||
|
||||
// if there is no input file given, then exit
|
||||
if (0 == opts.arguments().size()) {
|
||||
cerr << "wave: no input file given, "
|
||||
<< "use --help to get a hint." << endl;
|
||||
return 5;
|
||||
}
|
||||
|
||||
// preprocess the given input file
|
||||
return do_actual_work(opts, vm);
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
cout << "wave: exception caught: " << e.what() << endl;
|
||||
return 6;
|
||||
}
|
||||
catch (...) {
|
||||
cerr << "wave: unexpected exception caught." << endl;
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
44
tool/cpp.hpp
Normal file
44
tool/cpp.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*=============================================================================
|
||||
Wave: A Standard compliant C++ preprocessor library
|
||||
|
||||
Copyright (c) 2001-2004 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)
|
||||
=============================================================================*/
|
||||
|
||||
#if !defined(CPP_HPP_920D0370_741F_44AF_BF86_F6104BDACF75_INCLUDED)
|
||||
#define CPP_HPP_920D0370_741F_44AF_BF86_F6104BDACF75_INCLUDED
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This file may be used as a precompiled header (if applicable)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// include often used files from the stdlib
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// include boost config
|
||||
#include <boost/config.hpp> // global configuration information
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// build version
|
||||
#include "cpp_version.hpp"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// configure this app here (global configuration constants)
|
||||
#include "cpp_config.hpp"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// include required boost libraries
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/pool/pool_alloc.hpp>
|
||||
|
||||
#endif // !defined(CPP_HPP_920D0370_741F_44AF_BF86_F6104BDACF75_INCLUDED)
|
||||
228
tool/cpp_config.hpp
Normal file
228
tool/cpp_config.hpp
Normal file
@@ -0,0 +1,228 @@
|
||||
/*=============================================================================
|
||||
Wave: A Standard compliant C++ preprocessor library
|
||||
|
||||
Global application configuration of the Wave driver command
|
||||
|
||||
Copyright (c) 2001-2004 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)
|
||||
=============================================================================*/
|
||||
|
||||
#if !defined(CPP_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED)
|
||||
#define CPP_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Decide, whether to implement macro scopes (#scope/#endscope), variadics,
|
||||
// placemarkers and well defined token pasting in C++ mode
|
||||
//
|
||||
// To implement these features, uncomment the following
|
||||
//
|
||||
#define BOOST_WAVE_ENABLE_CPP0X_EXTENSIONS 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Define the macro scoping keywords to be used for the experimental macro
|
||||
// scoping support.
|
||||
//
|
||||
// If the following macros aren't defined, the corresponding default value is
|
||||
// used.
|
||||
//
|
||||
// Note, if you change this, you will have to change the corresponding entries
|
||||
// inside the wave/cpplexer/re2c/cpp.re file too.
|
||||
//
|
||||
//#define BOOST_WAVE_PP_REGION "region"
|
||||
//#define BOOST_WAVE_PP_REGION_UC "REGION" // uppercase of BOOST_WAVE_PP_REGION
|
||||
//#define BOOST_WAVE_PP_ENDREGION "endregion"
|
||||
//#define BOOST_WAVE_PP_IMPORT "import"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Define the maximal include nesting depth allowed. If this value isn't
|
||||
// defined it defaults to 1024
|
||||
//
|
||||
// To define a new initial include nesting depth uncomment the following and
|
||||
// supply a new integer value.
|
||||
//
|
||||
//#define BOOST_WAVE_MAX_INCLUDE_LEVEL_DEPTH 1024
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Decide, whether to support variadics and placemarkers
|
||||
//
|
||||
// To implement support variadics and placemarkers uncomment the following
|
||||
//
|
||||
#define BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Decide, whether to implement a #warning directive as
|
||||
//
|
||||
// To implement #warning directives, uncomment the following
|
||||
//
|
||||
#define BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Decide, whether to implement #pragma once
|
||||
//
|
||||
// To implement #pragma once, uncomment the following
|
||||
//
|
||||
#define BOOST_WAVE_SUPPORT_PRAGMA_ONCE 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Decide, whether to implement #include_next
|
||||
// Please note, that this is an extension to the C++ Standard.
|
||||
//
|
||||
// To implement #include_next, uncomment the following
|
||||
//
|
||||
#define BOOST_WAVE_SUPPORT_INCLUDE_NEXT 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Undefine the following, to enable some MS specific language extensions:
|
||||
// __int8, __int16, __int32, __int64, __based, __declspec, __cdecl,
|
||||
// __fastcall, __stdcall, __try, __except, __finally, __leave, __inline,
|
||||
// __asm
|
||||
#define BOOST_WAVE_SUPPORT_MS_EXTENSIONS 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allow the message body of the #error and #warning directives to be
|
||||
// preprocessed before the diagnostic is issued.
|
||||
//
|
||||
// Uncommenting the following will preprocess the message bodies of #error and
|
||||
// #warning messages before the error (warning) is issued
|
||||
//
|
||||
#define BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allow the #pragma directives to be returned to the caller (optionally after
|
||||
// preprocessing the body)
|
||||
//
|
||||
// Undefining the following will skip #pragma directives, so that the caller
|
||||
// will not see them.
|
||||
//
|
||||
#define BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allow the body of a #pragma directive to be preprocessed before the
|
||||
// directive is returned to the caller.
|
||||
//
|
||||
// Uncommenting the following will preprocess the bodies of #pragma directives
|
||||
//
|
||||
#define BOOST_WAVE_PREPROCESS_PRAGMA_BODY 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allow to define macros with the command line syntax (-DMACRO(x)=definition)
|
||||
//
|
||||
// Uncommenting the following will enable the possibility to define macros
|
||||
// based on the command line syntax
|
||||
//
|
||||
#define BOOST_WAVE_ENABLE_COMMANDLINE_MACROS 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Define the string type to be used to store the token values and the file
|
||||
// names inside a file_position template class
|
||||
//
|
||||
|
||||
// use the following, if you have a fast std::allocator<char>
|
||||
#define BOOST_WAVE_STRINGTYPE wave::util::flex_string< \
|
||||
char, std::char_traits<char>, std::allocator<char>, \
|
||||
wave::util::CowString</*char,*/ \
|
||||
wave::util::AllocatorStringStorage<char> > \
|
||||
> \
|
||||
/**/
|
||||
#include <boost/wave/util/flex_string.hpp>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Uncomment the following, if you need debug output, the
|
||||
// BOOST_SPIRIT_DEBUG_FLAGS constants below help to fine control the amount of
|
||||
// the generated debug output
|
||||
//#define BOOST_SPIRIT_DEBUG
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// debug rules, subrules and grammars only, for possible flags see
|
||||
// spirit/debug.hpp
|
||||
#if defined(BOOST_SPIRIT_DEBUG)
|
||||
|
||||
#define BOOST_SPIRIT_DEBUG_FLAGS ( \
|
||||
BOOST_SPIRIT_DEBUG_FLAGS_NODES | \
|
||||
BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES \
|
||||
) \
|
||||
/**/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// debug flags for the pp-iterator library, possible flags (defined in
|
||||
// wave_config.hpp):
|
||||
//
|
||||
// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR 0x0001
|
||||
// #define BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION 0x0002
|
||||
// #define BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR 0x0004
|
||||
// #define BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR 0x0008
|
||||
// #define BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR 0x0010
|
||||
// #define BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR 0x0020
|
||||
// #define BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR 0x0040
|
||||
|
||||
#define BOOST_SPIRIT_DEBUG_FLAGS_CPP (\
|
||||
/* insert the required flags from above */ \
|
||||
) \
|
||||
/**/
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// For all recognized preprocessor statements the output parse trees
|
||||
// formatted as xml are printed. The formatted parse trees are streamed to the
|
||||
// std::ostream defined by the BOOST_WAVE_DUMP_PARSE_TREE_OUT constant.
|
||||
//
|
||||
// Uncomment the following, if you want to see these parse trees.
|
||||
//
|
||||
//#define BOOST_WAVE_DUMP_PARSE_TREE 1
|
||||
//#define BOOST_WAVE_DUMP_PARSE_TREE_OUT std::cerr
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// For all #if and #elif directives the preprocessed expressions are printed.
|
||||
// These expressions are streamed to the std::ostream defined by the
|
||||
// BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT constant.
|
||||
//
|
||||
// Uncomment the following, if you want to see the preprocessed expressions
|
||||
//
|
||||
//#define BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS 1
|
||||
//#define BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT std::cerr
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Decide, whether to use the separate compilation model for the instantiation
|
||||
// of the C++ lexer objects.
|
||||
//
|
||||
// If this is defined, you should explicitly instantiate the C++ lexer
|
||||
// template with the correct parameters in a separate compilation unit of
|
||||
// your program (see the files instantiate_slex_lexer.cpp and
|
||||
// instantiate_re2c_lexer.cpp).
|
||||
//
|
||||
// To use the lexer inclusion model, uncomment the following
|
||||
//
|
||||
#define BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Decide, whether to use the separate compilation model for the instantiation
|
||||
// of the grammar objects.
|
||||
//
|
||||
// If this is defined, you should explicitly instantiate the grammar
|
||||
// templates with the correct parameters in a separate compilation unit of
|
||||
// your program (see the files instantiate_cpp_grammar.cpp).
|
||||
//
|
||||
// To use the grammar inclusion model, uncomment the following
|
||||
//
|
||||
#define BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION 1
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MSVC specific #pragma's
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning (disable: 4355) // 'this' used in base member initializer list
|
||||
#pragma warning (disable: 4800) // forcing value to bool 'true' or 'false'
|
||||
#pragma inline_depth(255)
|
||||
#pragma inline_recursion(on)
|
||||
#endif // defined(BOOST_MSVC)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Now include the cofiguration stuff for the Wave library itself
|
||||
#include <boost/wave/wave_config.hpp>
|
||||
|
||||
#endif // !defined(CPP_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED)
|
||||
22
tool/cpp_version.hpp
Normal file
22
tool/cpp_version.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*=============================================================================
|
||||
Wave: A Standard compliant C++ preprocessor library
|
||||
|
||||
Copyright (c) 2001-2004 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)
|
||||
=============================================================================*/
|
||||
|
||||
#if !defined(CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED)
|
||||
#define CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED
|
||||
|
||||
#include <boost/wave/wave_version.hpp>
|
||||
|
||||
#define CPP_VERSION_MAJOR BOOST_WAVE_VERSION_MAJOR
|
||||
#define CPP_VERSION_MINOR BOOST_WAVE_VERSION_MINOR
|
||||
#define CPP_VERSION_SUBMINOR BOOST_WAVE_VERSION_SUBMINOR
|
||||
#define CPP_VERSION_DATE 20040126L
|
||||
|
||||
#endif // !defined(CPP_VERSION_HPP_CE4FE67F_63F9_468D_8364_C855F89D3C5D_INCLUDED)
|
||||
471
tool/trace_macro_expansion.hpp
Normal file
471
tool/trace_macro_expansion.hpp
Normal file
@@ -0,0 +1,471 @@
|
||||
/*=============================================================================
|
||||
Wave: A Standard compliant C++ preprocessor library
|
||||
|
||||
Copyright (c) 2001-2004 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)
|
||||
=============================================================================*/
|
||||
|
||||
#if !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED)
|
||||
#define TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/timer.hpp>
|
||||
|
||||
#include <boost/wave/token_ids.hpp>
|
||||
#include <boost/wave/util/macro_helpers.hpp>
|
||||
#include <boost/wave/trace_policies.hpp>
|
||||
#include <boost/wave/language_support.hpp>
|
||||
|
||||
#ifdef BOOST_NO_STRINGSTREAM
|
||||
#include <strstream>
|
||||
#define WAVE_OSSTREAM std::ostrstream
|
||||
std::string WAVE_GETSTRING(std::ostrstream& ss)
|
||||
{
|
||||
ss << ends;
|
||||
std::string rval = ss.str();
|
||||
ss.freeze(false);
|
||||
return rval;
|
||||
}
|
||||
#else
|
||||
#include <sstream>
|
||||
#define WAVE_GETSTRING(ss) ss.str()
|
||||
#define WAVE_OSSTREAM std::ostringstream
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class stop_watch : public boost::timer {
|
||||
|
||||
typedef boost::timer base_t;
|
||||
|
||||
public:
|
||||
stop_watch() : is_suspended_since(0), suspended_overall(0) {}
|
||||
|
||||
void suspend()
|
||||
{
|
||||
if (0 == is_suspended_since) {
|
||||
// if not already suspended
|
||||
is_suspended_since = this->base_t::elapsed();
|
||||
}
|
||||
}
|
||||
void resume()
|
||||
{
|
||||
if (0 != is_suspended_since) {
|
||||
// if really suspended
|
||||
suspended_overall += this->base_t::elapsed() - is_suspended_since;
|
||||
is_suspended_since = 0;
|
||||
}
|
||||
}
|
||||
double elapsed() const
|
||||
{
|
||||
if (0 == is_suspended_since) {
|
||||
// currently running
|
||||
return this->base_t::elapsed() - suspended_overall;
|
||||
}
|
||||
|
||||
// currently suspended
|
||||
BOOST_ASSERT(is_suspended_since >= suspended_overall);
|
||||
return is_suspended_since - suspended_overall;
|
||||
}
|
||||
|
||||
std::string format_elapsed_time() const
|
||||
{
|
||||
double current = elapsed();
|
||||
char time_buffer[sizeof("1234:56:78.90 abcd.")+1];
|
||||
|
||||
using namespace std;
|
||||
if (current >= 3600) {
|
||||
// show hours
|
||||
sprintf (time_buffer, "%d:%02d:%02d.%03d hrs.",
|
||||
(int)(current) / 3600, ((int)(current) % 3600) / 60,
|
||||
((int)(current) % 3600) % 60,
|
||||
(int)(current * 1000) % 1000);
|
||||
}
|
||||
else if (current >= 60) {
|
||||
// show minutes
|
||||
sprintf (time_buffer, "%d:%02d.%03d min.",
|
||||
(int)(current) / 60, (int)(current) % 60,
|
||||
(int)(current * 1000) % 1000);
|
||||
}
|
||||
else {
|
||||
// show seconds
|
||||
sprintf(time_buffer, "%d.%03d sec.", (int)current,
|
||||
(int)(current * 1000) % 1000);
|
||||
}
|
||||
return time_buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
double is_suspended_since;
|
||||
double suspended_overall;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The trace_macro_expansion policy is used to trace the macro expansion of
|
||||
// macros whenever it is requested from inside the input stream to preprocess
|
||||
// through the '#pragma wave_option(trace: enable)' directive. The macro
|
||||
// tracing is disabled with the help of a '#pragma wave_option(trace: disable)'
|
||||
// directive.
|
||||
//
|
||||
// This policy type is used as a template parameter to the boost::wave::context<>
|
||||
// object.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class trace_macro_expansion
|
||||
: public boost::wave::trace_policies::default_tracing
|
||||
{
|
||||
public:
|
||||
trace_macro_expansion(std::ostream &outstrm_,
|
||||
boost::wave::trace_policies::trace_flags flags_)
|
||||
: outstrm(outstrm_), level(0),
|
||||
flags(flags_), logging_flags(boost::wave::trace_policies::trace_nothing)
|
||||
{
|
||||
}
|
||||
~trace_macro_expansion()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The function enable_tracing is called, whenever the status of the
|
||||
// tracing was changed.
|
||||
//
|
||||
// The parameter 'enable' is to be used as the new tracing status.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
void enable_tracing(boost::wave::trace_policies::trace_flags flags)
|
||||
{ logging_flags = flags; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The function tracing_enabled should return the current tracing status.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
boost::wave::trace_policies::trace_flags tracing_enabled()
|
||||
{ return logging_flags; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The function 'expanding_function_like_macro' is called, whenever a
|
||||
// function-like macro is to be expanded.
|
||||
//
|
||||
// The 'macrodef' parameter marks the position, where the macro to expand
|
||||
// is defined.
|
||||
// The 'formal_args' parameter holds the formal arguments used during the
|
||||
// definition of the macro.
|
||||
// The 'definition' parameter holds the macro definition for the macro to
|
||||
// trace.
|
||||
//
|
||||
// The 'macrocall' parameter marks the position, where this macro invoked.
|
||||
// The 'arguments' parameter holds the macro arguments used during the
|
||||
// invocation of the macro
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename TokenT, typename ContainerT>
|
||||
void expanding_function_like_macro(
|
||||
TokenT const ¯odef, std::vector<TokenT> const &formal_args,
|
||||
ContainerT const &definition,
|
||||
TokenT const ¯ocall, std::vector<ContainerT> const &arguments)
|
||||
{
|
||||
if (!enabled_macro_tracing()) return;
|
||||
|
||||
if (0 == get_level()) {
|
||||
// output header line
|
||||
WAVE_OSSTREAM stream;
|
||||
|
||||
stream
|
||||
<< macrocall.get_position() << ": "
|
||||
<< macrocall.get_value() << "(";
|
||||
|
||||
// argument list
|
||||
for (typename ContainerT::size_type i = 0; i < arguments.size(); ++i) {
|
||||
stream << boost::wave::util::impl::as_string(arguments[i]);
|
||||
if (i < arguments.size()-1)
|
||||
stream << ", ";
|
||||
}
|
||||
stream << ")" << std::endl;
|
||||
output(WAVE_GETSTRING(stream));
|
||||
increment_level();
|
||||
}
|
||||
|
||||
// output definition reference
|
||||
{
|
||||
WAVE_OSSTREAM stream;
|
||||
|
||||
stream
|
||||
<< macrodef.get_position() << ": see macro definition: "
|
||||
<< macrodef.get_value() << "(";
|
||||
|
||||
// formal argument list
|
||||
for (typename std::vector<TokenT>::size_type i = 0;
|
||||
i < formal_args.size(); ++i)
|
||||
{
|
||||
stream << formal_args[i].get_value();
|
||||
if (i < formal_args.size()-1)
|
||||
stream << ", ";
|
||||
}
|
||||
stream << ")" << std::endl;
|
||||
output(WAVE_GETSTRING(stream));
|
||||
}
|
||||
|
||||
if (formal_args.size() > 0) {
|
||||
// map formal and real arguments
|
||||
open_trace_body("invoked with\n");
|
||||
for (typename std::vector<TokenT>::size_type j = 0;
|
||||
j < formal_args.size(); ++j)
|
||||
{
|
||||
using namespace boost::wave;
|
||||
|
||||
WAVE_OSSTREAM stream;
|
||||
stream << formal_args[j].get_value() << " = ";
|
||||
#if WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
|
||||
if (T_ELLIPSIS == token_id(formal_args[j])) {
|
||||
// ellipsis
|
||||
for (typename ContainerT::size_type k = j;
|
||||
k < arguments.size(); ++k)
|
||||
{
|
||||
stream << boost::wave::util::impl::as_string(arguments[k]);
|
||||
if (k < arguments.size()-1)
|
||||
stream << ", ";
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
stream << boost::wave::util::impl::as_string(arguments[j]);
|
||||
}
|
||||
stream << std::endl;
|
||||
output(WAVE_GETSTRING(stream));
|
||||
}
|
||||
close_trace_body();
|
||||
}
|
||||
open_trace_body();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The function 'expanding_object_like_macro' is called, whenever a
|
||||
// object-like macro is to be expanded .
|
||||
//
|
||||
// The 'macrodef' parameter marks the position, where the macro to expand
|
||||
// is defined.
|
||||
// The 'definition' parameter holds the macro definition for the macro to
|
||||
// trace.
|
||||
//
|
||||
// The 'macrocall' parameter marks the position, where this macro invoked.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename TokenT, typename ContainerT>
|
||||
void expanding_object_like_macro(TokenT const ¯odef,
|
||||
ContainerT const &definition, TokenT const ¯ocall)
|
||||
{
|
||||
if (!enabled_macro_tracing()) return;
|
||||
|
||||
if (0 == get_level()) {
|
||||
// output header line
|
||||
WAVE_OSSTREAM stream;
|
||||
|
||||
stream
|
||||
<< macrocall.get_position() << ": "
|
||||
<< macrocall.get_value() << std::endl;
|
||||
output(WAVE_GETSTRING(stream));
|
||||
increment_level();
|
||||
}
|
||||
|
||||
// output definition reference
|
||||
{
|
||||
WAVE_OSSTREAM stream;
|
||||
|
||||
stream
|
||||
<< macrodef.get_position() << ": see macro definition: "
|
||||
<< macrodef.get_value() << std::endl;
|
||||
output(WAVE_GETSTRING(stream));
|
||||
}
|
||||
open_trace_body();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The function 'expanded_macro' is called, whenever the expansion of a
|
||||
// macro is finished but before the rescanning process starts.
|
||||
//
|
||||
// The parameter 'result' contains the token sequence generated as the
|
||||
// result of the macro expansion.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename ContainerT>
|
||||
void expanded_macro(ContainerT const &result)
|
||||
{
|
||||
if (!enabled_macro_tracing()) return;
|
||||
|
||||
WAVE_OSSTREAM stream;
|
||||
stream << boost::wave::util::impl::as_string(result) << std::endl;
|
||||
output(WAVE_GETSTRING(stream));
|
||||
|
||||
open_trace_body("rescanning\n");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The function 'rescanned_macro' is called, whenever the rescanning of a
|
||||
// macro is finished.
|
||||
//
|
||||
// The parameter 'result' contains the token sequence generated as the
|
||||
// result of the rescanning.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename ContainerT>
|
||||
void rescanned_macro(ContainerT const &result)
|
||||
{
|
||||
if (!enabled_macro_tracing() || get_level() == 0)
|
||||
return;
|
||||
|
||||
WAVE_OSSTREAM stream;
|
||||
stream << boost::wave::util::impl::as_string(result) << std::endl;
|
||||
output(WAVE_GETSTRING(stream));
|
||||
close_trace_body();
|
||||
close_trace_body();
|
||||
|
||||
if (1 == get_level())
|
||||
decrement_level();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The function 'interpret_pragma' is called, whenever a #pragma wave
|
||||
// directive is found, which isn't known to the core Wave library.
|
||||
//
|
||||
// The parameter 'pending' may be used to push tokens back into the input
|
||||
// stream, which are to be used as the replacement text for the whole
|
||||
// #pragma wave() directive.
|
||||
//
|
||||
// The parameter 'option' contains the name of the interpreted pragma.
|
||||
//
|
||||
// The parameter 'values' holds the values of the parameter provided to
|
||||
// the pragma operator.
|
||||
//
|
||||
// The parameter 'act_token' contains the actual #pragma token, which may
|
||||
// be used for error output.
|
||||
//
|
||||
// The parameter 'language' contains the current language mode, in which
|
||||
// the Wave library operates.
|
||||
//
|
||||
// If the return value is 'false', the whole #pragma directive is
|
||||
// interpreted as unknown and a corresponding error message is issued. A
|
||||
// return value of 'true' signs a successful interpretation of the given
|
||||
// #pragma.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename TokenT, typename ContainerT>
|
||||
bool
|
||||
interpret_pragma(ContainerT &pending, TokenT const &option,
|
||||
ContainerT const &values, TokenT const &act_token,
|
||||
boost::wave::language_support language)
|
||||
{
|
||||
if (option.get_value() == "timer") {
|
||||
// #pragma wave timer(value)
|
||||
if (0 == values.size()) {
|
||||
// no value means '1'
|
||||
using namespace boost::wave;
|
||||
timer(TokenT(T_INTLIT, "1", act_token.get_position()));
|
||||
}
|
||||
else {
|
||||
timer(values.front());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
void open_trace_body(char const *label = 0)
|
||||
{
|
||||
if (label)
|
||||
output(label);
|
||||
output("[\n");
|
||||
increment_level();
|
||||
}
|
||||
void close_trace_body()
|
||||
{
|
||||
if (get_level() > 0) {
|
||||
decrement_level();
|
||||
output("]\n");
|
||||
outstrm << std::flush; // flush the stream buffer
|
||||
}
|
||||
}
|
||||
|
||||
template <typename StringT>
|
||||
void output(StringT const &outstr) const
|
||||
{
|
||||
indent(get_level());
|
||||
outstrm << outstr; // output the given string
|
||||
}
|
||||
|
||||
void indent(int level) const
|
||||
{
|
||||
for (int i = 0; i < level; ++i)
|
||||
outstrm << " "; // indent
|
||||
}
|
||||
|
||||
int increment_level() { return ++level; }
|
||||
int decrement_level() { BOOST_ASSERT(level > 0); return --level; }
|
||||
int get_level() const { return level; }
|
||||
|
||||
bool enabled_macro_tracing() const
|
||||
{
|
||||
using namespace boost::wave::trace_policies;
|
||||
return (flags & trace_macros) && (logging_flags & trace_macros);
|
||||
}
|
||||
bool enabled_include_tracing() const
|
||||
{
|
||||
using namespace boost::wave::trace_policies;
|
||||
return (flags & trace_includes) && (logging_flags & trace_includes);
|
||||
}
|
||||
|
||||
template <typename TokenT>
|
||||
void timer(TokenT const &value)
|
||||
{
|
||||
if (value.get_value() == "0" || value.get_value() == "restart") {
|
||||
// restart the timer
|
||||
elapsed_time.restart();
|
||||
}
|
||||
else if (value.get_value() == "1") {
|
||||
// print out the current elapsed time
|
||||
std::cerr
|
||||
<< value.get_position() << ": "
|
||||
<< elapsed_time.format_elapsed_time()
|
||||
<< std::endl;
|
||||
}
|
||||
else if (value.get_value() == "suspend") {
|
||||
// suspend the timer
|
||||
elapsed_time.suspend();
|
||||
}
|
||||
else if (value.get_value() == "resume") {
|
||||
// resume the timer
|
||||
elapsed_time.resume();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream &outstrm; // output stream
|
||||
int level; // indentation level
|
||||
boost::wave::trace_policies::trace_flags flags; // enabled globally
|
||||
boost::wave::trace_policies::trace_flags logging_flags; // enabled by a #pragma
|
||||
|
||||
stop_watch elapsed_time; // trace timings
|
||||
};
|
||||
|
||||
#undef WAVE_GETSTRING
|
||||
#undef WAVE_OSSTREAM
|
||||
|
||||
#endif // !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED)
|
||||
Reference in New Issue
Block a user