summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/wave/samples/hannibal/hannibal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/wave/samples/hannibal/hannibal.cpp')
-rw-r--r--src/boost/libs/wave/samples/hannibal/hannibal.cpp319
1 files changed, 319 insertions, 0 deletions
diff --git a/src/boost/libs/wave/samples/hannibal/hannibal.cpp b/src/boost/libs/wave/samples/hannibal/hannibal.cpp
new file mode 100644
index 000000000..fa9e1f291
--- /dev/null
+++ b/src/boost/libs/wave/samples/hannibal/hannibal.cpp
@@ -0,0 +1,319 @@
+// Hannibal: partial C++ grammar to parse C++ type information
+// Copyright (c) 2005-2006 Danny Havenith
+//
+// Boost.Wave: A Standard compliant C++ preprocessor
+// Copyright (c) 2001-2010 Hartmut Kaiser
+//
+// http://www.boost.org/
+//
+// Distributed under 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)
+
+#define HANNIBAL_DUMP_PARSE_TREE 1
+//#define HANNIBAL_TRACE_DECLARATIONS
+//#define BOOST_SPIRIT_DEBUG
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <boost/spirit/include/classic_ast.hpp>
+#include <boost/spirit/include/classic_tree_to_xml.hpp>
+#include <boost/program_options.hpp>
+
+///////////////////////////////////////////////////////////////////////////////
+// Include Wave itself
+#include <boost/wave.hpp>
+
+///////////////////////////////////////////////////////////////////////////////
+// Include the lexer stuff
+#include <boost/wave/cpplexer/cpp_lex_token.hpp> // token class
+#include <boost/wave/cpplexer/cpp_lex_iterator.hpp> // lexer class
+
+///////////////////////////////////////////////////////////////////////////////
+// Include the Hannibal grammar
+#include "translation_unit_parser.h"
+#include "translation_unit_skipper.h"
+
+using std::vector;
+using std::string;
+namespace po = boost::program_options;
+
+#if HANNIBAL_DUMP_PARSE_TREE != 0
+///////////////////////////////////////////////////////////////////////////////
+namespace {
+
+ ///////////////////////////////////////////////////////////////////////////
+ // helper routines needed to generate the parse tree XML dump
+ typedef boost::wave::cpplexer::lex_token<> token_type;
+
+ token_type::string_type get_token_id(token_type const &t)
+ {
+ using namespace boost::wave;
+ return get_token_name(token_id(t)); // boost::wave::token_id(t);
+ }
+
+ token_type::string_type get_token_value(token_type const &t)
+ {
+ return t.get_value();
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+} // unnamed namespace
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace {
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Parse the command line for input files and (system-) include paths
+ // Prints usage info if needed.
+ // returns true if program should continue, false if program must stop
+ bool parse_command_line( int argc, char *argv[], po::variables_map &vm)
+ {
+ //
+ // Setup command line structure
+ po::options_description visible("Usage: hannibal [options] file");
+ visible.add_options()
+ ("help,h", "show this help message")
+ ("include,I", po::value<vector<string> >(),
+ "specify additional include directory")
+ ("sysinclude,S", po::value<vector<string> >(),
+ "specify additional system include directory")
+ ("define,D", po::value<vector<string> >()->composing(),
+ "specify a macro to define (as macro[=[value]])")
+ ("predefine,P", po::value<vector<string> >()->composing(),
+ "specify a macro to predefine (as macro[=[value]])")
+ ("undefine,U", po::value<vector<string> >()->composing(),
+ "specify a macro to undefine")
+ ;
+
+ po::options_description hidden;
+ hidden.add_options()
+ ("input-file", "input file");
+
+ po::options_description desc;
+ desc.add( visible).add( hidden);
+
+ po::positional_options_description p;
+ p.add("input-file", 1);
+
+ //
+ // Parse
+ po::store(po::command_line_parser(argc, argv).
+ options(desc).positional(p).run(), vm);
+ po::notify(vm);
+
+ //
+ // Print usage, if necessary
+ if (!vm.count( "input-file") || vm.count( "help"))
+ {
+ std::cout << visible << std::endl;
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+} // unnamed namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// main entry point
+int main(int argc, char *argv[])
+{
+ po::variables_map vm;
+
+ if (!parse_command_line( argc, argv, vm))
+ {
+ return -1;
+ }
+
+ string inputfile = vm["input-file"].as< string>();
+
+// current file position is saved for exception handling
+boost::wave::util::file_position_type current_position;
+
+ try {
+ // Open and read in the specified input file.
+ std::ifstream instream( inputfile.c_str());
+ std::string instring;
+
+ if (!instream.is_open()) {
+ std::cerr << "Hannibal: could not open input file: " << inputfile
+ << std::endl;
+ return -2;
+ }
+ instream.unsetf(std::ios::skipws);
+ instring = std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
+ std::istreambuf_iterator<char>());
+
+ // The template boost::wave::cpplexer::lex_token<> is the token type to be
+ // used by the Wave library.
+ typedef boost::wave::cpplexer::lex_token<> token_type;
+
+ // The template boost::wave::cpplexer::lex_iterator<> is the lexer type to
+ // be used by the Wave library.
+ typedef boost::wave::cpplexer::lex_iterator<token_type> lex_iterator_type;
+
+ // This is the resulting context type to use. The first template parameter
+ // should match the iterator type to be used during construction of the
+ // corresponding context object (see below).
+ typedef boost::wave::context<
+ std::string::iterator,
+ lex_iterator_type,
+ boost::wave::iteration_context_policies::load_file_to_string
+ > context_type;
+
+ // The preprocessor iterator shouldn't be constructed directly. It is
+ // to be generated through a wave::context<> object. This wave:context<>
+ // object is to be used additionally to initialize and define different
+ // parameters of the actual preprocessing (not done here).
+ //
+ // The preprocessing of the input stream is done on the fly behind the
+ // scenes during iteration over the context_type::iterator_type stream.
+ context_type ctx (instring.begin(), instring.end(), inputfile.c_str());
+
+ // add include directories to the include path
+ if (vm.count("include")) {
+ vector<string> const &paths =
+ vm["include"].as<vector<string> >();
+ vector<string>::const_iterator end = paths.end();
+ for (vector<string>::const_iterator cit = paths.begin();
+ cit != end; ++cit)
+ {
+ ctx.add_include_path((*cit).c_str());
+ }
+ }
+
+ // add system include directories to the include path
+ if (vm.count("sysinclude")) {
+ vector<string> const &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 additional defined macros
+ if (vm.count("define")) {
+ vector<string> const &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> const &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> const &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);
+ }
+ }
+
+ // analyze the input file
+ context_type::iterator_type first = ctx.begin();
+ context_type::iterator_type last = ctx.end();
+
+ translation_unit_skipper s;
+
+#if HANNIBAL_DUMP_PARSE_TREE != 0
+ typedef boost::spirit::classic::tree_parse_info<context_type::iterator_type>
+ result_type;
+ translation_unit_grammar::rule_map_type rule_map;
+ translation_unit_grammar g(&rule_map);
+
+ // parse the input file
+ result_type pi = boost::spirit::classic::ast_parse(first, last, g, s);
+#else
+ typedef boost::spirit::classic::parse_info<context_type::iterator_type>
+ result_type;
+ translation_unit_grammar g;
+
+ // parse the input file
+ result_type pi = boost::spirit::classic::parse(first, last, g, s);
+#endif
+
+ if (pi.full) {
+ std::cout
+ << "Hannibal: parsed sucessfully: " << inputfile << std::endl;
+
+#if HANNIBAL_DUMP_PARSE_TREE != 0
+ // generate xml dump from parse tree, if requested
+ boost::spirit::classic::tree_to_xml(std::cerr, pi.trees, "", rule_map,
+ &get_token_id, &get_token_value);
+#endif
+ }
+ else {
+ std::cerr
+ << "Hannibal: parsing failed: " << inputfile << std::endl;
+ std::cerr
+ << "Hannibal: last recognized token was: "
+ << get_token_id(*pi.stop) << std::endl;
+
+ using boost::wave::util::file_position_type;
+ file_position_type const& pos(pi.stop->get_position());
+ std::cerr
+ << "Hannibal: at: " << pos.get_file() << "(" << pos.get_line()
+ << "," << pos.get_column() << ")" << std::endl;
+ return 1;
+ }
+ }
+ catch (boost::wave::cpp_exception const& e) {
+ // some preprocessing error
+ std::cerr
+ << e.file_name() << ":" << e.line_no() << ":" << e.column_no()
+ << ": " << e.description() << std::endl;
+ return 2;
+ }
+ catch (boost::wave::cpplexer::lexing_exception const& e) {
+ // some lexing error
+ std::cerr
+ << e.file_name() << ":" << e.line_no() << ":" << e.column_no()
+ << ": " << e.description() << std::endl;
+ return 2;
+ }
+ catch (std::exception const& e) {
+ // use last recognized token to retrieve the error position
+ std::cerr
+ << current_position.get_file()
+ << "(" << current_position.get_line() << "): "
+ << "exception caught: " << e.what()
+ << std::endl;
+ return 3;
+ }
+ catch (...) {
+ // use last recognized token to retrieve the error position
+ std::cerr
+ << current_position.get_file()
+ << "(" << current_position.get_line() << "): "
+ << "unexpected exception caught." << std::endl;
+ return 4;
+ }
+ return 0;
+}