1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
3 http://www.boost.org/
4
5 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
6 Software License, Version 1.0. (See accompanying file
7 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9
10 #if !defined(BOOST_WAVE_LIBS_WAVE_TEST_COLLECT_HOOKS_INFORMATION_HPP)
11 #define BOOST_WAVE_LIBS_WAVE_TEST_COLLECT_HOOKS_INFORMATION_HPP
12
13 #include <boost/config.hpp>
14 #include <boost/lexical_cast.hpp>
15 #include <boost/filesystem/path.hpp>
16 #include <boost/filesystem/operations.hpp>
17
18 ///////////////////////////////////////////////////////////////////////////////
19 // workaround for missing ostringstream
20 #ifdef BOOST_NO_STRINGSTREAM
21 #include <strstream>
22 #define BOOST_WAVETEST_OSSTREAM std::ostrstream
BOOST_WAVETEST_GETSTRING(std::ostrstream & ss)23 std::string BOOST_WAVETEST_GETSTRING(std::ostrstream& ss)
24 {
25 ss << ends;
26 std::string rval = ss.str();
27 ss.freeze(false);
28 return rval;
29 }
30 #else
31 #include <sstream>
32 #define BOOST_WAVETEST_GETSTRING(ss) ss.str()
33 #define BOOST_WAVETEST_OSSTREAM std::ostringstream
34 #endif
35
36 ///////////////////////////////////////////////////////////////////////////////
37 template <typename String>
handle_filepath(String const & name)38 String handle_filepath(String const &name)
39 {
40 using boost::wave::util::impl::unescape_lit;
41
42 String unesc_name (unescape_lit(name));
43 typename String::size_type p = unesc_name.find_last_of("/\\");
44 if (p != unesc_name.npos)
45 unesc_name = unesc_name.substr(p+1);
46 return unesc_name;
47 }
48
49 ///////////////////////////////////////////////////////////////////////////////
50 template <typename String>
repr(boost::wave::util::file_position<String> const & pos)51 inline String repr(boost::wave::util::file_position<String> const& pos)
52 {
53 std::string linenum = boost::lexical_cast<std::string>(pos.get_line());
54 return handle_filepath(pos.get_file()) + String("(") + linenum.c_str() + ")";
55 }
56
57 template <typename String>
repr(String const & value)58 inline String repr(String const& value)
59 {
60 String result;
61 typename String::const_iterator end = value.end();
62 for (typename String::const_iterator it = value.begin(); it != end; ++it)
63 {
64 typedef typename String::value_type char_type;
65 char_type c = *it;
66 if (c == static_cast<char_type>('\a'))
67 result.append("\\a");
68 else if (c == static_cast<char_type>('\b'))
69 result.append("\\b");
70 else if (c == static_cast<char_type>('\f'))
71 result.append("\\f");
72 else if (c == static_cast<char_type>('\n'))
73 result.append("\\n");
74 else if (c == static_cast<char_type>('\r'))
75 result.append("\\r");
76 else if (c == static_cast<char_type>('\t'))
77 result.append("\\t");
78 else if (c == static_cast<char_type>('\v'))
79 result.append("\\v");
80 else
81 result += static_cast<char_type>(c);
82 }
83 return result;
84 }
85
86 #if defined(BOOST_WINDOWS)
87 template <typename String>
replace_slashes(String value,char const * lookfor="\\\\",char replace_with='/')88 inline String replace_slashes(String value, char const* lookfor = "\\",
89 char replace_with = '/')
90 {
91 typename String::size_type p = value.find_first_of(lookfor);
92 while (p != value.npos) {
93 value[p] = replace_with;
94 p = value.find_first_of(lookfor, p+1);
95 }
96 return value;
97 }
98 #endif
99
100 ///////////////////////////////////////////////////////////////////////////////
101 template <typename Token>
102 class collect_hooks_information
103 : public boost::wave::context_policies::eat_whitespace<Token>
104 {
105 typedef boost::wave::context_policies::eat_whitespace<Token> base_type;
106
107 public:
collect_hooks_information(std::string & trace)108 collect_hooks_information(std::string& trace)
109 : hooks_trace(trace), skipped_token_hooks(false)
110 {}
111
set_skipped_token_hooks(bool flag)112 void set_skipped_token_hooks(bool flag)
113 {
114 skipped_token_hooks = flag;
115 }
116
117 ///////////////////////////////////////////////////////////////////////////
118 //
119 // The function 'expanding_function_like_macro' is called, whenever a
120 // function-like macro is to be expanded.
121 //
122 // The parameter 'macrodef' marks the position, where the macro to expand
123 // is defined.
124 //
125 // The parameter 'formal_args' holds the formal arguments used during the
126 // definition of the macro.
127 //
128 // The parameter 'definition' holds the macro definition for the macro to
129 // trace.
130 //
131 // The parameter 'macro_call' marks the position, where this macro invoked.
132 //
133 // The parameter 'arguments' holds the macro arguments used during the
134 // invocation of the macro
135 //
136 // The parameters 'seqstart' and 'seqend' point into the input token
137 // stream allowing to access the whole token sequence comprising the macro
138 // invocation (starting with the opening parenthesis and ending after the
139 // closing one).
140 //
141 // The return value defines, whether the corresponding macro will be
142 // expanded (return false) or will be copied to the output (return true).
143 // Note: the whole argument list is copied unchanged to the output as well
144 // without any further processing.
145 //
146 ///////////////////////////////////////////////////////////////////////////
147
148 template <typename Context, typename Container, typename Iterator>
149 bool
expanding_function_like_macro(Context const & ctx,Token const & macro,std::vector<Token> const & formal_args,Container const & definition,Token const & macrocall,std::vector<Container> const & arguments,Iterator const & seqstart,Iterator const & seqend)150 expanding_function_like_macro(Context const& ctx,
151 Token const& macro, std::vector<Token> const& formal_args,
152 Container const& definition,
153 Token const& macrocall, std::vector<Container> const& arguments,
154 Iterator const& seqstart, Iterator const& seqend)
155 {
156 BOOST_WAVETEST_OSSTREAM strm;
157 // trace real macro call
158 strm << "00: " << repr(macrocall.get_position()) << ": "
159 << macrocall.get_value() << "(";
160 for (typename std::vector<Token>::size_type i = 0;
161 i < arguments.size(); ++i)
162 {
163 strm << boost::wave::util::impl::as_string(arguments[i]);
164 if (i < arguments.size()-1)
165 strm << ",";
166 }
167 strm << "), ";
168
169 // trace macro definition
170 strm << "[" << repr(macro.get_position()) << ": "
171 << macro.get_value() << "(";
172 for (typename std::vector<Token>::size_type i = 0;
173 i < formal_args.size(); ++i)
174 {
175 strm << formal_args[i].get_value();
176 if (i < formal_args.size()-1)
177 strm << ", ";
178 }
179 strm << ")=" << boost::wave::util::impl::as_string(definition) << "]"
180 << std::endl;
181
182 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
183 return false; // default is to normally expand the macro
184 }
185
186 ///////////////////////////////////////////////////////////////////////////
187 //
188 // The function 'expanding_object_like_macro' is called, whenever a
189 // object-like macro is to be expanded .
190 //
191 // The parameter 'ctx' is a reference to the context object used for
192 // instantiating the preprocessing iterators by the user.
193 //
194 // The parameter 'macro' marks the position, where the macro to expand
195 // is defined.
196 //
197 // The definition 'definition' holds the macro definition for the macro to
198 // trace.
199 //
200 // The parameter 'macrocall' marks the position, where this macro invoked.
201 //
202 // The return value defines, whether the corresponding macro will be
203 // expanded (return false) or will be copied to the output (return true).
204 //
205 ///////////////////////////////////////////////////////////////////////////
206 template <typename Context, typename Container>
207 bool
expanding_object_like_macro(Context const & ctx,Token const & macro,Container const & definition,Token const & macrocall)208 expanding_object_like_macro(Context const& ctx, Token const& macro,
209 Container const& definition, Token const& macrocall)
210 {
211 BOOST_WAVETEST_OSSTREAM strm;
212 strm << "01: " << repr(macro.get_position()) << ": "
213 << macro.get_value() << std::endl;
214 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
215 return false; // default is to normally expand the macro
216 }
217
218 ///////////////////////////////////////////////////////////////////////////
219 //
220 // The function 'expanded_macro' is called, whenever the expansion of a
221 // macro is finished but before the rescanning process starts.
222 //
223 // The parameter 'ctx' is a reference to the context object used for
224 // instantiating the preprocessing iterators by the user.
225 //
226 // The parameter 'result' contains the token sequence generated as the
227 // result of the macro expansion.
228 //
229 ///////////////////////////////////////////////////////////////////////////
230 template <typename Context, typename Container>
expanded_macro(Context const & ctx,Container const & result)231 void expanded_macro(Context const& ctx, Container const& result)
232 {
233 BOOST_WAVETEST_OSSTREAM strm;
234 strm << "02: " << boost::wave::util::impl::as_string(result) << std::endl;
235 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
236 }
237
238 ///////////////////////////////////////////////////////////////////////////
239 //
240 // The function 'rescanned_macro' is called, whenever the rescanning of a
241 // macro is finished.
242 //
243 // The parameter 'ctx' is a reference to the context object used for
244 // instantiating the preprocessing iterators by the user.
245 //
246 // The parameter 'result' contains the token sequence generated as the
247 // result of the rescanning.
248 //
249 ///////////////////////////////////////////////////////////////////////////
250 template <typename Context, typename Container>
rescanned_macro(Context const & ctx,Container const & result)251 void rescanned_macro(Context const& ctx, Container const& result)
252 {
253 BOOST_WAVETEST_OSSTREAM strm;
254 strm << "03: " << boost::wave::util::impl::as_string(result) << std::endl;
255 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
256 }
257
258 ///////////////////////////////////////////////////////////////////////////
259 //
260 // The function 'found_include_directive' is called, whenever a #include
261 // directive was located.
262 //
263 // The parameter 'ctx' is a reference to the context object used for
264 // instantiating the preprocessing iterators by the user.
265 //
266 // The parameter 'filename' contains the (expanded) file name found after
267 // the #include directive. This has the format '<file>', '"file"' or
268 // 'file'.
269 // The formats '<file>' or '"file"' are used for #include directives found
270 // in the preprocessed token stream, the format 'file' is used for files
271 // specified through the --force_include command line argument.
272 //
273 // The parameter 'include_next' is set to true if the found directive was
274 // a #include_next directive and the BOOST_WAVE_SUPPORT_INCLUDE_NEXT
275 // preprocessing constant was defined to something != 0.
276 //
277 // The return value defines, whether the found file will be included
278 // (return false) or will be skipped (return true).
279 //
280 ///////////////////////////////////////////////////////////////////////////
281 template <typename Context>
282 bool
found_include_directive(Context const & ctx,std::string filename,bool include_next)283 found_include_directive(Context const& ctx, std::string filename,
284 bool include_next)
285 {
286 BOOST_WAVETEST_OSSTREAM strm;
287 strm << "04: " << filename;
288 if (include_next)
289 strm << " (include_next)";
290 strm << std::endl;
291 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
292 return false; // ok to include this file
293 }
294
295 ///////////////////////////////////////////////////////////////////////////
296 //
297 // The function 'opened_include_file' is called, whenever a file referred
298 // by an #include directive was successfully located and opened.
299 //
300 // The parameter 'ctx' is a reference to the context object used for
301 // instantiating the preprocessing iterators by the user.
302 //
303 // The parameter 'filename' contains the file system path of the
304 // opened file (this is relative to the directory of the currently
305 // processed file or a absolute path depending on the paths given as the
306 // include search paths).
307 //
308 // The include_depth parameter contains the current include file depth.
309 //
310 // The is_system_include parameter denotes, whether the given file was
311 // found as a result of a #include <...> directive.
312 //
313 ///////////////////////////////////////////////////////////////////////////
314 template <typename Context>
315 void
opened_include_file(Context const & ctx,std::string relname,std::string absname,bool is_system_include)316 opened_include_file(Context const& ctx, std::string relname,
317 std::string absname, bool is_system_include)
318 {
319 using boost::wave::util::impl::escape_lit;
320
321 #if defined(BOOST_WINDOWS)
322 relname = replace_slashes(relname);
323 absname = replace_slashes(absname);
324 #endif
325
326 BOOST_WAVETEST_OSSTREAM strm;
327 strm << "05: " << escape_lit(relname)
328 << " (" << escape_lit(absname) << ")" << std::endl;
329 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
330 }
331
332 ///////////////////////////////////////////////////////////////////////////
333 //
334 // The function 'returning_from_include_file' is called, whenever an
335 // included file is about to be closed after it's processing is complete.
336 //
337 // The parameter 'ctx' is a reference to the context object used for
338 // instantiating the preprocessing iterators by the user.
339 //
340 ///////////////////////////////////////////////////////////////////////////
341 template <typename Context>
342 void
returning_from_include_file(Context const & ctx)343 returning_from_include_file(Context const& ctx)
344 {
345 BOOST_WAVETEST_OSSTREAM strm;
346 strm << "06: " << std::endl;
347 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
348 }
349
350 ///////////////////////////////////////////////////////////////////////////
351 //
352 // The function 'interpret_pragma' is called, whenever a #pragma command
353 // directive is found which isn't known to the core Wave library, where
354 // command is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant
355 // which defaults to "wave".
356 //
357 // The parameter 'ctx' is a reference to the context object used for
358 // instantiating the preprocessing iterators by the user.
359 //
360 // The parameter 'pending' may be used to push tokens back into the input
361 // stream, which are to be used as the replacement text for the whole
362 // #pragma directive.
363 //
364 // The parameter 'option' contains the name of the interpreted pragma.
365 //
366 // The parameter 'values' holds the values of the parameter provided to
367 // the pragma operator.
368 //
369 // The parameter 'act_token' contains the actual #pragma token, which may
370 // be used for error output.
371 //
372 // If the return value is 'false', the whole #pragma directive is
373 // interpreted as unknown and a corresponding error message is issued. A
374 // return value of 'true' signs a successful interpretation of the given
375 // #pragma.
376 //
377 ///////////////////////////////////////////////////////////////////////////
378 template <typename Context, typename Container>
379 bool
interpret_pragma(Context const & ctx,Container & pending,Token const & option,Container const & values,Token const & act_token)380 interpret_pragma(Context const& ctx, Container &pending,
381 Token const& option, Container const& values, Token const& act_token)
382 {
383 BOOST_WAVETEST_OSSTREAM strm;
384 strm << "07: " << std::endl;
385 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
386 return false;
387 }
388
389 ///////////////////////////////////////////////////////////////////////////
390 //
391 // The function 'defined_macro' is called, whenever a macro was defined
392 // successfully.
393 //
394 // The parameter 'ctx' is a reference to the context object used for
395 // instantiating the preprocessing iterators by the user.
396 //
397 // The parameter 'name' is a reference to the token holding the macro name.
398 //
399 // The parameter 'is_functionlike' is set to true, whenever the newly
400 // defined macro is defined as a function like macro.
401 //
402 // The parameter 'parameters' holds the parameter tokens for the macro
403 // definition. If the macro has no parameters or if it is a object like
404 // macro, then this container is empty.
405 //
406 // The parameter 'definition' contains the token sequence given as the
407 // replacement sequence (definition part) of the newly defined macro.
408 //
409 // The parameter 'is_predefined' is set to true for all macros predefined
410 // during the initialization phase of the library.
411 //
412 ///////////////////////////////////////////////////////////////////////////
413 template <typename Context, typename Container>
414 void
defined_macro(Context const & ctx,Token const & macro,bool is_functionlike,std::vector<Token> const & pars,Container const & definition,bool is_predefined)415 defined_macro(Context const& ctx, Token const& macro,
416 bool is_functionlike, std::vector<Token> const& pars,
417 Container const& definition, bool is_predefined)
418 {
419 // do not trace the definition of the internal helper macros
420 if (!is_predefined) {
421 BOOST_WAVETEST_OSSTREAM strm;
422 strm << "08: " << repr(macro.get_position()) << ": "
423 << macro.get_value();
424 if (is_functionlike) {
425 // list the parameter names for function style macros
426 strm << "(";
427 for (typename std::vector<Token>::size_type i = 0;
428 i < pars.size(); ++i)
429 {
430 strm << pars[i].get_value();
431 if (i < pars.size()-1)
432 strm << ", ";
433 }
434 strm << ")";
435 }
436 strm << "=" << boost::wave::util::impl::as_string(definition)
437 << std::endl;
438 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
439 }
440 }
441
442 ///////////////////////////////////////////////////////////////////////////
443 //
444 // The function 'undefined_macro' is called, whenever a macro definition
445 // was removed successfully.
446 //
447 // The parameter 'ctx' is a reference to the context object used for
448 // instantiating the preprocessing iterators by the user.
449 //
450 // The parameter 'name' holds the name of the macro, which definition was
451 // removed.
452 //
453 ///////////////////////////////////////////////////////////////////////////
454 template <typename Context>
455 void
undefined_macro(Context const & ctx,Token const & macro)456 undefined_macro(Context const& ctx, Token const& macro)
457 {
458 BOOST_WAVETEST_OSSTREAM strm;
459 strm << "09: " << repr(macro.get_position()) << ": "
460 << macro.get_value() << std::endl;
461 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
462 }
463
464 ///////////////////////////////////////////////////////////////////////////
465 //
466 // The function 'found_directive' is called, whenever a preprocessor
467 // directive was encountered, but before the corresponding action is
468 // executed.
469 //
470 // The parameter 'ctx' is a reference to the context object used for
471 // instantiating the preprocessing iterators by the user.
472 //
473 // The parameter 'directive' is a reference to the token holding the
474 // preprocessing directive.
475 //
476 // The return value defines, whether the given expression has to be
477 // to be executed in a normal way (return 'false'), or if it has to be
478 // skipped altogether (return 'true'), which means it gets replaced in the
479 // output by a single newline.
480 //
481 ///////////////////////////////////////////////////////////////////////////
482 template <typename Context>
483 bool
found_directive(Context const & ctx,Token const & directive)484 found_directive(Context const& ctx, Token const& directive)
485 {
486 BOOST_WAVETEST_OSSTREAM strm;
487 strm << "10: " << repr(directive.get_position()) << ": "
488 << directive.get_value() << std::endl;
489 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
490 return false; // by default we never skip any directives
491 }
492
493 ///////////////////////////////////////////////////////////////////////////
494 //
495 // The function 'evaluated_conditional_expression' is called, whenever a
496 // conditional preprocessing expression was evaluated (the expression
497 // given to a #if, #elif, #ifdef or #ifndef directive)
498 //
499 // The parameter 'ctx' is a reference to the context object used for
500 // instantiating the preprocessing iterators by the user.
501 //
502 // The parameter 'directive' is a reference to the token holding the
503 // corresponding preprocessing directive.
504 //
505 // The parameter 'expression' holds the non-expanded token sequence
506 // comprising the evaluated expression.
507 //
508 // The parameter expression_value contains the result of the evaluation of
509 // the expression in the current preprocessing context.
510 //
511 // The return value defines, whether the given expression has to be
512 // evaluated again, allowing to decide which of the conditional branches
513 // should be expanded. You need to return 'true' from this hook function
514 // to force the expression to be re-evaluated.
515 //
516 ///////////////////////////////////////////////////////////////////////////
517 template <typename Context, typename Container>
518 bool
evaluated_conditional_expression(Context const & ctx,Token const & directive,Container const & expression,bool expression_value)519 evaluated_conditional_expression(Context const& ctx,
520 Token const& directive, Container const& expression,
521 bool expression_value)
522 {
523 BOOST_WAVETEST_OSSTREAM strm;
524 strm << "11: " << repr(directive.get_position()) << ": "
525 << directive.get_value() << " "
526 << boost::wave::util::impl::as_string(expression) << ": "
527 << expression_value << std::endl;
528 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
529 return false; // ok to continue, do not re-evaluate expression
530 }
531
532 ///////////////////////////////////////////////////////////////////////////
533 //
534 // The function 'skipped_token' is called, whenever a token is about to be
535 // skipped due to a false preprocessor condition (code fragments to be
536 // skipped inside the not evaluated conditional #if/#else/#endif branches).
537 //
538 // The parameter 'ctx' is a reference to the context object used for
539 // instantiating the preprocessing iterators by the user.
540 //
541 // The parameter 'token' refers to the token to be skipped.
542 //
543 ///////////////////////////////////////////////////////////////////////////
544 template <typename Context>
545 void
skipped_token(Context const & ctx,Token const & token)546 skipped_token(Context const& ctx, Token const& token)
547 {
548 // this normally generates a lot of noise
549 if (skipped_token_hooks) {
550 BOOST_WAVETEST_OSSTREAM strm;
551 strm << "12: " << repr(token.get_position()) << ": >"
552 << repr(token.get_value()) << "<" << std::endl;
553 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
554 }
555 }
556
557 ///////////////////////////////////////////////////////////////////////////
558 //
559 // The function 'generated_token' will be called by the library whenever a
560 // token is about to be returned from the library.
561 //
562 // The parameter 'ctx' is a reference to the context object used for
563 // instantiating the preprocessing iterators by the user.
564 //
565 // The parameter 't' is the token about to be returned from the library.
566 // This function may alter the token, but in this case it must be
567 // implemented with a corresponding signature:
568 //
569 // Token const&
570 // generated_token(Context const& ctx, Token& t);
571 //
572 // which makes it possible to modify the token in place.
573 //
574 // The default behavior is to return the token passed as the parameter
575 // without modification.
576 //
577 ///////////////////////////////////////////////////////////////////////////
578 template <typename Context>
579 Token const&
generated_token(Context const & ctx,Token const & t)580 generated_token(Context const& ctx, Token const& t)
581 {
582 // this generates a lot of noise
583 // BOOST_WAVETEST_OSSTREAM strm;
584 // strm << "13: " << std::endl;
585 // hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
586 return t;
587 }
588
589 ///////////////////////////////////////////////////////////////////////////
590 //
591 // The function 'may_skip_whitespace' will be called by the
592 // library, whenever it must be tested whether a specific token refers to
593 // whitespace and this whitespace has to be skipped.
594 //
595 // The parameter 'ctx' is a reference to the context object used for
596 // instantiating the preprocessing iterators by the user.
597 //
598 // The 'token' parameter holds a reference to the current token. The policy
599 // is free to change this token if needed.
600 //
601 // The 'skipped_newline' parameter holds a reference to a boolean value
602 // which should be set to true by the policy function whenever a newline
603 // is going to be skipped.
604 //
605 // If the return value is true, the given token is skipped and the
606 // preprocessing continues to the next token. If the return value is
607 // false, the given token is returned to the calling application.
608 //
609 // ATTENTION!
610 // Caution has to be used, because by returning true the policy function
611 // is able to force skipping even significant tokens, not only whitespace.
612 //
613 ///////////////////////////////////////////////////////////////////////////
614 template <typename Context>
615 bool
may_skip_whitespace(Context const & ctx,Token & token,bool & skipped_newline)616 may_skip_whitespace(Context const& ctx, Token& token, bool& skipped_newline)
617 {
618 // this generates a lot of noise
619 // BOOST_WAVETEST_OSSTREAM strm;
620 // strm << "14: " << std::endl;
621 // hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
622 return this->base_type::may_skip_whitespace(ctx, token, skipped_newline);
623 }
624
625 #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
626 ///////////////////////////////////////////////////////////////////////////
627 //
628 // The function 'found_warning_directive' will be called by the library
629 // whenever a #warning directive is found.
630 //
631 // The parameter 'ctx' is a reference to the context object used for
632 // instantiating the preprocessing iterators by the user.
633 //
634 // The parameter 'message' references the argument token sequence of the
635 // encountered #warning directive.
636 //
637 // If the return value is false, the library throws a preprocessor
638 // exception of the type 'warning_directive', if the return value is true
639 // the execution continues as if no #warning directive has been found.
640 //
641 ///////////////////////////////////////////////////////////////////////////
642 template <typename Context, typename Container>
643 bool
found_warning_directive(Context const & ctx,Container const & message)644 found_warning_directive(Context const& ctx, Container const& message)
645 {
646 BOOST_WAVETEST_OSSTREAM strm;
647 strm << "15: " << boost::wave::util::impl::as_string(message)
648 << std::endl;
649 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
650 return false;
651 }
652 #endif
653
654 ///////////////////////////////////////////////////////////////////////////
655 //
656 // The function 'found_error_directive' will be called by the library
657 // whenever a #error directive is found.
658 //
659 // The parameter 'ctx' is a reference to the context object used for
660 // instantiating the preprocessing iterators by the user.
661 //
662 // The parameter 'message' references the argument token sequence of the
663 // encountered #error directive.
664 //
665 // If the return value is false, the library throws a preprocessor
666 // exception of the type 'error_directive', if the return value is true
667 // the execution continues as if no #error directive has been found.
668 //
669 ///////////////////////////////////////////////////////////////////////////
670 template <typename Context, typename Container>
671 bool
found_error_directive(Context const & ctx,Container const & message)672 found_error_directive(Context const& ctx, Container const& message)
673 {
674 BOOST_WAVETEST_OSSTREAM strm;
675 strm << "16: " << boost::wave::util::impl::as_string(message)
676 << std::endl;
677 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
678 return false;
679 }
680
681 ///////////////////////////////////////////////////////////////////////////
682 //
683 // The function 'found_line_directive' will be called by the library
684 // whenever a #line directive is found.
685 //
686 // The parameter 'ctx' is a reference to the context object used for
687 // instantiating the preprocessing iterators by the user.
688 //
689 // The parameter 'arguments' references the argument token sequence of the
690 // encountered #line directive.
691 //
692 // The parameter 'line' contains the recognized line number from the #line
693 // directive.
694 //
695 // The parameter 'filename' references the recognized file name from the
696 // #line directive (if there was one given).
697 //
698 ///////////////////////////////////////////////////////////////////////////
699 template <typename Context, typename Container>
700 void
found_line_directive(Context const & ctx,Container const & arguments,unsigned int line,std::string const & filename)701 found_line_directive(Context const& ctx, Container const& arguments,
702 unsigned int line, std::string const& filename)
703 {
704 BOOST_WAVETEST_OSSTREAM strm;
705 strm << "17: " << boost::wave::util::impl::as_string(arguments)
706 << " (" << line << ", \"" << filename << "\")" << std::endl;
707 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
708 }
709
710 ///////////////////////////////////////////////////////////////////////////
711 //
712 // The function 'throw_exception' will be called by the library whenever a
713 // preprocessing exception occurs.
714 //
715 // The parameter 'ctx' is a reference to the context object used for
716 // instantiating the preprocessing iterators by the user.
717 //
718 // The parameter 'e' is the exception object containing detailed error
719 // information.
720 //
721 // The default behavior is to call the function boost::throw_exception.
722 //
723 ///////////////////////////////////////////////////////////////////////////
724 template <typename Context, typename Exception>
725 void
throw_exception(Context const & ctx,Exception const & e)726 throw_exception(Context const& ctx, Exception const& e)
727 {
728 BOOST_WAVETEST_OSSTREAM strm;
729 strm << "18: " << e.what() << std::endl;
730 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
731 return this->base_type::throw_exception(ctx, e);
732 }
733
734 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
735 ///////////////////////////////////////////////////////////////////////////
736 //
737 // The function 'detected_include_guard' is called whenever either a
738 // include file is about to be added to the list of #pragma once headers.
739 // That means this header file will not be opened and parsed again even
740 // if it is specified in a later #include directive.
741 // This function is called as the result of a detected include guard
742 // scheme.
743 //
744 // The implemented heuristics for include guards detects two forms of
745 // include guards:
746 //
747 // #ifndef INCLUDE_GUARD_MACRO
748 // #define INCLUDE_GUARD_MACRO
749 // ...
750 // #endif
751 //
752 // or
753 //
754 // if !defined(INCLUDE_GUARD_MACRO)
755 // #define INCLUDE_GUARD_MACRO
756 // ...
757 // #endif
758 //
759 // note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO
760 // will work as well). The code allows for any whitespace, newline and single
761 // '#' tokens before the #if/#ifndef and after the final #endif.
762 //
763 // The parameter 'ctx' is a reference to the context object used for
764 // instantiating the preprocessing iterators by the user.
765 //
766 // The parameter 'filename' contains the file system path of the
767 // opened file (this is relative to the directory of the currently
768 // processed file or a absolute path depending on the paths given as the
769 // include search paths).
770 //
771 // The parameter contains the name of the detected include guard.
772 //
773 ///////////////////////////////////////////////////////////////////////////
774 template <typename ContextT>
775 void
detected_include_guard(ContextT const & ctx,std::string filename,std::string const & include_guard)776 detected_include_guard(ContextT const& ctx, std::string filename,
777 std::string const& include_guard)
778 {
779 using boost::wave::util::impl::escape_lit;
780
781 #if defined(BOOST_WINDOWS)
782 filename = replace_slashes(filename);
783 #endif
784
785 BOOST_WAVETEST_OSSTREAM strm;
786 strm << "19: " << escape_lit(filename) << ": "
787 << include_guard << std::endl;
788 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
789 }
790
791 ///////////////////////////////////////////////////////////////////////////
792 //
793 // The function 'detected_pragma_once' is called whenever either a
794 // include file is about to be added to the list of #pragma once headers.
795 // That means this header file will not be opened and parsed again even
796 // if it is specified in a later #include directive.
797 // This function is called as the result of a detected directive
798 // #pragma once.
799 //
800 // The parameter 'ctx' is a reference to the context object used for
801 // instantiating the preprocessing iterators by the user.
802 //
803 // The parameter pragma_token refers to the token "#pragma" triggering
804 // this preprocessing hook.
805 //
806 // The parameter 'filename' contains the file system path of the
807 // opened file (this is relative to the directory of the currently
808 // processed file or a absolute path depending on the paths given as the
809 // include search paths).
810 //
811 ///////////////////////////////////////////////////////////////////////////
812 template <typename ContextT, typename TokenT>
813 void
detected_pragma_once(ContextT const & ctx,TokenT const & pragma_token,std::string filename)814 detected_pragma_once(ContextT const& ctx, TokenT const& pragma_token,
815 std::string filename)
816 {
817 using boost::wave::util::impl::escape_lit;
818
819 #if defined(BOOST_WINDOWS)
820 filename = replace_slashes(filename);
821 #endif
822
823 BOOST_WAVETEST_OSSTREAM strm;
824 strm << "20: " << repr(pragma_token.get_position()) << ": "
825 << pragma_token.get_value() << ": "
826 << escape_lit(filename) << std::endl;
827 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
828 }
829 #endif
830
831 ///////////////////////////////////////////////////////////////////////////
832 //
833 // The function 'found_unknown_directive' is called, whenever an unknown
834 // preprocessor directive was encountered.
835 //
836 // The parameter 'ctx' is a reference to the context object used for
837 // instantiating the preprocessing iterators by the user.
838 //
839 // The parameter 'line' holds the tokens of the entire source line
840 // containing the unknown directive.
841 //
842 // The parameter 'pending' may be used to push tokens back into the input
843 // stream, which are to be used as the replacement text for the whole
844 // line containing the unknown directive.
845 //
846 // The return value defines, whether the given expression has been
847 // properly interpreted by the hook function or not. If this function
848 // returns 'false', the library will raise an 'ill_formed_directive'
849 // preprocess_exception. Otherwise the tokens pushed back into 'pending'
850 // are passed on to the user program.
851 //
852 ///////////////////////////////////////////////////////////////////////////
853 template <typename ContextT, typename ContainerT>
854 bool
found_unknown_directive(ContextT const & ctx,ContainerT const & line,ContainerT & pending)855 found_unknown_directive(ContextT const& ctx, ContainerT const& line,
856 ContainerT& pending)
857 {
858 BOOST_WAVETEST_OSSTREAM strm;
859 strm << "21: " << repr((*line.begin()).get_position()) << ": "
860 << boost::wave::util::impl::as_string(line) << std::endl;
861 hooks_trace += BOOST_WAVETEST_GETSTRING(strm);
862 return false;
863 }
864
865 private:
866 std::string& hooks_trace;
867 bool skipped_token_hooks;
868 };
869
870 #endif
871
872
873
874