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