1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
3
4 Sample: Print out the preprocessed tokens returned by the Wave iterator
5
6 This sample shows, how it is possible to use a custom lexer type and a
7 custom token type with the Wave library.
8
9 http://www.boost.org/
10
11 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
12 Software License, Version 1.0. (See accompanying file
13 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
14 =============================================================================*/
15
16 #include "cpp_tokens.hpp" // global configuration
17
18 ///////////////////////////////////////////////////////////////////////////////
19 // Include Wave itself
20 #include <boost/wave.hpp>
21
22 ///////////////////////////////////////////////////////////////////////////////
23 // The following files contain the custom lexer type to use
24 #include "slex_token.hpp"
25 #include "slex_iterator.hpp"
26
27 ///////////////////////////////////////////////////////////////////////////////
28 // include lexer specifics, import lexer names
29 #if !defined(BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION)
30 #include "slex/cpp_slex_lexer.hpp"
31 #endif // !defined(BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION)
32
33 #include <iostream>
34
35 ///////////////////////////////////////////////////////////////////////////////
36 // import required names
37 using namespace boost::spirit::classic;
38
39 using std::string;
40 using std::getline;
41 using std::ifstream;
42 using std::cout;
43 using std::cerr;
44 using std::endl;
45 using std::ostream;
46
47 ///////////////////////////////////////////////////////////////////////////////
48 // main program
49 int
main(int argc,char * argv[])50 main(int argc, char *argv[])
51 {
52 if (2 != argc) {
53 cout << "Usage: cpp_tokens input_file" << endl;
54 return 1;
55 }
56
57 // read the file to analyse into a std::string
58 ifstream infile(argv[1]);
59 string teststr;
60 if (infile.is_open()) {
61 infile.unsetf(std::ios::skipws);
62 #if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
63 // this is known to be very slow for large files on some systems
64 copy (std::istream_iterator<char>(infile),
65 std::istream_iterator<char>(),
66 std::inserter(teststr, teststr.end()));
67 #else
68 teststr = std::string(std::istreambuf_iterator<char>(infile.rdbuf()),
69 std::istreambuf_iterator<char>());
70 #endif
71 }
72 else {
73 teststr = argv[1];
74 }
75
76 // The following typedef does the trick. It defines the context type to use,
77 // which depends on the lexer type (provided by the second template
78 // parameter). Our lexer type 'slex_iterator<>' depends on a custom token type
79 // 'slex_token<>'. Our custom token type differs from the original one provided
80 // by the Wave library only by defining an additional operator<<(), which is
81 // used to dump the token information carried by a given token (see loop
82 // below).
83 typedef boost::wave::cpplexer::slex_token<> token_type;
84 typedef boost::wave::cpplexer::slex::slex_iterator<token_type> lexer_type;
85 typedef boost::wave::context<std::string::iterator, lexer_type>
86 context_type;
87
88 // The C++ preprocessor iterator shouldn't be constructed directly. It is to be
89 // generated through a boost::wave::context<> object. This object is
90 // additionally to be used to initialize and define different parameters of
91 // the actual preprocessing.
92 // The preprocessing of the input stream is done on the fly behind the scenes
93 // during iteration over the context_type::iterator_type stream.
94 context_type ctx (teststr.begin(), teststr.end(), argv[1]);
95
96 ctx.set_language(boost::wave::support_cpp0x);
97 ctx.set_language(boost::wave::enable_preserve_comments(ctx.get_language()));
98 ctx.set_language(boost::wave::enable_prefer_pp_numbers(ctx.get_language()));
99 ctx.set_language(boost::wave::enable_emit_contnewlines(ctx.get_language()));
100
101 context_type::iterator_type first = ctx.begin();
102 context_type::iterator_type last = ctx.end();
103 context_type::token_type current_token;
104
105 try {
106 // Traverse over the tokens generated from the input and dump the token
107 // contents.
108 while (first != last) {
109 // retrieve next token
110 current_token = *first;
111
112 // output token info
113 cout << "matched " << current_token << endl;
114 ++first;
115 }
116 }
117 catch (boost::wave::cpp_exception const& e) {
118 // some preprocessing error
119 cerr
120 << e.file_name() << "(" << e.line_no() << "): "
121 << e.description() << endl;
122 return 2;
123 }
124 catch (std::exception const& e) {
125 // use last recognized token to retrieve the error position
126 cerr
127 << current_token.get_position().get_file()
128 << "(" << current_token.get_position().get_line() << "): "
129 << "unexpected exception: " << e.what()
130 << endl;
131 return 3;
132 }
133 catch (...) {
134 // use last recognized token to retrieve the error position
135 cerr
136 << current_token.get_position().get_file()
137 << "(" << current_token.get_position().get_line() << "): "
138 << "unexpected exception." << endl;
139 return 4;
140 }
141 return 0;
142 }
143